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

Roberto Togni rxt
Sun Oct 21 15:59:52 CEST 2007


On Sat, 20 Oct 2007 16:14:08 +0300
Kostya <kostya.shishkov at gmail.com> wrote:

> 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. 

> 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?

Maybe reinint also on pic_num change.

> +        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);

Can this write out of the buffer in case of errors? I'm thinking about
a case where cur_slice is big and len2 and rm->slices are small.
Also if a slice is missing the slice table will have some
uninitialized values.

> +    get_buffer(pb, rm->videobuf + 1 + 8*rm->slices + pos, len);

This could be dangerous, since the rm->slices used here is not the same
used to allocate the buffer. Also pos could be anything.

> +    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;
> +}
> +

Maybe the easiest solution is to use always the slice number from the
first slice and just use a counter for the cur_slice number (ignoring
the value from the header) and write slices in sequence (ignoring pos).

>  static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
[...]

Can you test the attached patch? I only tested with rv10/20. This
should address all the issues.

For all the rest patch ok, and thanks for taking care of this.

Ciao,
 Roberto

-- 
Better is the enemy of good enough.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: slicedmx.diff
Type: text/x-patch
Size: 5393 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20071021/09c82a01/attachment.bin>



More information about the ffmpeg-devel mailing list