FFmpeg
Loading...
Searching...
No Matches
lrcenc.c
Go to the documentation of this file.
1/*
2 * LRC lyrics file format muxer
3 * Copyright (c) 2014 StarBrilliant <m13253@hotmail.com>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <inttypes.h>
23#include <stdint.h>
24#include <string.h>
25
26#include "avformat.h"
27#include "internal.h"
28#include "lrc.h"
29#include "metadata.h"
30#include "mux.h"
31#include "version.h"
32#include "libavutil/dict.h"
33#include "libavutil/log.h"
34#include "libavutil/macros.h"
35#include "libavutil/opt.h"
36
37typedef struct LRCSubtitleContext {
38 const AVClass *class;
39 int precision; ///< precision of the fractional part of the timestamp, 2 for centiseconds
41
43{
44 const AVDictionaryEntry *metadata_item;
45
46 if(s->streams[0]->codecpar->codec_id != AV_CODEC_ID_SUBRIP &&
47 s->streams[0]->codecpar->codec_id != AV_CODEC_ID_TEXT) {
48 av_log(s, AV_LOG_ERROR, "Unsupported subtitle codec: %s\n",
49 avcodec_get_name(s->streams[0]->codecpar->codec_id));
50 return AVERROR(EINVAL);
51 }
52 avpriv_set_pts_info(s->streams[0], 64, 1, AV_TIME_BASE);
53
56 if(!(s->flags & AVFMT_FLAG_BITEXACT)) { // avoid breaking regression tests
57 /* LRC provides a metadata slot for specifying encoder version
58 * in addition to encoder name. We will store LIBAVFORMAT_VERSION
59 * to it.
60 */
61 av_dict_set(&s->metadata, "ve", AV_STRINGIFY(LIBAVFORMAT_VERSION), 0);
62 } else {
63 av_dict_set(&s->metadata, "ve", NULL, 0);
64 }
65 for(metadata_item = NULL;
66 (metadata_item = av_dict_iterate(s->metadata, metadata_item));) {
67 char *delim;
68 if(!metadata_item->value[0]) {
69 continue;
70 }
71 while((delim = strchr(metadata_item->value, '\n'))) {
72 *delim = ' ';
73 }
74 while((delim = strchr(metadata_item->value, '\r'))) {
75 *delim = ' ';
76 }
77 avio_printf(s->pb, "[%s:%s]\n",
78 metadata_item->key, metadata_item->value);
79 }
80 avio_w8(s->pb, '\n');
81 return 0;
82}
83
85{
86 const LRCSubtitleContext *p = s->priv_data;
87
88 if(pkt->pts != AV_NOPTS_VALUE) {
89 const uint8_t *line = pkt->data;
90 const uint8_t *end = pkt->data + pkt->size;
91
92 while (end > line && (end[-1] == '\n' || end[-1] == '\r'))
93 end--;
94 if (line != end) {
95 while (line[0] == '\n' || line[0] == '\r')
96 line++; // Skip first empty lines
97 }
98
99 int frac_mult = 1;
100 for (int i = 0; i < p->precision; ++i)
101 frac_mult *= 10;
102
103 while(line) {
104 const uint8_t *next_line = memchr(line, '\n', end - line);
105 size_t size = end - line;
106
107 if (next_line) {
108 size = next_line - line;
109 if (next_line > line && next_line[-1] == '\r')
110 size--;
111 next_line++;
112 }
113 if (size && line[0] == '[') {
115 "Subtitle starts with '[', may cause problems with LRC format.\n");
116 }
117
118 /* Offset feature of LRC can easily make pts negative,
119 * we just output it directly and let the player drop it. */
120 uint64_t abs_pts = FFABS64U(pkt->pts);
121 uint64_t minutes = abs_pts / (60 * AV_TIME_BASE);
122 uint64_t seconds = (abs_pts / AV_TIME_BASE) % 60;
123 uint64_t fraction = abs_pts % AV_TIME_BASE;
124 uint64_t rescaled = av_rescale_q(fraction, AV_TIME_BASE_Q, (AVRational){1, frac_mult});
125 avio_write(s->pb, "[-", 1 + (pkt->pts < 0));
126 avio_printf(s->pb, "%02"PRIu64":%02"PRIu64".%0*"PRIu64"]",
127 minutes, seconds, p->precision, rescaled);
128
129 avio_write(s->pb, line, size);
130 avio_w8(s->pb, '\n');
131 line = next_line;
132 }
133 }
134 return 0;
135}
136
137#define OFFSET(x) offsetof(LRCSubtitleContext, x)
138#define SE AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_ENCODING_PARAM
139static const AVOption options[] = {
140 {"precision", "precision of the fractional part of the timestamp, 2 for centiseconds", OFFSET(precision), AV_OPT_TYPE_INT, {.i64 = 2}, 1, 6, SE},
141 { NULL },
142};
143
144static const AVClass lrcenc_class = {
145 .class_name = "lrc",
146 .item_name = av_default_item_name,
147 .option = options,
148 .version = LIBAVUTIL_VERSION_INT,
149};
150
152 .p.name = "lrc",
153 .p.long_name = NULL_IF_CONFIG_SMALL("LRC lyrics"),
154 .p.extensions = "lrc",
157 .p.video_codec = AV_CODEC_ID_NONE,
158 .p.audio_codec = AV_CODEC_ID_NONE,
159 .p.subtitle_codec = AV_CODEC_ID_SUBRIP,
160 .flags_internal = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
161 .priv_data_size = sizeof(LRCSubtitleContext),
164 .p.priv_class = &lrcenc_class,
165};
const FFOutputFormat ff_lrc_muxer
Definition lrcenc.c:151
void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition avformat.c:834
Main libavformat public API header.
#define AVFMT_FLAG_BITEXACT
When muxing, try to avoid writing any random/volatile data to the output.
Definition avformat.h:1501
#define AVFMT_VARIABLE_FPS
Format allows variable fps.
Definition avformat.h:501
#define AVFMT_TS_NEGATIVE
Format allows muxing negative timestamps.
Definition avformat.h:510
#define AVFMT_TS_NONSTRICT
Format does not require strictly increasing timestamps, but they must still be monotonic.
Definition avformat.h:507
#define AVFMT_GLOBALHEADER
Format wants global header.
Definition avformat.h:497
void avio_w8(AVIOContext *s, int b)
Definition aviobuf.c:184
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2
Writes a formatted string to the context.
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition aviobuf.c:206
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define FFABS64U(a)
Definition common.h:92
#define NULL
Definition coverity.c:32
static AVPacket * pkt
Public dictionary API.
#define SE
Definition dvbsubenc.c:531
static int write_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
Definition ffmpeg_mux.c:204
static void write_header(FFV1Context *f)
Definition ffv1enc.c:384
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
const char * avcodec_get_name(enum AVCodecID id)
Get the name of a codec.
Definition utils.c:421
@ AV_CODEC_ID_TEXT
raw UTF-8 text
Definition codec_id.h:568
@ AV_CODEC_ID_NONE
Definition codec_id.h:48
@ AV_CODEC_ID_SUBRIP
Definition codec_id.h:583
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition dict.c:42
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition dict.c:86
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
#define AV_TIME_BASE
Internal time base represented as integer.
Definition avutil.h:253
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition avutil.h:263
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
#define AV_STRINGIFY(s)
Definition macros.h:66
Libavformat version macros.
#define LIBAVFORMAT_VERSION
Definition version.h:40
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
const AVMetadataConv ff_lrc_metadata_conv[]
Definition lrc.c:25
static const AVClass lrcenc_class
Definition lrcenc.c:144
#define OFFSET(x)
Definition lrcenc.c:137
static int lrc_write_header(AVFormatContext *s)
Definition lrcenc.c:42
static int lrc_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition lrcenc.c:84
Utility Preprocessor macros.
void ff_metadata_conv_ctx(AVFormatContext *ctx, const AVMetadataConv *d_conv, const AVMetadataConv *s_conv)
Definition metadata.c:59
internal metadata API header see avformat.h or the public API!
#define FF_OFMT_FLAG_MAX_ONE_OF_EACH
If this flag is set, it indicates that for each codec type whose corresponding default codec (i....
Definition mux.h:50
int ff_standardize_creation_time(AVFormatContext *s)
Standardize creation_time metadata in AVFormatContext to an ISO-8601 timestamp string.
Definition mux_utils.c:154
AVOptions.
Describe the class of an AVClass context structure.
Definition log.h:76
char * key
Definition dict.h:91
char * value
Definition dict.h:92
Format I/O context.
Definition avformat.h:1333
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
Rational number (pair of numerator and denominator).
Definition rational.h:58
int precision
precision of the fractional part of the timestamp, 2 for centiseconds
Definition lrcenc.c:39
#define av_log(a,...)
int size