summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKostya Shishkov <kostya.shishkov@gmail.com>2007-10-21 17:17:28 +0000
committerKostya Shishkov <kostya.shishkov@gmail.com>2007-10-21 17:17:28 +0000
commit383b123ed37df4ff99010646f1fa5911ff1428cc (patch)
treee14ddcd00f6ebe7a9ba01ba4e99f7eaa9e08b342
parent46fb896b9dde91be9646a0e7f7637487ae6236b8 (diff)
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
-rw-r--r--libavformat/rm.h5
-rw-r--r--libavformat/rmdec.c113
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 && 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 +682,7 @@ static int rm_read_close(AVFormatContext *s)
RMContext *rm = s->priv_data;
av_free(rm->audiobuf);
+ av_free(rm->videobuf);
return 0;
}