[FFmpeg-devel] LRC (music lyrics) muxer and demuxer
Peter Ross
pross
Wed Dec 29 06:07:15 CET 2010
On Sun, Dec 26, 2010 at 10:00:59PM +0100, Aurelien Jacobs wrote:
> On Sun, Dec 26, 2010 at 11:45:50PM +1100, Peter Ross wrote:
> > Typical sample: http://lrc.awardspace.us/lrc/Evanescence-Missing.lrc
>
> First some general comments.
>
> Using CODEC_ID_TEXT don't seem appropriate.
> We need to be able to decode the "Simple format extended" (gender
> specifier) and the "Enhanced format" (Word Time Tag).
> See : http://en.wikipedia.org/wiki/LRC_%28file_format%29
> So for this to work, we need a specific CODEC_ID_LRC (and we will need
> to implement an encoder and a decoder, but that's another story).
Yep, that stuff definately belongs in the decoder.
> It seems you also need to support multiple timestamps on a single line
> (allows to avoid duplicating the same text several times).
> See : http://www.mobile-mir.com/en/HowToLRC.php
> And for a real world sample file, see:
> http://www.lyrdb.com/karaoke/18374.htm
Okay.
> Also, I wonder how we will generate AVSubtitle.end_display_time in the
> decoder ? In LRC, the start time of the next frame is the end time of
> current frame. The decoder could wait for the next frame before
> returning current frame, adding a 1 frame delay, but with subtitles, the
> time between two frames can be really long and the video would continue
> to decode while the subtitle is waiting for next frame to appear to know
> the end time of the frame which is supposed to be displayed now. So I
> guess this wouldn't really work.
> Any idea about how we could handle this ?
If the demuxer parses the entire file at file_open() time, then it can
calculate the duration and pass that onto the decoder via AVPacket->duration.
Also some files use an blank lyric line to force the previous line to
disappear from the display.
> Now about the code itself.
>
> > [...]
> > +const AVMetadataConv ff_lrc_metadata_conv[] = {
> > + { "al", "album" },
> > + { "ar", "artist" },
> > + { "au", "composer" },
> > + { "by", "encoded_by" },
> > + { "la", "language" },
> > + { "re", "encoder" },
> > + { "ti", "title" },
> > + { 0 },
> > +};
>
> You may want to add:
> + { "ve", "encoder_version" },
Ok.
> > +static int probe(AVProbeData *p)
> > +{
> > + const AVMetadataConv * c;
> > + if (p->buf[0] != '[')
> > + return 0;
> > + for (c = ff_lrc_metadata_conv; c->native; c++) {
> > + int len = strlen(c->native);
> > + if (p->buf_size >= len + 2 && !memcmp(p->buf + 1, c->native, len) &&
> > + p->buf[len + 1]==':')
> > + return AVPROBE_SCORE_MAX/2 + 1;
> > + }
> > + return 0;
> > +}
>
> This probe function is a bit week. Maybe you could test that the line
> correctly ends with a ']'. And you could also check that the second line
> is also correct.
> Also this autodetect fonction won't work for files with no metadata.
Agree.
> > +static int read_header(AVFormatContext *s, AVFormatParameters *ap)
> > +{
> > + AVStream *st = av_new_stream(s, 0);
> > + if (!st)
> > + return -1;
> > + st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
> > + st->codec->codec_id = CODEC_ID_TEXT;
> > + st->start_time = 0;
> > + av_set_pts_info(st, 64, 1, 100);
>
> > + ff_metadata_conv_ctx(s, ff_lrc_metadata_conv, NULL);
>
> What is this ff_metadata_conv_ctx() good for ?
That tells ffmpeg to automatically translate betwen the LRC metadata keys
and the generic ffmpeg keys. e.g. 'ti' == 'title'. Somebody feel free
to correct me on this.
> > [...]
> > + split = strchr(start, ':');
> > + if (!split)
> > + continue;
> > + end = strchr(split, ']');
> > + if (!end)
> > + continue;
>
> Could be simplified this way (at least I find it simpler):
>
> + if (!(split = strchr(start, ':')) ||
> + !(end = strchr(split, ']')))
> + continue;
>
> > [...]
> > + for (c = ff_lrc_metadata_conv; c->native; c++) {
> > + int len = split - start;
> > + if (strlen(c->native) == len && !memcmp(start, c->native, len))
> > + av_metadata_set2(&s->metadata, c->native, split + 1, 0);
> > + }
>
> I might simplify your code if you use ff_metadata_conv() ?
>
> > [...]
> > +
> > + end = strchr(start, '\n');
> > + av_new_packet(pkt, end ? end - start : strlen(start));
>
> It seems you drop the final '\n' (but not the '\r'). Why ?
> Other subtitles demuxers are outputing \r\n as part of the packet.
Ok.
> > [...]
> > +AVInputFormat lrc_demuxer = {
> > + .name = "lrc",
>
> > + .long_name = NULL_IF_CONFIG_SMALL("LRC"),
>
> Not a very descriptive long name...
'LRC lyrics'? Suggestions welcome.
> > +static int write_header(AVFormatContext *s)
> > +{
> > + AVMetadataTag *t = NULL;
> > + if (s->nb_streams != 1)
> > + return -1;
>
> Here you should also check that codec_id is the one supported.
>
> > [...]
> > +
> > +AVOutputFormat lrc_muxer = {
> > + .name = "lrc",
> > + .long_name = NULL_IF_CONFIG_SMALL("LRC"),
> > + .extensions = "lrc",
> > + .subtitle_codec = CODEC_ID_TEXT,
> > + .write_header = write_header,
> > + .write_packet = write_packet,
>
> > + .flags = AVFMT_GLOBALHEADER,
>
> Is this really needed/useful/appropriate ?
> This flag supposedly mean that the muxer expect some extradata to be
> available, but I don't think it tells anything about metadata.
Correct. Thanks for the review.
-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20101229/9f07affe/attachment.pgp>
More information about the ffmpeg-devel
mailing list