[FFmpeg-devel] [RFC, PATCH] RealVideo full-frame demux/decode

Kostya kostya.shishkov
Sat Oct 20 15:14:08 CEST 2007


Here is another attempt on making lavc RV decoder work
with full frames instead of slices.

Attached patches:
0. RM demuxer
1. RV10/20 decoder patch to make it work with slices
2. Indentation after patch #1

Some notes on demuxer: as at least one sample shows that
video frame slices may be interleaved with audio slices
I store them in special buffer and make packet only when
all data for single frame is gathered. 
-------------- next part --------------
Index: libavformat/rm.h
===================================================================
--- libavformat/rm.h	(revision 10722)
+++ libavformat/rm.h	(working copy)
@@ -46,6 +46,9 @@
     int old_format;
     int current_stream;
     int remaining_len;
+    uint8_t *videobuf; ///< place to store merged video frame
+    int videobufsize;  ///< current assembled frame size
+    int cur_slice, slices;
     /// Audio descrambling matrix parameters
     uint8_t *audiobuf; ///< place to store reordered audio data
     int64_t audiotimestamp; ///< Audio packet timestamp
Index: libavformat/rmdec.c
===================================================================
--- libavformat/rmdec.c	(revision 10722)
+++ libavformat/rmdec.c	(working copy)
@@ -365,6 +365,7 @@
 
     n = get_be16(pb);
     (*len)-=2;
+    n &= 0x7FFF;
     if (n >= 0x4000) {
         return n - 0x4000;
     } else {
@@ -433,6 +434,81 @@
     return -1;
 }
 
+static int rm_assemble_video_frame(AVFormatContext *s, RMContext *rm, AVPacket *pkt, int len)
+{
+    ByteIOContext *pb = &s->pb;
+    int hdr, seq, pic_num, len2, pos;
+    int type;
+    int ssize;
+
+    hdr = get_byte(pb); len--;
+    type = hdr >> 6;
+    switch(type){
+    case 0: // slice
+    case 2: // last slice
+        seq = get_byte(pb); len--;
+        len2 = get_num(pb, &len);
+        pos = get_num(pb, &len);
+        pic_num = get_byte(pb); len--;
+        rm->remaining_len = len;
+        break;
+    case 1: //whole frame
+        seq = get_byte(pb); len--;
+        if(av_new_packet(pkt, len + 9) < 0)
+            return AVERROR(EIO);
+        pkt->data[0] = 0;
+        AV_WL32(pkt->data + 1, 1);
+        AV_WL32(pkt->data + 5, 0);
+        get_buffer(pb, pkt->data + 9, len);
+        rm->remaining_len = 0;
+        return 0;
+    case 3: //frame as a part of packet
+        len2 = get_num(pb, &len);
+        pos = get_num(pb, &len);
+        pic_num = get_byte(pb); len--;
+        rm->remaining_len = len - len2;
+        if(av_new_packet(pkt, len2 + 9) < 0)
+            return AVERROR(EIO);
+        pkt->data[0] = 0;
+        AV_WL32(pkt->data + 1, 1);
+        AV_WL32(pkt->data + 5, 0);
+        get_buffer(pb, pkt->data + 9, len2);
+        return 0;
+    }
+    //now we have to deal with single slice
+    rm->cur_slice = seq & 0x7F;
+    rm->slices = ((hdr & 0x3F) << 1) + 1;
+
+    if(rm->cur_slice == 1){//XXX: maybe enable for all slices?
+        ssize = len2 + 8*rm->slices + 1;
+        rm->videobuf = av_realloc(rm->videobuf, ssize);
+        rm->videobufsize = ssize;
+    }
+    if(type == 2){
+        len = FFMIN(len, pos);
+        pos = len2 - pos;
+    }
+
+    AV_WL32(rm->videobuf - 7 + 8*rm->cur_slice, 1);
+    AV_WL32(rm->videobuf - 3 + 8*rm->cur_slice, pos);
+    get_buffer(pb, rm->videobuf + 1 + 8*rm->slices + pos, len);
+    rm->remaining_len-= len;
+
+    if(type == 2 || (pos + len + 1 + 8*rm->slices) == rm->videobufsize){
+         //adjust slice headers
+         memmove(rm->videobuf + 1 + 8*rm->cur_slice, rm->videobuf + 1 + 8*rm->slices, rm->videobufsize - 1 - 8*rm->slices);
+         ssize = rm->videobufsize - 8*(rm->slices - rm->cur_slice);
+
+         rm->videobuf[0] = rm->cur_slice-1;
+         if(av_new_packet(pkt, ssize) < 0)
+             return AVERROR(ENOMEM);
+         memcpy(pkt->data, rm->videobuf, ssize);
+         return 0;
+    }
+
+    return 1;
+}
+
 static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     RMContext *rm = s->priv_data;
@@ -492,32 +568,9 @@
         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);
-
+            if(rm_assemble_video_frame(s, rm, pkt, len) == 1)
+                goto resync;//got partial frame
         } 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) ||
@@ -620,6 +673,7 @@
     RMContext *rm = s->priv_data;
 
     av_free(rm->audiobuf);
+    av_free(rm->videobuf);
     return 0;
 }
 
-------------- next part --------------
Index: libavcodec/rv10.c
===================================================================
--- libavcodec/rv10.c	(revision 10722)
+++ libavcodec/rv10.c	(working copy)
@@ -711,6 +711,12 @@
     return buf_size;
 }
 
+static int get_slice_offset(AVCodecContext *avctx, uint8_t *buf, int n)
+{
+    if(avctx->slice_count) return avctx->slice_offset[n];
+    else                   return AV_RL32(buf + n*8);
+}
+
 static int rv10_decode_frame(AVCodecContext *avctx,
                              void *data, int *data_size,
                              uint8_t *buf, int buf_size)
@@ -718,6 +724,8 @@
     MpegEncContext *s = avctx->priv_data;
     int i;
     AVFrame *pict = data;
+    int slice_count;
+    uint8_t *slices_hdr = NULL;
 
 #ifdef DEBUG
     av_log(avctx, AV_LOG_DEBUG, "*****frame %d size=%d\n", avctx->frame_number, buf_size);
@@ -728,21 +736,24 @@
         return 0;
     }
 
-    if(avctx->slice_count){
-        for(i=0; i<avctx->slice_count; i++){
-            int offset= avctx->slice_offset[i];
+    if(!avctx->slice_count){
+        slice_count = (*buf++) + 1;
+        slices_hdr = buf + 4;
+        buf += 8 * slice_count;
+    }else
+        slice_count = avctx->slice_count;
+
+        for(i=0; i<slice_count; i++){
+            int offset= get_slice_offset(avctx, slices_hdr, 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= get_slice_offset(avctx, slices_hdr, 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);
-------------- next part --------------
--- libavcodec/rv10.c.svn	2007-10-20 16:10:52.000000000 +0300
+++ libavcodec/rv10.c	2007-10-20 16:11:20.000000000 +0300
@@ -743,17 +743,17 @@
     }else
         slice_count = avctx->slice_count;
 
-        for(i=0; i<slice_count; i++){
-            int offset= get_slice_offset(avctx, slices_hdr, i);
-            int size;
-
-            if(i+1 == slice_count)
-                size= buf_size - offset;
-            else
-                size= get_slice_offset(avctx, slices_hdr, i+1) - offset;
+    for(i=0; i<slice_count; i++){
+        int offset= get_slice_offset(avctx, slices_hdr, i);
+        int size;
+
+        if(i+1 == slice_count)
+            size= buf_size - offset;
+        else
+            size= get_slice_offset(avctx, slices_hdr, i+1) - offset;
 
-            rv10_decode_packet(avctx, buf+offset, size);
-        }
+        rv10_decode_packet(avctx, buf+offset, size);
+    }
 
     if(s->current_picture_ptr != NULL && s->mb_y>=s->mb_height){
         ff_er_frame_end(s);



More information about the ffmpeg-devel mailing list