changeset 4193:2d3be324c648 libavformat

Add support for muxing mov/mp4/3gp timed text streams
author conrad
date Sun, 11 Jan 2009 10:26:44 +0000
parents a48a6a414dfe
children 67ab85a3611d
files isom.c movenc.c
diffstat 2 files changed, 64 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/isom.c	Sun Jan 11 08:24:44 2009 +0000
+++ b/isom.c	Sun Jan 11 10:26:44 2009 +0000
@@ -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 },
--- a/movenc.c	Sun Jan 11 08:24:44 2009 +0000
+++ b/movenc.c	Sun Jan 11 10:26:44 2009 +0000
@@ -550,6 +550,7 @@
     { 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 @@
     { 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 @@
         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 @@
                                "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 @@
     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 @@
         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 @@
     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 @@
         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 @@
     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 @@
     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 @@
                        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);
         }
     }