[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