[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