Add support for muxing mov/mp4/3gp timed text streams

Originally committed as revision 16531 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
David Conrad 2009-01-11 10:26:44 +00:00
parent 58e9f2edb6
commit f620488654
2 changed files with 64 additions and 3 deletions

View File

@ -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 },

View File

@ -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 },
};
@ -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 },
};
@ -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) {
@ -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);
}
}
}
@ -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);
}
@ -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 */
@ -871,9 +917,13 @@ 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";
}
}
@ -897,8 +947,14 @@ 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->enc->codec_type == CODEC_TYPE_SUBTITLE) {
if (track->mode == MODE_MOV)
mov_write_gmhd_tag(pb);
else
mov_write_nmhd_tag(pb);
}
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);
}
}