History

avformat/lrcenc: add precision option

Allows to output LRC with more precision than standard centiseconds. Time base is determined by number of requested digits.

Kacper Michajłow committed 1 year ago

Commit 670c1b91 parent a29aeee2 files · +50 −6Browse files

Unified · Split

2 files
  1. doc/encoders.texi +14 −0
  2. libavformat/lrcenc.c +36 −6
doc/encoders.texi+14−0
@@ -4629,4 +4629,18 @@ one byte per subtitle on average. · 4628 unmodified lines
46294629 By default, this work-around is disabled.
46304630 @end table
46314631
4632+@section lrc
4633+
4634+This codec encodes the LRC lyrics format.
4635+
4636+@subsection Options
4637+
4638+@table @option
4639+@item precision
4640+Specify the precision of the fractional part of the timestamp. Time base is
4641+determined based on this value.
4642+
4643+Defaults to 2 for centiseconds.
4644+@end table
4645+
46324646 @c man end SUBTITLES ENCODERS
libavformat/lrcenc.c+36−6
@@ -32,6 +32,12 @@ · 31 unmodified lines
3232 #include "libavutil/dict.h"
3333 #include "libavutil/log.h"
3434 #include "libavutil/macros.h"
35+#include "libavutil/opt.h"
36+
37+typedef struct LRCSubtitleContext {
38+ const AVClass *class;
39+ int precision; ///< precision of the fractional part of the timestamp, 2 for centiseconds
40+} LRCSubtitleContext;
3541
3642 static int lrc_write_header(AVFormatContext *s)
3743 {
@@ -43,7 +49,7 @@ static int lrc_write_header(AVFormatContext *s) · 5 unmodified lines
4349 avcodec_get_name(s->streams[0]->codecpar->codec_id));
4450 return AVERROR(EINVAL);
4551 }
46− avpriv_set_pts_info(s->streams[0], 64, 1, 100);
52+ avpriv_set_pts_info(s->streams[0], 64, 1, AV_TIME_BASE);
4753
4854 ff_standardize_creation_time(s);
4955 ff_metadata_conv_ctx(s, ff_lrc_metadata_conv, NULL);
@@ -77,6 +83,8 @@ static int lrc_write_header(AVFormatContext *s) · 27 unmodified lines
7783
7884 static int lrc_write_packet(AVFormatContext *s, AVPacket *pkt)
7985 {
86+ const LRCSubtitleContext *p = s->priv_data;
87+
8088 if(pkt->pts != AV_NOPTS_VALUE) {
8189 const uint8_t *line = pkt->data;
8290 const uint8_t *end = pkt->data + pkt->size;
@@ -88,6 +96,10 @@ static int lrc_write_packet(AVFormatContext *s, AVPacket *pkt) · 5 unmodified lines
8896 line++; // Skip first empty lines
8997 }
9098
99+ int frac_mult = 1;
100+ for (int i = 0; i < p->precision; ++i)
101+ frac_mult *= 10;
102+
91103 while(line) {
92104 const uint8_t *next_line = memchr(line, '\n', end - line);
93105 size_t size = end - line;
@@ -105,11 +117,14 @@ static int lrc_write_packet(AVFormatContext *s, AVPacket *pkt) · 11 unmodified lines
105117
106118 /* Offset feature of LRC can easily make pts negative,
107119 * 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});
108125 avio_write(s->pb, "[-", 1 + (pkt->pts < 0));
109− avio_printf(s->pb, "%02"PRIu64":%02"PRIu64".%02"PRIu64"]",
110− (FFABS64U(pkt->pts) / 6000),
111− ((FFABS64U(pkt->pts) / 100) % 60),
112− (FFABS64U(pkt->pts) % 100));
126+ avio_printf(s->pb, "%02"PRIu64":%02"PRIu64".%0*"PRIu64"]",
127+ minutes, seconds, p->precision, rescaled);
113128
114129 avio_write(s->pb, line, size);
115130 avio_w8(s->pb, '\n');
@@ -119,6 +134,20 @@ static int lrc_write_packet(AVFormatContext *s, AVPacket *pkt) · 3 unmodified lines
119134 return 0;
120135 }
121136
137+#define OFFSET(x) offsetof(LRCSubtitleContext, x)
138+#define SE AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_ENCODING_PARAM
139+static 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+
144+static 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+
122151 const FFOutputFormat ff_lrc_muxer = {
123152 .p.name = "lrc",
124153 .p.long_name = NULL_IF_CONFIG_SMALL("LRC lyrics"),
@@ -129,7 +158,8 @@ const FFOutputFormat ff_lrc_muxer = { · 4 unmodified lines
129158 .p.audio_codec = AV_CODEC_ID_NONE,
130159 .p.subtitle_codec = AV_CODEC_ID_SUBRIP,
131160 .flags_internal = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
132− .priv_data_size = 0,
161+ .priv_data_size = sizeof(LRCSubtitleContext),
133162 .write_header = lrc_write_header,
134163 .write_packet = lrc_write_packet,
164+ .p.priv_class = &lrcenc_class,
135165 };

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t