[FFmpeg-devel] [RFC] RM full-frame demuxer

Kostya kostya.shishkov
Sun Sep 30 14:39:09 CEST 2007


Here is my attempt to write RM demuxer that will gather slices into frames.
Well, using it it will require also RM10/20 decoder patch (and RM30/40 but
that's my work) and probably matroska demuxer patching to output raw frame
instead of current way (by slices).

BTW, looks like if high bit in frame length is set then slice is truncated
into two slices, but it is not handled anywhere (not this code, not old
code, probably not MPlayer demuxer). I.e. real frame length should have
length 1352 (in test.rmvb) or 0x561 but the actual raw value is 0xC561. 
-------------- next part --------------
Index: libavformat/rmdec.c
===================================================================
--- libavformat/rmdec.c	(revision 10505)
+++ libavformat/rmdec.c	(working copy)
@@ -432,6 +432,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 +597,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