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:
parent
58e9f2edb6
commit
f620488654
@ -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 },
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user