From 383b123ed37df4ff99010646f1fa5911ff1428cc Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Sun, 21 Oct 2007 17:17:28 +0000 Subject: [PATCH] Demux full frames instead of sliced for RealVideo. Some changes by Roberto Togni and blessed by him on IRC. Originally committed as revision 10823 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/rm.h | 5 ++ libavformat/rmdec.c | 113 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 93 insertions(+), 25 deletions(-) diff --git a/libavformat/rm.h b/libavformat/rm.h index 553fbccc42..a9673f0648 100644 --- a/libavformat/rm.h +++ b/libavformat/rm.h @@ -46,6 +46,11 @@ typedef struct { 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 videobufpos; ///< position for the next slice in the video buffer + int curpic_num; ///< picture number of current frame + int cur_slice, slices; /// Audio descrambling matrix parameters uint8_t *audiobuf; ///< place to store reordered audio data int64_t audiotimestamp; ///< Audio packet timestamp diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c index bddc01144b..60778125bf 100644 --- a/libavformat/rmdec.c +++ b/libavformat/rmdec.c @@ -350,6 +350,7 @@ skip: if (!rm->nb_packets && (flags & 4)) rm->nb_packets = 3600 * 25; get_be32(pb); /* next data header */ + rm->curpic_num = -1; return 0; fail: @@ -365,6 +366,7 @@ static int get_num(ByteIOContext *pb, int *len) n = get_be16(pb); (*len)-=2; + n &= 0x7FFF; if (n >= 0x4000) { return n - 0x4000; } else { @@ -433,6 +435,89 @@ skip: 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 + + if((seq & 0x7F) == 1 || rm->curpic_num != pic_num){ + rm->slices = ((hdr & 0x3F) << 1) + 1; + ssize = len2 + 8*rm->slices + 1; + rm->videobuf = av_realloc(rm->videobuf, ssize); + rm->videobufsize = ssize; + rm->videobufpos = 8*rm->slices + 1; + rm->cur_slice = 0; + rm->curpic_num = pic_num; + } + if(type == 2){ + len = FFMIN(len, pos); + pos = len2 - pos; + } + + if(++rm->cur_slice > rm->cur_slice) + return 1; + AV_WL32(rm->videobuf - 7 + 8*rm->cur_slice, 1); + AV_WL32(rm->videobuf - 3 + 8*rm->cur_slice, rm->videobufpos - 8*rm->slices - 1); + if(rm->videobufpos + len > rm->videobufsize) + return 1; + if (get_buffer(pb, rm->videobuf + rm->videobufpos, len) != len) + return AVERROR(EIO); + rm->videobufpos += len, + rm->remaining_len-= len; + + if(type == 2 || (rm->videobufpos) == 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 +577,9 @@ resync: 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 && len2remaining_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 +682,7 @@ static int rm_read_close(AVFormatContext *s) RMContext *rm = s->priv_data; av_free(rm->audiobuf); + av_free(rm->videobuf); return 0; }