matroska: split real video frames so that each packet contains only one slice
authorAurelien Jacobs <aurel@gnuage.org>
Mon, 20 Nov 2006 00:31:59 +0000 (00:31 +0000)
committerAurelien Jacobs <aurel@gnuage.org>
Mon, 20 Nov 2006 00:31:59 +0000 (00:31 +0000)
Originally committed as revision 7129 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavformat/matroska.c

index b7f27ec0266dc756fc83d346af46b792fcddb48d..7411bd9f944e20185caa0f6722c4a3e8b9e11ef8 100644 (file)
@@ -176,6 +176,7 @@ typedef enum {
   MATROSKA_TRACK_ENABLED = (1<<0),
   MATROSKA_TRACK_DEFAULT = (1<<1),
   MATROSKA_TRACK_LACING  = (1<<2),
+  MATROSKA_TRACK_REAL_V  = (1<<4),
   MATROSKA_TRACK_SHIFT   = (1<<16)
 } MatroskaTrackFlags;
 
@@ -2267,6 +2268,7 @@ matroska_read_header (AVFormatContext    *s,
                      codec_id == CODEC_ID_RV30 || codec_id == CODEC_ID_RV40) {
                 extradata_offset = 26;
                 track->codec_priv_size -= extradata_offset;
+                track->flags |= MATROSKA_TRACK_REAL_V;
             }
 
             if (codec_id == CODEC_ID_NONE) {
@@ -2348,6 +2350,12 @@ matroska_find_track_by_num (MatroskaDemuxContext *matroska,
     return -1;
 }
 
+static inline int
+rv_offset(uint8_t *data, int slice, int slices)
+{
+    return LE_32(data+8*slice+4) + 8*slices;
+}
+
 static int
 matroska_parse_blockgroup (MatroskaDemuxContext *matroska,
                            uint64_t              cluster_time)
@@ -2498,14 +2506,14 @@ matroska_parse_blockgroup (MatroskaDemuxContext *matroska,
                 }
 
                 if (res == 0) {
+                    int real_v = matroska->tracks[track]->flags & MATROSKA_TRACK_REAL_V;
                     for (n = 0; n < laces; n++) {
                         uint64_t timecode = AV_NOPTS_VALUE;
+                        int slice, slices = 1;
 
-                        pkt = av_mallocz(sizeof(AVPacket));
-                        /* XXX: prevent data copy... */
-                        if (av_new_packet(pkt,lace_size[n]) < 0) {
-                            res = AVERROR_NOMEM;
-                            break;
+                        if (real_v) {
+                            slices = *data++ + 1;
+                            lace_size[n]--;
                         }
                         if (cluster_time != (uint64_t)-1 && n == 0) {
                             if (cluster_time + block_time >= 0)
@@ -2513,8 +2521,23 @@ matroska_parse_blockgroup (MatroskaDemuxContext *matroska,
                         }
                         /* FIXME: duration */
 
-                        memcpy(pkt->data, data, lace_size[n]);
-                        data += lace_size[n];
+                        for (slice=0; slice<slices; slice++) {
+                            int slice_size, slice_offset = 0;
+                            if (real_v)
+                                slice_offset = rv_offset(data, slice, slices);
+                            if (slice+1 == slices)
+                                slice_size = lace_size[n] - slice_offset;
+                            else
+                                slice_size = rv_offset(data, slice+1, slices) - slice_offset;
+                            pkt = av_mallocz(sizeof(AVPacket));
+                            /* XXX: prevent data copy... */
+                            if (av_new_packet(pkt, slice_size) < 0) {
+                                res = AVERROR_NOMEM;
+                                n = laces-1;
+                                break;
+                            }
+                            memcpy (pkt->data, data+slice_offset, slice_size);
+
                         if (n == 0)
                             pkt->flags = is_keyframe;
                         pkt->stream_index =
@@ -2524,6 +2547,8 @@ matroska_parse_blockgroup (MatroskaDemuxContext *matroska,
                         pkt->pos= pos;
 
                         matroska_queue_packet(matroska, pkt);
+                        }
+                        data += lace_size[n];
                     }
                 }