[FFmpeg-devel] [PATCH] Add MPL2 subtitles demuxer and decoder.

Clément Bœsch ubitux at gmail.com
Sat Dec 29 19:18:45 CET 2012


On Sat, Dec 29, 2012 at 12:45:18PM +0100, Stefano Sabatini wrote:
[...]
> > +/**
> > + * @file
> > + * MPL2 subtitles decoder
> 
> maybe mention a spec or some doc here, for example this one:
> http://web.archive.org/web/20090328040233/http://napisy.ussbrowarek.org/mpl2-eng.html
> 

Yep, I thought I added this link…

> > + */
> > +
> > +#include "avcodec.h"
> > +#include "ass.h"
> > +#include "libavutil/bprint.h"
> > +
> > +static int mpl2_event_to_ass(AVBPrint *buf, const char *p)
> > +{
> > +    if (*p == ' ')
> > +        p++;
> > +
> > +    while (*p) {
> > +        int got_style = 0;
> > +
> > +        while (*p && strchr("/\\_", *p)) {
> > +            if      (*p == '/')  av_bprintf(buf, "{\\i1}");
> > +            else if (*p == '\\') av_bprintf(buf, "{\\b1}");
> > +            else if (*p == '_')  av_bprintf(buf, "{\\u1}");
> > +            got_style = 1;
> > +            p++;
> > +        }
> > +
> > +        while (*p && *p != '|') {
> > +            if (*p != '\r' && *p != '\n')
> > +                av_bprint_chars(buf, *p, 1);
> > +            p++;
> > +        }
> > +
> > +        if (*p == '|') {
> > +            if (got_style)
> > +                av_bprintf(buf, "{\\r}");
> > +            av_bprintf(buf, "\\N");
> > +            p++;
> > +        }
> > +    }
> > +
> > +    av_bprintf(buf, "\r\n");
> > +    return 0;
> > +}
> > +
> 
> > +static int mpl2_decode_frame(AVCodecContext *avctx, void *data,
> > +                             int *got_sub_ptr, AVPacket *avpkt)
> > +{
> > +    AVBPrint buf;
> > +    AVSubtitle *sub = data;
> > +    const char *ptr = avpkt->data;
> > +    const int ts_start     = av_rescale_q(avpkt->pts,      avctx->time_base, (AVRational){1,100});
> 
> > +    const int ts_duration  = avpkt->duration != -1 ?
> 
> is -1 allowed? I ask because I can't find it specified in avcodec.h.
> 

It's only used for ff_ass_add_rect(), and it's a special case for the
latest event.

[...]
> > +static int read_ts(char **line, int64_t *pts_start, int *duration)
> > +{
> > +    char c;
> > +    int len;
> > +    int64_t end;
> > +
> > +    if (sscanf(*line, "[%"PRId64"][]%c%n",
> > +               pts_start, &c, &len) >= 2) {
> > +        *duration = -1;
> 
> > +        *line += len - 1;
> > +        return 0;
> > +    }
> > +    if (sscanf(*line, "[%"PRId64"][%"PRId64"]%c%n",
> > +               pts_start, &end, &c, &len) >= 3) {
> > +        *duration = end - *pts_start;
> 
> > +        *line += len - 1;
> > +        return 0;
> 
> Nit: this can be factorized (if it is worth the trouble)
> 

I can rewrite that if people want, but I don't think it's worth the
trouble.

> > +    }
> > +    return -1;
> > +}
> > +
> > +static int mpl2_read_header(AVFormatContext *s)
> > +{
> > +    MPL2Context *mpl2 = s->priv_data;
> > +    AVStream *st = avformat_new_stream(s, NULL);
> > +    int res = 0;
> > +
> > +    if (!st)
> > +        return AVERROR(ENOMEM);
> > +    avpriv_set_pts_info(st, 64, 1, 10);
> > +    st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
> > +    st->codec->codec_id   = AV_CODEC_ID_MPL2;
> > +
> > +    while (!url_feof(s->pb)) {
> > +        char line[4096];
> > +        char *p = line;
> > +        const int64_t pos = avio_tell(s->pb);
> > +        int len = ff_get_line(s->pb, line, sizeof(line));
> 
> Nit: you could add a warning in case the line is truncated (not sure
> you can really check it in an efficient way)
> 

I don't think we ever did that…

> > +        int64_t pts_start;
> > +        int duration;
> > +
> > +        if (!len)
> > +            break;
> > +
> > +        line[strcspn(line, "\r\n")] = 0;
> > +
> > +        if (!read_ts(&p, &pts_start, &duration)) {
> 
> Nit++: read_ts(...) >= 0?
> 

If you prefer…

> > +            AVPacket *sub;
> > +
> > +            sub = ff_subtitles_queue_insert(&mpl2->q, p, strlen(p), 0);
> > +            if (!sub)
> > +                return AVERROR(ENOMEM);
> > +            sub->pos = pos;
> > +            sub->pts = pts_start;
> > +            sub->duration = duration;
> > +        }
> > +    }
> > +
> > +    ff_subtitles_queue_finalize(&mpl2->q);
> > +    return res;
> > +}
> > +
> > +static int mpl2_read_packet(AVFormatContext *s, AVPacket *pkt)
> > +{
> > +    MPL2Context *mpl2 = s->priv_data;
> > +    return ff_subtitles_queue_read_packet(&mpl2->q, pkt);
> > +}
> > +
> > +static int mpl2_read_seek(AVFormatContext *s, int stream_index,
> > +                          int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
> > +{
> > +    MPL2Context *mpl2 = s->priv_data;
> > +    return ff_subtitles_queue_seek(&mpl2->q, s, stream_index,
> > +                                   min_ts, ts, max_ts, flags);
> > +}
> > +
> > +static int mpl2_read_close(AVFormatContext *s)
> > +{
> > +    MPL2Context *mpl2 = s->priv_data;
> > +    ff_subtitles_queue_clean(&mpl2->q);
> > +    return 0;
> > +}
> > +
> > +AVInputFormat ff_mpl2_demuxer = {
> > +    .name           = "mpl2",
> > +    .long_name      = NULL_IF_CONFIG_SMALL("MPL2 subtitles"),
> > +    .priv_data_size = sizeof(MPL2Context),
> > +    .read_probe     = mpl2_probe,
> > +    .read_header    = mpl2_read_header,
> > +    .read_packet    = mpl2_read_packet,
> > +    .read_seek2     = mpl2_read_seek,
> > +    .read_close     = mpl2_read_close,
> > +    .extensions     = "txt,mpl2",
> > +};
> > diff --git a/libavformat/version.h b/libavformat/version.h
> > index bd14e56..8a22dd4 100644
> > --- a/libavformat/version.h
> > +++ b/libavformat/version.h
> > @@ -30,8 +30,8 @@
> >  #include "libavutil/avutil.h"
> >  
> >  #define LIBAVFORMAT_VERSION_MAJOR 54
> > -#define LIBAVFORMAT_VERSION_MINOR 50
> > -#define LIBAVFORMAT_VERSION_MICRO 102
> > +#define LIBAVFORMAT_VERSION_MINOR 51
> > +#define LIBAVFORMAT_VERSION_MICRO 100
> >  
> >  #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
> >                                                 LIBAVFORMAT_VERSION_MINOR, \
> > diff --git a/tests/fate/subtitles.mak b/tests/fate/subtitles.mak
> > index 55c9557..9934ddf 100644
> > --- a/tests/fate/subtitles.mak
> > +++ b/tests/fate/subtitles.mak
> > @@ -10,6 +10,9 @@ fate-sub-movtext: CMD = md5 -i $(SAMPLES)/sub/MovText_capability_tester.mp4 -f a
> >  FATE_SUBTITLES-$(call ENCDEC, MOVTEXT, MOV) += fate-sub-movtextenc
> >  fate-sub-movtextenc: CMD = md5 -i $(SAMPLES)/sub/MovText_capability_tester.mp4 -map 0 -scodec mov_text -f mp4 -flags +bitexact -movflags frag_keyframe+empty_moov
> >  
> > +FATE_SUBTITLES_ASS-$(call DEMDEC, MPL2, MPL2) += fate-sub-mpl2
> > +fate-sub-mpl2: CMD = md5 -i $(SAMPLES)/sub/MPL2_capability_tester.txt -f ass
> > +
> >  FATE_SUBTITLES_ASS-$(call DEMDEC, REALTEXT, REALTEXT) += fate-sub-realtext
> >  fate-sub-realtext: CMD = md5 -i $(SAMPLES)/sub/RealText_capability_tester.rt -f ass
> >  
> > diff --git a/tests/ref/fate/sub-mpl2 b/tests/ref/fate/sub-mpl2
> > new file mode 100644
> > index 0000000..8835dd2
> > --- /dev/null
> > +++ b/tests/ref/fate/sub-mpl2
> > @@ -0,0 +1 @@
> > +3c2fb62002aec3af16d83135a0e3b0fc
> 
> LGTM otherwise.

Will apply in a day or two, thanks.

-- 
Clément B.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20121229/d5bcf7c8/attachment.asc>


More information about the ffmpeg-devel mailing list