#include "rm.h"
#include "avstring.h"
-static void get_str(ByteIOContext *pb, char *buf, int buf_size)
+static inline void get_strl(ByteIOContext *pb, char *buf, int buf_size, int len)
{
- int len, i;
- char *q;
+ int i;
+ char *q, r;
- len = get_be16(pb);
q = buf;
for(i=0;i<len;i++) {
+ r = get_byte(pb);
if (i < buf_size - 1)
- *q++ = get_byte(pb);
+ *q++ = r;
}
- *q = '\0';
+ if (buf_size > 0) *q = '\0';
}
-static void get_str8(ByteIOContext *pb, char *buf, int buf_size)
+static void get_str16(ByteIOContext *pb, char *buf, int buf_size)
{
- int len, i;
- char *q;
+ get_strl(pb, buf, buf_size, get_be16(pb));
+}
- len = get_byte(pb);
- q = buf;
- for(i=0;i<len;i++) {
- if (i < buf_size - 1)
- *q++ = get_byte(pb);
- }
- *q = '\0';
+static void get_str8(ByteIOContext *pb, char *buf, int buf_size)
+{
+ get_strl(pb, buf, buf_size, get_byte(pb));
}
static int rm_read_audio_stream_info(AVFormatContext *s, AVStream *st,
st->codec->codec_type = CODEC_TYPE_AUDIO;
if (!strcmp(buf, "dnet")) {
st->codec->codec_id = CODEC_ID_AC3;
+ st->need_parsing = AVSTREAM_PARSE_FULL;
} else if (!strcmp(buf, "28_8")) {
st->codec->codec_id = CODEC_ID_RA_288;
st->codec->extradata_size= 0;
/* very old .ra format */
return rm_read_header_old(s, ap);
} else if (tag != MKTAG('.', 'R', 'M', 'F')) {
- return AVERROR_IO;
+ return AVERROR(EIO);
}
get_be32(pb); /* header size */
flags = get_be16(pb); /* flags */
break;
case MKTAG('C', 'O', 'N', 'T'):
- get_str(pb, s->title, sizeof(s->title));
- get_str(pb, s->author, sizeof(s->author));
- get_str(pb, s->copyright, sizeof(s->copyright));
- get_str(pb, s->comment, sizeof(s->comment));
+ get_str16(pb, s->title, sizeof(s->title));
+ get_str16(pb, s->author, sizeof(s->author));
+ get_str16(pb, s->copyright, sizeof(s->copyright));
+ get_str16(pb, s->comment, sizeof(s->comment));
break;
case MKTAG('M', 'D', 'P', 'R'):
st = av_new_stream(s, 0);
if (!rm->nb_packets && (flags & 4))
rm->nb_packets = 3600 * 25;
get_be32(pb); /* next data header */
+ rm->curpic_num = -1;
return 0;
fail:
for(i=0;i<s->nb_streams;i++) {
av_free(s->streams[i]);
}
- return AVERROR_IO;
+ return AVERROR(EIO);
}
static int get_num(ByteIOContext *pb, int *len)
n = get_be16(pb);
(*len)-=2;
+ n &= 0x7FFF;
if (n >= 0x4000) {
return n - 0x4000;
} else {
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;
for (y = 0; y < rm->sub_packet_h; y++)
for (x = 0; x < rm->sub_packet_h/2; x++)
if (get_buffer(pb, rm->audiobuf+x*2*rm->audio_framesize+y*rm->coded_framesize, rm->coded_framesize) <= 0)
- return AVERROR_IO;
+ return AVERROR(EIO);
rm->audio_stream_num = 0;
rm->audio_pkt_cnt = rm->sub_packet_h * rm->audio_framesize / st->codec->block_align - 1;
// Release first audio packet
len= av_get_packet(pb, pkt, len);
pkt->stream_index = 0;
if (len <= 0) {
- return AVERROR_IO;
+ return AVERROR(EIO);
}
pkt->size = len;
}
resync:
len=sync(s, ×tamp, &flags, &i, &pos);
if(len<0)
- return AVERROR_IO;
+ return AVERROR(EIO);
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(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) ||
RMContext *rm = s->priv_data;
av_free(rm->audiobuf);
+ av_free(rm->videobuf);
return 0;
}