[FFmpeg-devel] [PATCH] MP4 Subtitle support

Clément Bœsch ubitux at gmail.com
Thu Oct 4 09:47:16 CEST 2012


On Wed, Oct 03, 2012 at 04:29:53PM +0200, Benjamin Rainer wrote:
> 	modified:   libavformat/isom.c
> 	modified:   libavformat/isom.h
> 	modified:   libavformat/mov.c
> 	modified:   libavformat/riff.h
> 	modified:   libavformat/utils.c
> 
> Added support for subtitles in MP4 (other than tx3g). Added support for the TextMetadataSampleEntry box ('mett') and XMLMetadataSampleEntry box ('metx'). Codecs are detected by the mime type.
> ---
>  libavformat/isom.c  |    9 ++++++++
>  libavformat/isom.h  |    1 +
>  libavformat/mov.c   |   63 +++++++++++++++++++++++++++++++++++++++++++--------
>  libavformat/riff.h  |    1 +
>  libavformat/utils.c |   13 +++++++++++
>  5 files changed, 77 insertions(+), 10 deletions(-)
> 
> diff --git a/libavformat/isom.c b/libavformat/isom.c
> index caa4d17..1396c9e 100644
> --- a/libavformat/isom.c
> +++ b/libavformat/isom.c
> @@ -302,6 +302,15 @@ const AVCodecTag ff_codec_movsubtitle_tags[] = {
>      { AV_CODEC_ID_NONE, 0 },
>  };
>  
> +const CodecMime ff_codec_movsubtitle_mimetypes[] = {
> +    { "text/srt", 	AV_CODEC_ID_SRT },	/* extend */
> +    { "text/subip",	AV_CODEC_ID_SUBRIP },
> +    { "text/webvtt", 	AV_CODEC_ID_WEBVTT },
> +    { "text/rtext", 	AV_CODEC_ID_REALTEXT },
> +    { "text/subV",  	AV_CODEC_ID_SUBVIEWER },
> +    { "",		AV_CODEC_ID_NONE },
> +};

Tabs are not allowed in FFmpeg. Also you ave a typo: s/subip/subrip/

> +
>  /* map numeric codes from mdhd atom to ISO 639 */
>  /* cf. QTFileFormat.pdf p253, qtff.pdf p205 */
>  /* http://developer.apple.com/documentation/mac/Text/Text-368.html */
> diff --git a/libavformat/isom.h b/libavformat/isom.h
> index 370ba43..4a52a28 100644
> --- a/libavformat/isom.h
> +++ b/libavformat/isom.h
> @@ -33,6 +33,7 @@ extern const AVCodecTag ff_mp4_obj_type[];
>  extern const AVCodecTag ff_codec_movvideo_tags[];
>  extern const AVCodecTag ff_codec_movaudio_tags[];
>  extern const AVCodecTag ff_codec_movsubtitle_tags[];
> +extern const CodecMime	ff_codec_movsubtitlte_mime_types[];
>  
>  int ff_mov_iso639_to_lang(const char lang[4], int mp4);
>  int ff_mov_lang_to_iso639(unsigned code, char to[4]);
> diff --git a/libavformat/mov.c b/libavformat/mov.c
> index 0639ddb..129dcdf 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -394,6 +394,25 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
>      return 0;
>  }
>  
> +static int mov_read_metadata_string(AVDictionary **metadata, AVIOContext *pb, MOVAtom atom, const char *dict_entry_name)
> +{
> +    char *str,*p;
> +    
> +    p = str = (char *)av_mallocz(atom.size); /* we do not know the size of the string, size of the box should be enough */
> +  
> +    if(!str)
> +	return AVERROR(ENOMEM);   
> +
> +    while((*str = avio_r8(pb)) != (int)NULL) str++;
> +    
> +    av_dict_set(metadata, dict_entry_name, p,0); /* add the string into our dictonary */
> +    

typo: dictionary

You also have various trailing whitespaces.

> +    av_free(p);
> +
> +    return 0;
> +
> +}
> +
>  static int mov_read_chpl(MOVContext *c, AVIOContext *pb, MOVAtom atom)
>  {
>      int64_t start;
> @@ -563,7 +582,7 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
>          st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
>      else if (type == MKTAG('m','1','a',' '))
>          st->codec->codec_id = AV_CODEC_ID_MP2;
> -    else if ((type == MKTAG('s','u','b','p')) || (type == MKTAG('c','l','c','p')))
> +    else if ((type == MKTAG('s','u','b','p')) || (type == MKTAG('c','l','c','p')) || (type == MKTAG('s','u','b','m')) || (type == MKTAG('s','u','b','r')))
>          st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
>  
>      avio_rb32(pb); /* component  manufacture */
> @@ -1237,7 +1256,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
>          }
>          /* we cannot demux concatenated h264 streams because of different extradata */
>          if (st->codec->codec_tag && st->codec->codec_tag == AV_RL32("avc1"))
> -            av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 might not play corrently.\n");
> +            av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 might not play correctly.\n");
>          sc->pseudo_stream_id = st->codec->codec_tag ? -1 : pseudo_stream_id;
>          sc->dref_id= dref_id;
>  
> @@ -1455,14 +1474,38 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
>                  sc->sample_size = (bits_per_sample >> 3) * st->codec->channels;
>              }
>          } else if (st->codec->codec_type==AVMEDIA_TYPE_SUBTITLE){
> -            // ttxt stsd contains display flags, justification, background
> -            // color, fonts, and default styles, so fake an atom to read it
> -            MOVAtom fake_atom = { .size = size - (avio_tell(pb) - start_pos) };
> -            if (format != AV_RL32("mp4s")) // mp4s contains a regular esds atom
> -                mov_read_glbl(c, pb, fake_atom);
> -            st->codec->codec_id= id;
> -            st->codec->width = sc->width;
> -            st->codec->height = sc->height;
> +            /* if we got the mett box there has to be the mime_format set, so we can select the appropriate codec for subtitles*/
> +	    if(format == MKTAG('m','e','t','t'))
> +	    {
> +		MOVAtom mett_atom = { .size = size - (avio_tell(pb) - start_pos) };
> +
> +		mov_read_metadata_string(&st->metadata, pb, mett_atom, "content_encoding"); /* optional */
> +		mov_read_metadata_string(&st->metadata, pb, mett_atom, "mime_format");
> +
> +		st->codec->codec_id = ff_codec_get_id_from_mime(ff_codec_movsubtitle_mimetypes,  ((AVDictionaryEntry *)av_dict_get(st->metadata, "mime_format", NULL, 0))->value);
> +
> +	    }else if(format == MKTAG('m','e','t','x'))
> +	    {
> +		MOVAtom metx_atom = { .size = size - (avio_tell(pb) - start_pos) };
> +
> +		mov_read_metadata_string(&st->metadata, pb, metx_atom, "content_encoding"); /* optional */
> +		mov_read_metadata_string(&st->metadata, pb, metx_atom, "namespace");
> +		mov_read_metadata_string(&st->metadata, pb, metx_atom, "schema_location");  /* optional */
> +		
> +		/* should identify codec by the namespace ... */
> +
> +	    }else
> +	    {
> +
> +   	       // ttxt stsd contains display flags, justification, background
> +               // color, fonts, and default styles, so fake an atom to read it
> +       	       MOVAtom fake_atom = { .size = size - (avio_tell(pb) - start_pos) };
> +               if (format != AV_RL32("mp4s")) // mp4s contains a regular esds atom
> +                   mov_read_glbl(c, pb, fake_atom);
> +               st->codec->codec_id= id;
> +               st->codec->width = sc->width;
> +               st->codec->height = sc->height;
> +	   }

On the form: various typo, trailing whitespaces, tabs and bad styles;
please stick with the surrounding coding style.

BTW overall I think the approach is wrong: what you likely want is a "raw
text" subtitles encoder: basically a subtitle codec to strip all the ASS
tags from the internal representation, and use it in MOV to encode text
(with no markup) subtitles.

Why: because I believe putting various broken markups into MOV is wrong,
and it also means quite a maintenance burden to support all the different
subtitles codecs into MOV (and add some regularly).

[...]

-- 
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/20121004/631a1ebe/attachment.asc>


More information about the ffmpeg-devel mailing list