[FFmpeg-devel] [RFC] Feed whole frames to RV* decoders

Kostya kostya.shishkov
Tue Oct 2 07:02:59 CEST 2007


Here is an updated working version of gathering complete frames
for Real Video decoders. Both RM and Matroska demuxers are passing
whole frames to RealVideo decoder (RV10/20 is patched to accept
this format).

Please comment. 
-------------- next part --------------
Index: libavcodec/rv10.c
===================================================================
--- libavcodec/rv10.c	(revision 10505)
+++ libavcodec/rv10.c	(working copy)
@@ -718,6 +718,7 @@
     MpegEncContext *s = avctx->priv_data;
     int i;
     AVFrame *pict = data;
+    int slice_count, *slice_offset;
 
 #ifdef DEBUG
     av_log(avctx, AV_LOG_DEBUG, "*****frame %d size=%d\n", avctx->frame_number, buf_size);
@@ -729,20 +730,29 @@
     }
 
     if(avctx->slice_count){
-        for(i=0; i<avctx->slice_count; i++){
-            int offset= avctx->slice_offset[i];
+        slice_count = avctx->slice_count;
+        slice_offset = avctx->slice_offset;
+    }else{
+        slice_count = (*buf++) + 1;
+        slice_offset = av_malloc(sizeof(int)*slice_count);
+        for(i = 0; i < slice_count; i++){
+            buf += 4;
+            slice_offset[i] = AV_RL32(buf);
+            buf += 4;
+        }
+    }
+
+        for(i=0; i<slice_count; i++){
+            int offset= slice_offset[i];
             int size;
 
-            if(i+1 == avctx->slice_count)
+            if(i+1 == slice_count)
                 size= buf_size - offset;
             else
-                size= avctx->slice_offset[i+1] - offset;
+                size= slice_offset[i+1] - offset;
 
             rv10_decode_packet(avctx, buf+offset, size);
         }
-    }else{
-        rv10_decode_packet(avctx, buf, buf_size);
-    }
 
     if(s->current_picture_ptr != NULL && s->mb_y>=s->mb_height){
         ff_er_frame_end(s);
Index: libavformat/matroskadec.c
===================================================================
--- libavformat/matroskadec.c	(revision 10505)
+++ libavformat/matroskadec.c	(working copy)
@@ -2390,8 +2390,25 @@
             int slice, slices = 1;
 
             if (real_v) {
-                slices = *data++ + 1;
-                lace_size[n]--;
+                pkt = av_mallocz(sizeof(AVPacket));
+                /* XXX: prevent data copy... */
+                if (av_new_packet(pkt, lace_size[n]) < 0) {
+                    res = AVERROR(ENOMEM);
+                    n = laces-1;
+                    break;
+                }
+                memcpy (pkt->data, data, lace_size[n]);
+
+                if (n == 0)
+                    pkt->flags = is_keyframe;
+                pkt->stream_index = matroska->tracks[track]->stream_index;
+
+                pkt->pts = timecode;
+                pkt->pos = pos;
+                pkt->duration = duration;
+
+                matroska_queue_packet(matroska, pkt);
+                continue;
             }
 
             for (slice=0; slice<slices; slice++) {
Index: libavformat/rmdec.c
===================================================================
--- libavformat/rmdec.c	(revision 10505)
+++ libavformat/rmdec.c	(working copy)
@@ -364,6 +364,10 @@
 
     n = get_be16(pb);
     (*len)-=2;
+    if (n >= 0x8000) {
+        av_log(NULL,0,"Got number %X\n",n);
+        n -= 0x8000;
+    }
     if (n >= 0x4000) {
         return n - 0x4000;
     } else {
@@ -432,6 +436,112 @@
     return -1;
 }
 
+static int rm_assemble_frame(AVFormatContext *s, RMContext *rm, ByteIOContext *pb, AVPacket *pkt, int len)
+{
+    int hdr, type, seq, pic_num, pkt_len, pos, frame_length, ret;
+    int slices, slice_count;
+    uint8_t *slice_hdr, *slice_data, *slice_data_start, *data_end;
+    int flags, idx;
+    int64_t timestamp, pos2;
+
+    hdr = get_byte(pb); len--;
+    type = hdr >> 6;
+
+    switch (type) {
+    case 0: // partial frame start
+    case 2: // partial frame end - should not happen here
+        seq = get_byte(pb); len--;
+        pkt_len = get_num(pb, &len);
+        pos = get_num(pb, &len);
+        pic_num = get_byte(pb); len--;
+        frame_length = len;
+        slices = (((hdr << 8) | seq) >> 7) & 0x7F;
+        slices++; //sometimes first slice report one less slice that consequent slices
+        break;
+    case 1: // whole frame
+        pic_num = get_byte(pb); len--;
+        pos = 0;
+        frame_length = pkt_len = len;
+        slices = 1;
+        break;
+    case 3: // one of multiple frames in one packet
+        pkt_len = get_num(pb, &len);
+        pos = get_num(pb, &len);
+        pic_num = get_byte(pb); len--;
+        frame_length = pkt_len;
+        slices = 1;
+        break;
+    }
+    
+    if (type == 2) //frame tail should not be met here
+        return -1;
+
+    if(av_new_packet(pkt, pkt_len + slices * 8 + 1))
+        return AVERROR(ENOMEM);
+    slice_hdr = pkt->data + 1;
+    slice_data = slice_data_start = slice_hdr + slices * 8;
+    data_end = pkt->data + pkt_len + slices * 8 + 1;
+   
+    pkt->data[0] = slices - 1;
+    
+    AV_WL32(slice_hdr + 0, 1);
+    AV_WL32(slice_hdr + 4, 0);
+    slice_hdr += 8;
+    ret = get_buffer(pb, slice_data, frame_length);
+    if (ret != frame_length) {
+         av_free_packet(pkt);
+         return AVERROR(EIO);
+    }
+    slice_data += frame_length;
+    slice_count = 1;
+    rm->remaining_len = len - frame_length;
+    while(slice_data < data_end && slice_count < slices) {
+        len=sync(s, &timestamp, &flags, &idx, &pos2);
+        if (len<0) {
+            av_free_packet(pkt);
+            return AVERROR(EIO);
+        }
+
+        hdr = get_byte(pb); len--;
+        type = hdr >> 6;
+        seq = get_byte(pb); len--;
+        pkt_len = get_num(pb, &len);
+        pos = get_num(pb, &len);
+        pic_num = get_byte(pb); len--;
+        
+        if (type == 2) {
+            rm->remaining_len = len - pos;
+            frame_length = pos;
+        } else {
+            frame_length = len;
+        }
+        if (slice_data + frame_length > data_end) {
+            av_free_packet(pkt);
+            return AVERROR(EIO);
+        }
+        
+        AV_WL32(slice_hdr + 0, 1);
+        AV_WL32(slice_hdr + 4, slice_data - slice_data_start);
+        slice_hdr += 8;
+
+        ret = get_buffer(pb, slice_data, frame_length);
+        if (ret != frame_length) {
+            av_free_packet(pkt);
+            return AVERROR(EIO);
+        }
+        slice_data += frame_length;
+        slice_count++;
+        if (type == 2) 
+            break;
+    }
+    if(slice_count < slices){
+        pkt->data[0] = slice_count - 1;
+        memmove(slice_hdr, slice_hdr+8*(slices - slice_count), pkt->size - 1 - 8*slices);
+        pkt->size -= 8*(slices - slice_count);
+    }
+    return 0;
+}
+
 static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     RMContext *rm = s->priv_data;
@@ -491,32 +601,8 @@
         st = s->streams[i];
 
         if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
-            int h, pic_num, len2, pos;
-
-            h= get_byte(pb); len--;
-            if(!(h & 0x40)){
-                seq = get_byte(pb); len--;
-            }
-
-            if((h & 0xc0) == 0x40){
-                len2= pos= 0;
-            }else{
-                len2 = get_num(pb, &len);
-                pos = get_num(pb, &len);
-            }
-            /* picture number */
-            pic_num= get_byte(pb); len--;
-            rm->remaining_len= len;
-            rm->current_stream= st->id;
-
-//            av_log(NULL, AV_LOG_DEBUG, "%X len:%d pos:%d len2:%d pic_num:%d\n",h, len, pos, len2, pic_num);
-            if((h & 0xc0) == 0x80)
-                len=pos;
-            if(len2 && len2<len)
-                len=len2;
-            rm->remaining_len-= len;
-            av_get_packet(pb, pkt, len);
-
+            rm->current_stream = st->id;
+            rm_assemble_frame(s, rm, pb, pkt, len);
         } else if (st->codec->codec_type == CODEC_TYPE_AUDIO) {
             if ((st->codec->codec_id == CODEC_ID_RA_288) ||
                 (st->codec->codec_id == CODEC_ID_COOK) ||



More information about the ffmpeg-devel mailing list