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
4629By default, this work-around is disabled.4629By default, this work-around is disabled.
4630@end table4630@end table
4631 4631
4632@section lrc
4633
4634This codec encodes the LRC lyrics format.
4635
4636@subsection Options
4637
4638@table @option
4639@item precision
4640Specify the precision of the fractional part of the timestamp. Time base is
4641determined based on this value.
4642
4643Defaults to 2 for centiseconds.
4644@end table
4645
4632@c man end SUBTITLES ENCODERS4646@c man end SUBTITLES ENCODERS
libavformat/lrcenc.c+36−6
@@ -32,6 +32,12 @@ · 31 unmodified lines
32#include "libavutil/dict.h"32#include "libavutil/dict.h"
33#include "libavutil/log.h"33#include "libavutil/log.h"
34#include "libavutil/macros.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
40} LRCSubtitleContext;
35 41
36static int lrc_write_header(AVFormatContext *s)42static int lrc_write_header(AVFormatContext *s)
37{43{
@@ -43,7 +49,7 @@ static int lrc_write_header(AVFormatContext *s) · 5 unmodified lines
43 avcodec_get_name(s->streams[0]->codecpar->codec_id));49 avcodec_get_name(s->streams[0]->codecpar->codec_id));
44 return AVERROR(EINVAL);50 return AVERROR(EINVAL);
45 }51 }
46 avpriv_set_pts_info(s->streams[0], 64, 1, 100);52 avpriv_set_pts_info(s->streams[0], 64, 1, AV_TIME_BASE);
47 53
48 ff_standardize_creation_time(s);54 ff_standardize_creation_time(s);
49 ff_metadata_conv_ctx(s, ff_lrc_metadata_conv, NULL);55 ff_metadata_conv_ctx(s, ff_lrc_metadata_conv, NULL);
@@ -77,6 +83,8 @@ static int lrc_write_header(AVFormatContext *s) · 27 unmodified lines
77 83
78static int lrc_write_packet(AVFormatContext *s, AVPacket *pkt)84static int lrc_write_packet(AVFormatContext *s, AVPacket *pkt)
79{85{
86 const LRCSubtitleContext *p = s->priv_data;
87
80 if(pkt->pts != AV_NOPTS_VALUE) {88 if(pkt->pts != AV_NOPTS_VALUE) {
81 const uint8_t *line = pkt->data;89 const uint8_t *line = pkt->data;
82 const uint8_t *end = pkt->data + pkt->size;90 const uint8_t *end = pkt->data + pkt->size;
@@ -88,6 +96,10 @@ static int lrc_write_packet(AVFormatContext *s, AVPacket *pkt) · 5 unmodified lines
88 line++; // Skip first empty lines96 line++; // Skip first empty lines
89 }97 }
90 98
99 int frac_mult = 1;
100 for (int i = 0; i < p->precision; ++i)
101 frac_mult *= 10;
102
91 while(line) {103 while(line) {
92 const uint8_t *next_line = memchr(line, '\n', end - line);104 const uint8_t *next_line = memchr(line, '\n', end - line);
93 size_t size = end - line;105 size_t size = end - line;
@@ -105,11 +117,14 @@ static int lrc_write_packet(AVFormatContext *s, AVPacket *pkt) · 11 unmodified lines
105 117
106 /* Offset feature of LRC can easily make pts negative,118 /* Offset feature of LRC can easily make pts negative,
107 * we just output it directly and let the player drop it. */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});
108 avio_write(s->pb, "[-", 1 + (pkt->pts < 0));125 avio_write(s->pb, "[-", 1 + (pkt->pts < 0));
109 avio_printf(s->pb, "%02"PRIu64":%02"PRIu64".%02"PRIu64"]",126 avio_printf(s->pb, "%02"PRIu64":%02"PRIu64".%0*"PRIu64"]",
110 (FFABS64U(pkt->pts) / 6000),127 minutes, seconds, p->precision, rescaled);
111 ((FFABS64U(pkt->pts) / 100) % 60),
112 (FFABS64U(pkt->pts) % 100));
113 128
114 avio_write(s->pb, line, size);129 avio_write(s->pb, line, size);
115 avio_w8(s->pb, '\n');130 avio_w8(s->pb, '\n');
@@ -119,6 +134,20 @@ static int lrc_write_packet(AVFormatContext *s, AVPacket *pkt) · 3 unmodified lines
119 return 0;134 return 0;
120}135}
121 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
122const FFOutputFormat ff_lrc_muxer = {151const FFOutputFormat ff_lrc_muxer = {
123 .p.name = "lrc",152 .p.name = "lrc",
124 .p.long_name = NULL_IF_CONFIG_SMALL("LRC lyrics"),153 .p.long_name = NULL_IF_CONFIG_SMALL("LRC lyrics"),
@@ -129,7 +158,8 @@ const FFOutputFormat ff_lrc_muxer = { · 4 unmodified lines
129 .p.audio_codec = AV_CODEC_ID_NONE,158 .p.audio_codec = AV_CODEC_ID_NONE,
130 .p.subtitle_codec = AV_CODEC_ID_SUBRIP,159 .p.subtitle_codec = AV_CODEC_ID_SUBRIP,
131 .flags_internal = FF_OFMT_FLAG_MAX_ONE_OF_EACH,160 .flags_internal = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
132 .priv_data_size = 0,161 .priv_data_size = sizeof(LRCSubtitleContext),
133 .write_header = lrc_write_header,162 .write_header = lrc_write_header,
134 .write_packet = lrc_write_packet,163 .write_packet = lrc_write_packet,
164 .p.priv_class = &lrcenc_class,
135};165};

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