[FFmpeg-devel] [PATCH] Add support for muxing timed text in mov/mp4/3gp

Baptiste Coudurier baptiste.coudurier
Sun Jan 11 09:05:51 CET 2009


David Conrad wrote:
> Hi,
> 
> This adds support for muxing timed text in mov/mp4/3gp. For the iPod
> mode it works slightly different ("sbtl" rather than "text" for the
> media type) which is the only way iPods recognize it, also causing
> QuickTime to treat it very differently than standard timed text (mainly
> ignoring most style elements and requiring different dimensions.) I
> don't think it's worth making a new CODEC_ID for this variant though.
> 
> Also, 3GPP TS 26.245 says to use a null media handler (nmhd) but that
> doesn't work for .mov for QuickTime, thus the generic media handler
> (gmhd) for .mov.
> 
> [...]
>
> --- a/libavformat/isom.c
> +++ b/libavformat/isom.c
> @@ -28,6 +28,7 @@
>  /* http://www.mp4ra.org */
>  /* ordered by muxing preference */
>  const AVCodecTag ff_mp4_obj_type[] = {
> +    { CODEC_ID_MOV_TEXT  , 0x08 },
>      { CODEC_ID_MPEG4     , 0x20 },
>      { CODEC_ID_H264      , 0x21 },
>      { CODEC_ID_AAC       , 0x40 },

Ok

> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> index 6ddbed1..e26a130 100644
> --- a/libavformat/movenc.c
> +++ b/libavformat/movenc.c
> @@ -550,6 +550,7 @@ static const AVCodecTag codec_3gp_tags[] = {
>      { CODEC_ID_AAC,    MKTAG('m','p','4','a') },
>      { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
>      { CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
> +    { CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
>      { CODEC_ID_NONE, 0 },
>  };

Ok

> @@ -567,6 +568,7 @@ static const AVCodecTag codec_ipod_tags[] = {
>      { CODEC_ID_AAC,    MKTAG('m','p','4','a') },
>      { CODEC_ID_ALAC,   MKTAG('a','l','a','c') },
>      { CODEC_ID_AC3,    MKTAG('a','c','-','3') },
> +    { CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
>      { CODEC_ID_NONE, 0 },
>  };

Ok

> @@ -579,6 +581,7 @@ static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
>          if      (track->enc->codec_id == CODEC_ID_H264)      tag = MKTAG('a','v','c','1');
>          else if (track->enc->codec_id == CODEC_ID_AC3)       tag = MKTAG('a','c','-','3');
>          else if (track->enc->codec_id == CODEC_ID_DIRAC)     tag = MKTAG('d','r','a','c');
> +        else if (track->enc->codec_id == CODEC_ID_MOV_TEXT)  tag = MKTAG('t','x','3','g');
>          else if (track->enc->codec_type == CODEC_TYPE_VIDEO) tag = MKTAG('m','p','4','v');
>          else if (track->enc->codec_type == CODEC_TYPE_AUDIO) tag = MKTAG('m','p','4','a');
>      } else if (track->mode == MODE_IPOD) {

Ok

> @@ -621,6 +624,8 @@ static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
>                                 "the file may be unplayable!\n");
>                      }
>                  }
> +            } else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE) {
> +                tag = codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id);
>              }
>          }
>      }

Ok

> @@ -643,6 +648,21 @@ static int mov_write_uuid_tag_ipod(ByteIOContext *pb)
>      return 28;
>  }
>  
> +static int mov_write_subtitle_tag(ByteIOContext *pb, MOVTrack *track)
> +{
> +    int64_t pos = url_ftell(pb);
> +    put_be32(pb, 0);    /* size */
> +    put_le32(pb, track->tag); // store it byteswapped
> +    put_be32(pb, 0);    /* Reserved */
> +    put_be16(pb, 0);    /* Reserved */
> +    put_be16(pb, 1);    /* Data-reference index */
> +
> +    if (track->enc->extradata_size)
> +        put_buffer(pb, track->enc->extradata, track->enc->extradata_size);
> +
> +    return updateSize(pb, pos);
> +}
> +
>  static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track)
>  {
>      int64_t pos = url_ftell(pb);
> @@ -718,6 +738,8 @@ static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack *track)
>          mov_write_video_tag(pb, track);
>      else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
>          mov_write_audio_tag(pb, track);
> +    else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE)
> +        mov_write_subtitle_tag(pb, track);
>      return updateSize(pb, pos);
>  }

Ok

> @@ -838,6 +860,30 @@ static int mov_write_dinf_tag(ByteIOContext *pb)
>      return updateSize(pb, pos);
>  }
>  
> +static int mov_write_nmhd_tag(ByteIOContext *pb)
> +{
> +    put_be32(pb, 12);
> +    put_tag(pb, "nmhd");
> +    put_be32(pb, 0);
> +    return 12;
> +}
> +
> +static int mov_write_gmhd_tag(ByteIOContext *pb)
> +{
> +    put_be32(pb, 0x20);   /* size */
> +    put_tag(pb, "gmhd");
> +    put_be32(pb, 0x18);   /* gmin size */
> +    put_tag(pb, "gmin");  /* generic media info */
> +    put_be32(pb, 0);      /* version & flags */
> +    put_be16(pb, 0x40);   /* graphics mode = */
> +    put_be16(pb, 0x8000); /* opColor (r?) */
> +    put_be16(pb, 0x8000); /* opColor (g?) */
> +    put_be16(pb, 0x8000); /* opColor (b?) */
> +    put_be16(pb, 0);      /* balance */
> +    put_be16(pb, 0);      /* reserved */
> +    return 0x20;
> +}
> +
>  static int mov_write_smhd_tag(ByteIOContext *pb)
>  {
>      put_be32(pb, 16); /* size */

Ok

> @@ -871,9 +917,15 @@ static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack *track)
>          if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
>              hdlr_type = "vide";
>              descr = "VideoHandler";
> -        } else {
> +        } else if (track->enc->codec_type == CODEC_TYPE_AUDIO){
>              hdlr_type = "soun";
>              descr = "SoundHandler";
> +        } else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE){
> +            if (track->mode == MODE_IPOD)
> +                hdlr_type = "sbtl";
> +            else
> +                hdlr_type = "text";
> +            descr = "SubtitleHandler";

Nitpick:

if (track->mode == MODE_IPOD) hdlr_type = "sbtl";
else                          hdlr_type = "text";

>          }
>      }
>  
> @@ -897,8 +949,12 @@ static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack *track)
>      put_tag(pb, "minf");
>      if(track->enc->codec_type == CODEC_TYPE_VIDEO)
>          mov_write_vmhd_tag(pb);
> -    else
> +    else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
>          mov_write_smhd_tag(pb);
> +    else if (track->mode == MODE_MOV)
> +        mov_write_gmhd_tag(pb);
> +    else
> +        mov_write_nmhd_tag(pb);

Missing codec_type == CODEC_TYPE_SUBTITLE

>      if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */
>          mov_write_hdlr_tag(pb, NULL);
>      mov_write_dinf_tag(pb);
> @@ -989,7 +1045,8 @@ static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack *track, AVStream *st)
>      put_be32(pb, 0x40000000); /* reserved */
>  
>      /* Track width and height, for visual only */
> -    if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
> +    if(track->enc->codec_type == CODEC_TYPE_VIDEO ||
> +       track->enc->codec_type == CODEC_TYPE_SUBTITLE) {
>          double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
>          if(!sample_aspect_ratio) sample_aspect_ratio = 1;
>          put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000);
> @@ -1624,6 +1681,9 @@ static int mov_write_header(AVFormatContext *s)
>                         i, track->enc->sample_rate);
>                  return -1;
>              }
> +        }else if(st->codec->codec_type == CODEC_TYPE_SUBTITLE){
> +            track->timescale = st->codec->time_base.den;
> +            av_set_pts_info(st, 64, 1, st->codec->time_base.den);
>          }
>      }
>  

Ok

-- 
Baptiste COUDURIER                              GnuPG Key Id: 0x5C1ABAAA
Key fingerprint                 8D77134D20CC9220201FC5DB0AC9325C5C1ABAAA
checking for life_signs in -lkenny... no




More information about the ffmpeg-devel mailing list