[libav-devel] [PATCH] movenc: Add dvd subtitle support

John Stebbins stebbins at jetheaddev.com
Tue Mar 18 03:59:37 CET 2014


---
 libavformat/movenc.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 91 insertions(+), 4 deletions(-)

diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 2ae3475..3f1e65b 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -308,7 +308,9 @@ static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
 
     // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
     // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
-    if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
+    if (track->enc->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
+        avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
+    else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
         avio_w8(pb, 0x15); // flags (= Audiostream)
     else
         avio_w8(pb, 0x11); // flags (= Visualstream)
@@ -759,6 +761,7 @@ static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
     else if (track->enc->codec_id == AV_CODEC_ID_VC1)       tag = MKTAG('v','c','-','1');
     else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO)  tag = MKTAG('m','p','4','v');
     else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)  tag = MKTAG('m','p','4','a');
+    else if (track->enc->codec_id == AV_CODEC_ID_DVD_SUBTITLE)  tag = MKTAG('m','p','4','s');
 
     return tag;
 }
@@ -981,6 +984,21 @@ static int mov_write_subtitle_tag(AVIOContext *pb, MOVTrack *track)
     return update_size(pb, pos);
 }
 
+static int mov_write_subpic_tag(AVIOContext *pb, MOVTrack *track)
+{
+    int64_t pos = avio_tell(pb);
+
+    avio_wb32(pb, 0); /* size */
+    avio_wl32(pb, track->tag); // store it byteswapped
+    avio_wb32(pb, 0); /* Reserved */
+    avio_wb16(pb, 0); /* Reserved */
+    avio_wb16(pb, 1); /* Data-reference index */
+
+    mov_write_esds_tag(pb, track);
+
+    return update_size(pb, pos);
+}
+
 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
 {
     AVRational sar;
@@ -1116,6 +1134,8 @@ static int mov_write_stsd_tag(AVIOContext *pb, MOVTrack *track)
         mov_write_video_tag(pb, track);
     else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
         mov_write_audio_tag(pb, track);
+    else if (track->enc->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
+        mov_write_subpic_tag(pb, track);
     else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)
         mov_write_subtitle_tag(pb, track);
     else if (track->enc->codec_tag == MKTAG('r','t','p',' '))
@@ -1307,6 +1327,7 @@ static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track)
             descr     = "SoundHandler";
         } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) {
             if (track->tag == MKTAG('t','x','3','g')) hdlr_type = "sbtl";
+            if (track->tag == MKTAG('m','p','4','s')) hdlr_type = "subp";
             else                                      hdlr_type = "text";
             descr = "SubtitleHandler";
         } else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) {
@@ -3175,6 +3196,68 @@ static void mov_free(AVFormatContext *s)
     av_freep(&mov->tracks);
 }
 
+static uint32_t rgb_to_yuv(uint32_t rgb)
+{
+    uint8_t r, g, b;
+    int y, cb, cr;
+
+    r = (rgb >> 16) & 0xFF;
+    g = (rgb >>  8) & 0xFF;
+    b = (rgb      ) & 0xFF;
+
+    y  = av_clip_uint8( 16. +  0.257 * r + 0.504 * g + 0.098 * b);
+    cb = av_clip_uint8(128. -  0.148 * r - 0.291 * g + 0.439 * b);
+    cr = av_clip_uint8(128. +  0.439 * r - 0.368 * g - 0.071 * b);
+
+    return (y << 16) | (cr << 8) | cb;
+}
+
+static int mov_rewrite_dvd_sub_extradata(MOVTrack *track, AVStream *st)
+{
+    int i, width, height;
+    int have_palette, have_size;
+    uint32_t palette[16];
+    char *cur;
+
+    if (!st->codec->extradata || !st->codec->extradata_size)
+        return AVERROR_INVALIDDATA;
+
+    cur = st->codec->extradata;
+    while (*cur) {
+        if (strncmp("palette:", cur, 8) == 0) {
+            int i;
+            char *p = cur + 8;
+            for (i = 0; i < 16; i++) {
+                palette[i] = rgb_to_yuv(strtoul(p, &p, 16));
+                while (*p == ',' || av_isspace(*p))
+                    p++;
+            }
+            have_palette = 1;
+        } else if (!strncmp("size:", cur, 5)) {
+            if (sscanf(cur + 5, "%dx%d", &width, &height) != 2) {
+                return AVERROR_INVALIDDATA;
+            }
+            have_size = 1;
+        }
+        if (have_palette && have_size)
+            break;
+        cur += strcspn(cur, "\n\r");
+        cur += strspn(cur, "\n\r");
+    }
+    if (!have_palette || !have_size)
+        return AVERROR_INVALIDDATA;
+
+    track->vos_data = av_malloc(16*4);
+    for (i = 0; i < 16; i++) {
+        AV_WB32(track->vos_data + i * 4, palette[i]);
+    }
+    track->vos_len = 16 * 4;
+    st->codec->width = width;
+    st->codec->height = track->height = height;
+
+    return 0;
+}
+
 static int mov_write_header(AVFormatContext *s)
 {
     AVIOContext *pb = s->pb;
@@ -3331,9 +3414,13 @@ static int mov_write_header(AVFormatContext *s)
 
         /* copy extradata if it exists */
         if (st->codec->extradata_size) {
-            track->vos_len  = st->codec->extradata_size;
-            track->vos_data = av_malloc(track->vos_len);
-            memcpy(track->vos_data, st->codec->extradata, track->vos_len);
+            if (st->codec->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
+                mov_rewrite_dvd_sub_extradata(track, st);
+            else {
+                track->vos_len  = st->codec->extradata_size;
+                track->vos_data = av_malloc(track->vos_len);
+                memcpy(track->vos_data, st->codec->extradata, track->vos_len);
+            }
         }
     }
 
-- 
1.8.5.3



More information about the libav-devel mailing list