summaryrefslogtreecommitdiff
path: root/libavformat/movenc.c
diff options
context:
space:
mode:
authorDavid Conrad <lessen42@gmail.com>2009-01-11 10:26:44 +0000
committerDavid Conrad <lessen42@gmail.com>2009-01-11 10:26:44 +0000
commitf620488654700dfc06ce5548baa15c4344662969 (patch)
tree39117b591ff7835775950ebd66d0fae0fcdc16a4 /libavformat/movenc.c
parent58e9f2edb6cbb4f97c4a9a48fd086cfec19b6f26 (diff)
Add support for muxing mov/mp4/3gp timed text streams
Originally committed as revision 16531 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavformat/movenc.c')
-rw-r--r--libavformat/movenc.c66
1 files changed, 63 insertions, 3 deletions
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 6ddbed16f4..bb900e3e52 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 },
};
@@ -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);
}
}