matroskadec: add support for track content encoding
authorAurelien Jacobs <aurel@gnuage.org>
Thu, 8 May 2008 21:47:31 +0000 (21:47 +0000)
committerAurelien Jacobs <aurel@gnuage.org>
Thu, 8 May 2008 21:47:31 +0000 (21:47 +0000)
Only the header strip method is supported for now.

Originally committed as revision 13082 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavformat/matroska.h
libavformat/matroskadec.c

index 370a8bf..025eefb 100644 (file)
@@ -89,6 +89,8 @@
 #define MATROSKA_ID_TRACKMINCACHE 0x6DE7
 #define MATROSKA_ID_TRACKMAXCACHE 0x6DF8
 #define MATROSKA_ID_TRACKDEFAULTDURATION 0x23E383
+#define MATROSKA_ID_TRACKCONTENTENCODINGS 0x6D80
+#define MATROSKA_ID_TRACKCONTENTENCODING 0x6240
 
 /* IDs in the trackvideo master */
 #define MATROSKA_ID_VIDEOFRAMERATE 0x2383E3
 #define MATROSKA_ID_AUDIOBITDEPTH 0x6264
 #define MATROSKA_ID_AUDIOCHANNELS 0x9F
 
+/* IDs in the content encoding master */
+#define MATROSKA_ID_ENCODINGSCOPE 0x5032
+#define MATROSKA_ID_ENCODINGTYPE 0x5033
+#define MATROSKA_ID_ENCODINGCOMPRESSION 0x5034
+#define MATROSKA_ID_ENCODINGCOMPALGO 0x4254
+#define MATROSKA_ID_ENCODINGCOMPSETTINGS 0x4255
+
 /* ID in the cues master */
 #define MATROSKA_ID_POINTENTRY 0xBB
 
@@ -168,6 +177,13 @@ typedef enum {
   MATROSKA_ASPECT_RATIO_MODE_FIXED = 0x2,
 } MatroskaAspectRatioMode;
 
+typedef enum {
+  MATROSKA_TRACK_ENCODING_COMP_ZLIB        = 0,
+  MATROSKA_TRACK_ENCODING_COMP_BZLIB       = 1,
+  MATROSKA_TRACK_ENCODING_COMP_LZO         = 2,
+  MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP = 3,
+} MatroskaTrackEncodingCompAlgo;
+
 /*
  * These aren't in any way "matroska-form" things,
  * it's just something I use in the muxer/demuxer.
index 25fbdd5..4899fb4 100644 (file)
@@ -55,6 +55,11 @@ typedef struct Track {
 
     uint64_t default_duration;
     MatroskaTrackFlags flags;
+
+    int encoding_scope;
+    int encoding_algo;
+    uint8_t *encoding_settings;
+    int encoding_settings_len;
 } MatroskaTrack;
 
 typedef struct MatroskaVideoTrack {
@@ -1428,6 +1433,147 @@ matroska_add_stream (MatroskaDemuxContext *matroska)
                 break;
             }
 
+            case MATROSKA_ID_TRACKCONTENTENCODINGS: {
+                if ((res = ebml_read_master(matroska, &id)) < 0)
+                    break;
+
+                while (res == 0) {
+                    if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
+                        res = AVERROR(EIO);
+                        break;
+                    } else if (matroska->level_up > 0) {
+                        matroska->level_up--;
+                        break;
+                    }
+
+                    switch (id) {
+                        case MATROSKA_ID_TRACKCONTENTENCODING: {
+                            int encoding_scope = 1;
+                            if ((res = ebml_read_master(matroska, &id)) < 0)
+                                break;
+
+                            while (res == 0) {
+                                if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
+                                    res = AVERROR(EIO);
+                                    break;
+                                } else if (matroska->level_up > 0) {
+                                    matroska->level_up--;
+                                    break;
+                                }
+
+                                switch (id) {
+                                    case MATROSKA_ID_ENCODINGSCOPE: {
+                                        uint64_t num;
+                                        if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
+                                            break;
+                                        encoding_scope = num;
+                                        break;
+                                    }
+
+                                    case MATROSKA_ID_ENCODINGTYPE: {
+                                        uint64_t num;
+                                        if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
+                                            break;
+                                        if (num)
+                                            av_log(matroska->ctx, AV_LOG_ERROR,
+                                                   "Unsupported encoding type");
+                                        break;
+                                    }
+
+                                    case MATROSKA_ID_ENCODINGCOMPRESSION: {
+                                        if ((res = ebml_read_master(matroska, &id)) < 0)
+                                            break;
+
+                                        while (res == 0) {
+                                            if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
+                                                res = AVERROR(EIO);
+                                                break;
+                                            } else if (matroska->level_up > 0) {
+                                                matroska->level_up--;
+                                                break;
+                                            }
+
+                                            switch (id) {
+                                                case MATROSKA_ID_ENCODINGCOMPALGO: {
+                                                    uint64_t num;
+                                                    if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
+                                                        break;
+                                                    if (num != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP)
+                                                        av_log(matroska->ctx, AV_LOG_ERROR,
+                                                               "Unsupported compression algo");
+                                                    track->encoding_algo = num;
+                                                    break;
+                                                }
+
+                                                case MATROSKA_ID_ENCODINGCOMPSETTINGS: {
+                                                    uint8_t *data;
+                                                    int size;
+                                                    if ((res = ebml_read_binary(matroska, &id, &data, &size) < 0))
+                                                        break;
+                                                    track->encoding_settings = data;
+                                                    track->encoding_settings_len = size;
+                                                    break;
+                                                }
+
+                                                default:
+                                                    av_log(matroska->ctx, AV_LOG_INFO,
+                                                           "Unknown compression header entry "
+                                                           "0x%x - ignoring\n", id);
+                                                    /* pass-through */
+
+                                                case EBML_ID_VOID:
+                                                    res = ebml_read_skip(matroska);
+                                                    break;
+                                            }
+
+                                            if (matroska->level_up) {
+                                                matroska->level_up--;
+                                                break;
+                                            }
+                                        }
+                                        break;
+                                    }
+
+                                    default:
+                                        av_log(matroska->ctx, AV_LOG_INFO,
+                                               "Unknown content encoding header entry "
+                                               "0x%x - ignoring\n", id);
+                                        /* pass-through */
+
+                                    case EBML_ID_VOID:
+                                        res = ebml_read_skip(matroska);
+                                        break;
+                                }
+
+                                if (matroska->level_up) {
+                                    matroska->level_up--;
+                                    break;
+                                }
+                            }
+
+                            track->encoding_scope = encoding_scope;
+                            break;
+                        }
+
+                        default:
+                            av_log(matroska->ctx, AV_LOG_INFO,
+                                   "Unknown content encodings header entry "
+                                   "0x%x - ignoring\n", id);
+                            /* pass-through */
+
+                        case EBML_ID_VOID:
+                            res = ebml_read_skip(matroska);
+                            break;
+                    }
+
+                    if (matroska->level_up) {
+                        matroska->level_up--;
+                        break;
+                    }
+                }
+                break;
+            }
+
             default:
                 av_log(matroska->ctx, AV_LOG_INFO,
                        "Unknown track header entry 0x%x - ignoring\n", id);
@@ -2551,14 +2697,21 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
             } else {
                 int offset = 0;
 
+                if (matroska->tracks[track]->encoding_scope&1 &&
+                    matroska->tracks[track]->encoding_algo == MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP) {
+                    offset = matroska->tracks[track]->encoding_settings_len;
+                }
+
                 pkt = av_mallocz(sizeof(AVPacket));
                 /* XXX: prevent data copy... */
-                if (av_new_packet(pkt, lace_size[n]-offset) < 0) {
+                if (av_new_packet(pkt, lace_size[n]+offset) < 0) {
                     res = AVERROR(ENOMEM);
                     n = laces-1;
                     break;
                 }
-                memcpy (pkt->data, data+offset, lace_size[n]-offset);
+                if (offset)
+                    memcpy (pkt->data, matroska->tracks[track]->encoding_settings, offset);
+                memcpy (pkt->data+offset, data, lace_size[n]);
 
                 if (n == 0)
                     pkt->flags = is_keyframe;