X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Frmdec.c;h=5e3b3c760c7cae5f305d1306759d5e0602d448c3;hb=0e9602ef93255476d8f05b2a4f4ab70fdf1f22ff;hp=7f734162920349e3a1b2fc67ded47c0dd2360acf;hpb=6f3e0b21748b53fd7b0471196bbda1d7e561f4fe;p=ffmpeg diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c index 7f734162920..5e3b3c760c7 100644 --- a/libavformat/rmdec.c +++ b/libavformat/rmdec.c @@ -1,6 +1,6 @@ /* * "Real" compatible demuxer. - * Copyright (c) 2000, 2001 Fabrice Bellard. + * Copyright (c) 2000, 2001 Fabrice Bellard * * This file is part of FFmpeg. * @@ -18,62 +18,94 @@ * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "libavutil/avstring.h" +#include "libavutil/intreadwrite.h" #include "avformat.h" #include "rm.h" -#include "avstring.h" -static void get_str(ByteIOContext *pb, char *buf, int buf_size) +struct RMStream { + AVPacket pkt; ///< place to store merged video frame / reordered audio data + 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; + int64_t pktpos; ///< first slice position in file + /// Audio descrambling matrix parameters + int64_t audiotimestamp; ///< Audio packet timestamp + int sub_packet_cnt; // Subpacket counter, used while reading + int sub_packet_size, sub_packet_h, coded_framesize; ///< Descrambling parameters from container + int audio_framesize; /// Audio frame size from container + int sub_packet_lengths[16]; /// Length of each subpacket +}; + +typedef struct { + int nb_packets; + int old_format; + int current_stream; + int remaining_len; + int audio_stream_num; ///< Stream number for audio packets + int audio_pkt_cnt; ///< Output packet counter +} RMDemuxContext; + +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 0) *q = '\0'; } static void get_str8(ByteIOContext *pb, char *buf, int buf_size) { - int len, i; - char *q; + get_strl(pb, buf, buf_size, get_byte(pb)); +} - len = get_byte(pb); - q = buf; - for(i=0;ipb) : get_byte(s->pb); + get_strl(s->pb, buf, sizeof(buf), len); + av_metadata_set(&s->metadata, ff_rm_metadata[i], buf); } - *q = '\0'; } -static int rm_read_audio_stream_info(AVFormatContext *s, AVStream *st, - int read_all) +RMStream *ff_rm_alloc_rmstream (void) +{ + RMStream *rms = av_mallocz(sizeof(RMStream)); + rms->curpic_num = -1; + return rms; +} + +void ff_rm_free_rmstream (RMStream *rms) +{ + av_free_packet(&rms->pkt); +} + +static int rm_read_audio_stream_info(AVFormatContext *s, ByteIOContext *pb, + AVStream *st, RMStream *ast, int read_all) { - RMContext *rm = s->priv_data; - ByteIOContext *pb = &s->pb; char buf[256]; uint32_t version; - int i; /* ra type header */ version = get_be32(pb); /* version */ if (((version >> 16) & 0xff) == 3) { int64_t startpos = url_ftell(pb); - /* very old version */ - for(i = 0; i < 14; i++) - get_byte(pb); - get_str8(pb, s->title, sizeof(s->title)); - get_str8(pb, s->author, sizeof(s->author)); - get_str8(pb, s->copyright, sizeof(s->copyright)); - get_str8(pb, s->comment, sizeof(s->comment)); + url_fskip(pb, 14); + rm_read_metadata(s, 0); if ((startpos + (version & 0xffff)) >= url_ftell(pb) + 2) { - // fourcc (should always be "lpcJ") - get_byte(pb); - get_str8(pb, buf, sizeof(buf)); + // fourcc (should always be "lpcJ") + get_byte(pb); + get_str8(pb, buf, sizeof(buf)); } // Skip extra header crap (this should never happen) if ((startpos + (version & 0xffff)) > url_ftell(pb)) @@ -90,25 +122,23 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVStream *st, get_be16(pb); /* version2 */ get_be32(pb); /* header size */ flavor= get_be16(pb); /* add codec info / flavor */ - rm->coded_framesize = coded_framesize = get_be32(pb); /* coded frame size */ + ast->coded_framesize = coded_framesize = get_be32(pb); /* coded frame size */ get_be32(pb); /* ??? */ get_be32(pb); /* ??? */ get_be32(pb); /* ??? */ - rm->sub_packet_h = sub_packet_h = get_be16(pb); /* 1 */ + ast->sub_packet_h = sub_packet_h = get_be16(pb); /* 1 */ st->codec->block_align= get_be16(pb); /* frame size */ - rm->sub_packet_size = sub_packet_size = get_be16(pb); /* sub packet size */ + ast->sub_packet_size = sub_packet_size = get_be16(pb); /* sub packet size */ get_be16(pb); /* ??? */ if (((version >> 16) & 0xff) == 5) { - get_be16(pb); get_be16(pb); get_be16(pb); } + get_be16(pb); get_be16(pb); get_be16(pb); + } st->codec->sample_rate = get_be16(pb); get_be32(pb); st->codec->channels = get_be16(pb); if (((version >> 16) & 0xff) == 5) { get_be32(pb); - buf[0] = get_byte(pb); - buf[1] = get_byte(pb); - buf[2] = get_byte(pb); - buf[3] = get_byte(pb); + get_buffer(pb, buf, 4); buf[4] = 0; } else { get_str8(pb, buf, sizeof(buf)); /* desc */ @@ -117,20 +147,21 @@ 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; - rm->audio_framesize = st->codec->block_align; + ast->audio_framesize = st->codec->block_align; st->codec->block_align = coded_framesize; - if(rm->audio_framesize >= UINT_MAX / sub_packet_h){ - av_log(s, AV_LOG_ERROR, "rm->audio_framesize * sub_packet_h too large\n"); + if(ast->audio_framesize >= UINT_MAX / sub_packet_h){ + av_log(s, AV_LOG_ERROR, "ast->audio_framesize * sub_packet_h too large\n"); return -1; } - rm->audiobuf = av_malloc(rm->audio_framesize * sub_packet_h); - } else if ((!strcmp(buf, "cook")) || (!strcmp(buf, "atrc"))) { - int codecdata_length, i; + av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h); + } else if ((!strcmp(buf, "cook")) || (!strcmp(buf, "atrc")) || (!strcmp(buf, "sipr"))) { + int codecdata_length; get_be16(pb); get_byte(pb); if (((version >> 16) & 0xff) == 5) get_byte(pb); @@ -140,23 +171,28 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVStream *st, return -1; } + if(sub_packet_size <= 0){ + av_log(s, AV_LOG_ERROR, "sub_packet_size is invalid\n"); + return -1; + } + if (!strcmp(buf, "cook")) st->codec->codec_id = CODEC_ID_COOK; + else if (!strcmp(buf, "sipr")) st->codec->codec_id = CODEC_ID_SIPR; else st->codec->codec_id = CODEC_ID_ATRAC3; st->codec->extradata_size= codecdata_length; st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - for(i = 0; i < codecdata_length; i++) - ((uint8_t*)st->codec->extradata)[i] = get_byte(pb); - rm->audio_framesize = st->codec->block_align; - st->codec->block_align = rm->sub_packet_size; + get_buffer(pb, st->codec->extradata, st->codec->extradata_size); + ast->audio_framesize = st->codec->block_align; + st->codec->block_align = ast->sub_packet_size; - if(rm->audio_framesize >= UINT_MAX / sub_packet_h){ + if(ast->audio_framesize >= UINT_MAX / sub_packet_h){ av_log(s, AV_LOG_ERROR, "rm->audio_framesize * sub_packet_h too large\n"); return -1; } - rm->audiobuf = av_malloc(rm->audio_framesize * sub_packet_h); + av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h); } else if (!strcmp(buf, "raac") || !strcmp(buf, "racp")) { - int codecdata_length, i; + int codecdata_length; get_be16(pb); get_byte(pb); if (((version >> 16) & 0xff) == 5) get_byte(pb); @@ -170,8 +206,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVStream *st, st->codec->extradata_size = codecdata_length - 1; st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); get_byte(pb); - for(i = 0; i < st->codec->extradata_size; i++) - ((uint8_t*)st->codec->extradata)[i] = get_byte(pb); + get_buffer(pb, st->codec->extradata, st->codec->extradata_size); } } else { st->codec->codec_id = CODEC_ID_NONE; @@ -181,36 +216,103 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVStream *st, get_byte(pb); get_byte(pb); get_byte(pb); + rm_read_metadata(s, 0); + } + } + return 0; +} + +int +ff_rm_read_mdpr_codecdata (AVFormatContext *s, ByteIOContext *pb, + AVStream *st, RMStream *rst, int codec_data_size) +{ + unsigned int v; + int size; + int64_t codec_pos; + + av_set_pts_info(st, 64, 1, 1000); + codec_pos = url_ftell(pb); + v = get_be32(pb); + if (v == MKTAG(0xfd, 'a', 'r', '.')) { + /* ra type header */ + if (rm_read_audio_stream_info(s, pb, st, rst, 0)) + return -1; + } else { + int fps, fps2; + if (get_le32(pb) != MKTAG('V', 'I', 'D', 'O')) { + fail1: + av_log(st->codec, AV_LOG_ERROR, "Unsupported video codec\n"); + goto skip; + } + st->codec->codec_tag = get_le32(pb); +// av_log(s, AV_LOG_DEBUG, "%X %X\n", st->codec->codec_tag, MKTAG('R', 'V', '2', '0')); + if ( st->codec->codec_tag != MKTAG('R', 'V', '1', '0') + && st->codec->codec_tag != MKTAG('R', 'V', '2', '0') + && st->codec->codec_tag != MKTAG('R', 'V', '3', '0') + && st->codec->codec_tag != MKTAG('R', 'V', '4', '0') + && st->codec->codec_tag != MKTAG('R', 'V', 'T', 'R')) + goto fail1; + st->codec->width = get_be16(pb); + st->codec->height = get_be16(pb); + st->codec->time_base.num= 1; + fps= get_be16(pb); + st->codec->codec_type = CODEC_TYPE_VIDEO; + get_be32(pb); + fps2= get_be16(pb); + get_be16(pb); + + st->codec->extradata_size= codec_data_size - (url_ftell(pb) - codec_pos); - get_str8(pb, s->title, sizeof(s->title)); - get_str8(pb, s->author, sizeof(s->author)); - get_str8(pb, s->copyright, sizeof(s->copyright)); - get_str8(pb, s->comment, sizeof(s->comment)); + if(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codec->extradata_size){ + //check is redundant as get_buffer() will catch this + av_log(s, AV_LOG_ERROR, "st->codec->extradata_size too large\n"); + return -1; + } + st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + get_buffer(pb, st->codec->extradata, st->codec->extradata_size); + +// av_log(s, AV_LOG_DEBUG, "fps= %d fps2= %d\n", fps, fps2); + st->codec->time_base.den = fps * st->codec->time_base.num; + switch(((uint8_t*)st->codec->extradata)[4]>>4){ + case 1: st->codec->codec_id = CODEC_ID_RV10; break; + case 2: st->codec->codec_id = CODEC_ID_RV20; break; + case 3: st->codec->codec_id = CODEC_ID_RV30; break; + case 4: st->codec->codec_id = CODEC_ID_RV40; break; + default: goto fail1; } } + +skip: + /* skip codec info */ + size = url_ftell(pb) - codec_pos; + url_fskip(pb, codec_data_size - size); + return 0; } + static int rm_read_header_old(AVFormatContext *s, AVFormatParameters *ap) { - RMContext *rm = s->priv_data; + RMDemuxContext *rm = s->priv_data; AVStream *st; rm->old_format = 1; st = av_new_stream(s, 0); if (!st) return -1; - return rm_read_audio_stream_info(s, st, 1); + st->priv_data = ff_rm_alloc_rmstream(); + return rm_read_audio_stream_info(s, s->pb, st, st->priv_data, 1); } static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap) { - RMContext *rm = s->priv_data; + RMDemuxContext *rm = s->priv_data; AVStream *st; - ByteIOContext *pb = &s->pb; - unsigned int tag, v; - int tag_size, size, codec_data_size, i; - int64_t codec_pos; + ByteIOContext *pb = s->pb; + unsigned int tag; + int tag_size; unsigned int start_time, duration; char buf[128]; int flags = 0; @@ -230,7 +332,7 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap) for(;;) { if (url_feof(pb)) - goto fail; + return -1; tag = get_le32(pb); tag_size = get_be32(pb); get_be16(pb); @@ -244,7 +346,7 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap) tag_size); #endif if (tag_size < 10 && tag != MKTAG('D', 'A', 'T', 'A')) - goto fail; + return -1; switch(tag) { case MKTAG('P', 'R', 'O', 'P'): /* file header */ @@ -261,15 +363,12 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap) 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)); + rm_read_metadata(s, 1); break; case MKTAG('M', 'D', 'P', 'R'): st = av_new_stream(s, 0); if (!st) - goto fail; + return AVERROR(ENOMEM); st->id = get_be16(pb); get_be32(pb); /* max bit rate */ st->codec->bit_rate = get_be32(pb); /* bit rate */ @@ -282,63 +381,11 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap) st->duration = duration; get_str8(pb, buf, sizeof(buf)); /* desc */ get_str8(pb, buf, sizeof(buf)); /* mimetype */ - codec_data_size = get_be32(pb); - codec_pos = url_ftell(pb); st->codec->codec_type = CODEC_TYPE_DATA; - av_set_pts_info(st, 64, 1, 1000); - - v = get_be32(pb); - if (v == MKTAG(0xfd, 'a', 'r', '.')) { - /* ra type header */ - if (rm_read_audio_stream_info(s, st, 0)) - return -1; - } else { - int fps, fps2; - if (get_le32(pb) != MKTAG('V', 'I', 'D', 'O')) { - fail1: - av_log(st->codec, AV_LOG_ERROR, "Unsupported video codec\n"); - goto skip; - } - st->codec->codec_tag = get_le32(pb); -// av_log(NULL, AV_LOG_DEBUG, "%X %X\n", st->codec->codec_tag, MKTAG('R', 'V', '2', '0')); - if ( st->codec->codec_tag != MKTAG('R', 'V', '1', '0') - && st->codec->codec_tag != MKTAG('R', 'V', '2', '0') - && st->codec->codec_tag != MKTAG('R', 'V', '3', '0') - && st->codec->codec_tag != MKTAG('R', 'V', '4', '0')) - goto fail1; - st->codec->width = get_be16(pb); - st->codec->height = get_be16(pb); - st->codec->time_base.num= 1; - fps= get_be16(pb); - st->codec->codec_type = CODEC_TYPE_VIDEO; - get_be32(pb); - fps2= get_be16(pb); - get_be16(pb); - - st->codec->extradata_size= codec_data_size - (url_ftell(pb) - codec_pos); - - if(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codec->extradata_size){ - //check is redundant as get_buffer() will catch this - av_log(s, AV_LOG_ERROR, "st->codec->extradata_size too large\n"); - return -1; - } - st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - get_buffer(pb, st->codec->extradata, st->codec->extradata_size); - -// av_log(NULL, AV_LOG_DEBUG, "fps= %d fps2= %d\n", fps, fps2); - st->codec->time_base.den = fps * st->codec->time_base.num; - switch(((uint8_t*)st->codec->extradata)[4]>>4){ - case 1: st->codec->codec_id = CODEC_ID_RV10; break; - case 2: st->codec->codec_id = CODEC_ID_RV20; break; - case 3: st->codec->codec_id = CODEC_ID_RV30; break; - case 4: st->codec->codec_id = CODEC_ID_RV40; break; - default: goto fail1; - } - } -skip: - /* skip codec info */ - size = url_ftell(pb) - codec_pos; - url_fskip(pb, codec_data_size - size); + st->priv_data = ff_rm_alloc_rmstream(); + if (ff_rm_read_mdpr_codecdata(s, s->pb, st, st->priv_data, + get_be32(pb)) < 0) + return -1; break; case MKTAG('D', 'A', 'T', 'A'): goto header_end; @@ -354,12 +401,6 @@ skip: rm->nb_packets = 3600 * 25; get_be32(pb); /* next data header */ return 0; - - fail: - for(i=0;inb_streams;i++) { - av_free(s->streams[i]); - } - return AVERROR(EIO); } static int get_num(ByteIOContext *pb, int *len) @@ -368,6 +409,7 @@ static int get_num(ByteIOContext *pb, int *len) n = get_be16(pb); (*len)-=2; + n &= 0x7FFF; if (n >= 0x4000) { return n - 0x4000; } else { @@ -381,14 +423,14 @@ static int get_num(ByteIOContext *pb, int *len) #define RAW_PACKET_SIZE 1000 static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_index, int64_t *pos){ - RMContext *rm = s->priv_data; - ByteIOContext *pb = &s->pb; + RMDemuxContext *rm = s->priv_data; + ByteIOContext *pb = s->pb; int len, num, res, i; AVStream *st; uint32_t state=0xFFFFFFFF; while(!url_feof(pb)){ - *pos= url_ftell(pb); + *pos= url_ftell(pb) - 3; if(rm->remaining_len > 0){ num= rm->current_stream; len= rm->remaining_len; @@ -436,44 +478,252 @@ skip: return -1; } +static int rm_assemble_video_frame(AVFormatContext *s, ByteIOContext *pb, + RMDemuxContext *rm, RMStream *vst, + AVPacket *pkt, int len) +{ + int hdr, seq, pic_num, len2, pos; + int type; + + hdr = get_byte(pb); len--; + type = hdr >> 6; + + if(type != 3){ // not frame as a part of packet + seq = get_byte(pb); len--; + } + if(type != 1){ // not whole frame + len2 = get_num(pb, &len); + pos = get_num(pb, &len); + pic_num = get_byte(pb); len--; + } + if(len<0) + return -1; + rm->remaining_len = len; + if(type&1){ // frame, not slice + if(type == 3) // frame as a part of packet + len= len2; + if(rm->remaining_len < len) + return -1; + rm->remaining_len -= 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); + return 0; + } + //now we have to deal with single slice + + if((seq & 0x7F) == 1 || vst->curpic_num != pic_num){ + vst->slices = ((hdr & 0x3F) << 1) + 1; + vst->videobufsize = len2 + 8*vst->slices + 1; + av_free_packet(&vst->pkt); //FIXME this should be output. + if(av_new_packet(&vst->pkt, vst->videobufsize) < 0) + return AVERROR(ENOMEM); + vst->videobufpos = 8*vst->slices + 1; + vst->cur_slice = 0; + vst->curpic_num = pic_num; + vst->pktpos = url_ftell(pb); + } + if(type == 2) + len = FFMIN(len, pos); + + if(++vst->cur_slice > vst->slices) + return 1; + AV_WL32(vst->pkt.data - 7 + 8*vst->cur_slice, 1); + AV_WL32(vst->pkt.data - 3 + 8*vst->cur_slice, vst->videobufpos - 8*vst->slices - 1); + if(vst->videobufpos + len > vst->videobufsize) + return 1; + if (get_buffer(pb, vst->pkt.data + vst->videobufpos, len) != len) + return AVERROR(EIO); + vst->videobufpos += len; + rm->remaining_len-= len; + + if(type == 2 || (vst->videobufpos) == vst->videobufsize){ + vst->pkt.data[0] = vst->cur_slice-1; + *pkt= vst->pkt; + vst->pkt.data= NULL; + vst->pkt.size= 0; + if(vst->slices != vst->cur_slice) //FIXME find out how to set slices correct from the begin + memmove(pkt->data + 1 + 8*vst->cur_slice, pkt->data + 1 + 8*vst->slices, + vst->videobufpos - 1 - 8*vst->slices); + pkt->size = vst->videobufpos + 8*(vst->cur_slice - vst->slices); + pkt->pts = AV_NOPTS_VALUE; + pkt->pos = vst->pktpos; + return 0; + } + + return 1; +} + +static inline void +rm_ac3_swap_bytes (AVStream *st, AVPacket *pkt) +{ + uint8_t *ptr; + int j; + + if (st->codec->codec_id == CODEC_ID_AC3) { + ptr = pkt->data; + for (j=0;jsize;j+=2) { + FFSWAP(int, ptr[0], ptr[1]); + ptr += 2; + } + } +} + +int +ff_rm_parse_packet (AVFormatContext *s, ByteIOContext *pb, + AVStream *st, RMStream *ast, int len, AVPacket *pkt, + int *seq, int *flags, int64_t *timestamp) +{ + RMDemuxContext *rm = s->priv_data; + + if (st->codec->codec_type == CODEC_TYPE_VIDEO) { + rm->current_stream= st->id; + if(rm_assemble_video_frame(s, pb, rm, ast, pkt, len)) + return -1; //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) || + (st->codec->codec_id == CODEC_ID_ATRAC3) || + (st->codec->codec_id == CODEC_ID_SIPR)) { + int x; + int sps = ast->sub_packet_size; + int cfs = ast->coded_framesize; + int h = ast->sub_packet_h; + int y = ast->sub_packet_cnt; + int w = ast->audio_framesize; + + if (*flags & 2) + y = ast->sub_packet_cnt = 0; + if (!y) + ast->audiotimestamp = *timestamp; + + switch(st->codec->codec_id) { + case CODEC_ID_RA_288: + for (x = 0; x < h/2; x++) + get_buffer(pb, ast->pkt.data+x*2*w+y*cfs, cfs); + break; + case CODEC_ID_ATRAC3: + case CODEC_ID_COOK: + for (x = 0; x < w/sps; x++) + get_buffer(pb, ast->pkt.data+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), sps); + break; + } + + if (++(ast->sub_packet_cnt) < h) + return -1; + else { + ast->sub_packet_cnt = 0; + rm->audio_stream_num = st->index; + rm->audio_pkt_cnt = h * w / st->codec->block_align - 1; + // Release first audio packet + av_new_packet(pkt, st->codec->block_align); + memcpy(pkt->data, ast->pkt.data, st->codec->block_align); //FIXME avoid this + *timestamp = ast->audiotimestamp; + *flags = 2; // Mark first packet as keyframe + } + } else if (st->codec->codec_id == CODEC_ID_AAC) { + int x; + rm->audio_stream_num = st->index; + ast->sub_packet_cnt = (get_be16(pb) & 0xf0) >> 4; + if (ast->sub_packet_cnt) { + for (x = 0; x < ast->sub_packet_cnt; x++) + ast->sub_packet_lengths[x] = get_be16(pb); + // Release first audio packet + rm->audio_pkt_cnt = ast->sub_packet_cnt - 1; + av_get_packet(pb, pkt, ast->sub_packet_lengths[0]); + *flags = 2; // Mark first packet as keyframe + } + } else { + av_get_packet(pb, pkt, len); + rm_ac3_swap_bytes(st, pkt); + } + } else + av_get_packet(pb, pkt, len); + + if( (st->discard >= AVDISCARD_NONKEY && !(*flags&2)) + || st->discard >= AVDISCARD_ALL){ + av_free_packet(pkt); + return -1; + } + + pkt->stream_index = st->index; + +#if 0 + if (st->codec->codec_type == CODEC_TYPE_VIDEO) { + if(st->codec->codec_id == CODEC_ID_RV20){ + int seq= 128*(pkt->data[2]&0x7F) + (pkt->data[3]>>1); + av_log(s, AV_LOG_DEBUG, "%d %"PRId64" %d\n", *timestamp, *timestamp*512LL/25, seq); + + seq |= (*timestamp&~0x3FFF); + if(seq - *timestamp > 0x2000) seq -= 0x4000; + if(seq - *timestamp < -0x2000) seq += 0x4000; + } + } +#endif + + pkt->pts= *timestamp; + if (*flags & 2) + pkt->flags |= PKT_FLAG_KEY; + + return st->codec->codec_type == CODEC_TYPE_AUDIO ? rm->audio_pkt_cnt : 0; +} + +int +ff_rm_retrieve_cache (AVFormatContext *s, ByteIOContext *pb, + AVStream *st, RMStream *ast, AVPacket *pkt) +{ + RMDemuxContext *rm = s->priv_data; + + assert (rm->audio_pkt_cnt > 0); + + if (st->codec->codec_id == CODEC_ID_AAC) + av_get_packet(pb, pkt, ast->sub_packet_lengths[ast->sub_packet_cnt - rm->audio_pkt_cnt]); + else { + av_new_packet(pkt, st->codec->block_align); + memcpy(pkt->data, ast->pkt.data + st->codec->block_align * //FIXME avoid this + (ast->sub_packet_h * ast->audio_framesize / st->codec->block_align - rm->audio_pkt_cnt), + st->codec->block_align); + } + rm->audio_pkt_cnt--; + pkt->flags = 0; + pkt->stream_index = st->index; + + return rm->audio_pkt_cnt; +} + static int rm_read_packet(AVFormatContext *s, AVPacket *pkt) { - RMContext *rm = s->priv_data; - ByteIOContext *pb = &s->pb; + RMDemuxContext *rm = s->priv_data; + ByteIOContext *pb = s->pb; AVStream *st; - int i, len, j; + int i, len; int64_t timestamp, pos; - uint8_t *ptr; int flags; if (rm->audio_pkt_cnt) { // If there are queued audio packet return them first st = s->streams[rm->audio_stream_num]; - if (st->codec->codec_id == CODEC_ID_AAC) - av_get_packet(pb, pkt, rm->sub_packet_lengths[rm->sub_packet_cnt - rm->audio_pkt_cnt]); - else { - av_new_packet(pkt, st->codec->block_align); - memcpy(pkt->data, rm->audiobuf + st->codec->block_align * - (rm->sub_packet_h * rm->audio_framesize / st->codec->block_align - rm->audio_pkt_cnt), - st->codec->block_align); - } - rm->audio_pkt_cnt--; - pkt->flags = 0; - pkt->stream_index = rm->audio_stream_num; + ff_rm_retrieve_cache(s, s->pb, st, st->priv_data, pkt); } else if (rm->old_format) { + RMStream *ast; + st = s->streams[0]; + ast = st->priv_data; if (st->codec->codec_id == CODEC_ID_RA_288) { int x, y; - 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) + for (y = 0; y < ast->sub_packet_h; y++) + for (x = 0; x < ast->sub_packet_h/2; x++) + if (get_buffer(pb, ast->pkt.data+x*2*ast->audio_framesize+y*ast->coded_framesize, ast->coded_framesize) <= 0) return AVERROR(EIO); rm->audio_stream_num = 0; - rm->audio_pkt_cnt = rm->sub_packet_h * rm->audio_framesize / st->codec->block_align - 1; + rm->audio_pkt_cnt = ast->sub_packet_h * ast->audio_framesize / st->codec->block_align - 1; // Release first audio packet av_new_packet(pkt, st->codec->block_align); - memcpy(pkt->data, rm->audiobuf, st->codec->block_align); + memcpy(pkt->data, ast->pkt.data, st->codec->block_align); //FIXME avoid this pkt->flags |= PKT_FLAG_KEY; // Mark first packet as keyframe pkt->stream_index = 0; } else { @@ -486,6 +736,7 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt) } pkt->size = len; } + rm_ac3_swap_bytes(st, pkt); } else { int seq=1; resync: @@ -494,133 +745,24 @@ resync: 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 && len2remaining_len-= len; - av_get_packet(pb, pkt, len); - - } 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) || - (st->codec->codec_id == CODEC_ID_ATRAC3)) { - int x; - int sps = rm->sub_packet_size; - int cfs = rm->coded_framesize; - int h = rm->sub_packet_h; - int y = rm->sub_packet_cnt; - int w = rm->audio_framesize; - - if (flags & 2) - y = rm->sub_packet_cnt = 0; - if (!y) - rm->audiotimestamp = timestamp; - - switch(st->codec->codec_id) { - case CODEC_ID_RA_288: - for (x = 0; x < h/2; x++) - get_buffer(pb, rm->audiobuf+x*2*w+y*cfs, cfs); - break; - case CODEC_ID_ATRAC3: - case CODEC_ID_COOK: - for (x = 0; x < w/sps; x++) - get_buffer(pb, rm->audiobuf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), sps); - break; - } - - if (++(rm->sub_packet_cnt) < h) - goto resync; - else { - rm->sub_packet_cnt = 0; - rm->audio_stream_num = i; - rm->audio_pkt_cnt = h * w / st->codec->block_align - 1; - // Release first audio packet - av_new_packet(pkt, st->codec->block_align); - memcpy(pkt->data, rm->audiobuf, st->codec->block_align); - timestamp = rm->audiotimestamp; - flags = 2; // Mark first packet as keyframe - } - } else if (st->codec->codec_id == CODEC_ID_AAC) { - int x; - rm->audio_stream_num = i; - rm->sub_packet_cnt = (get_be16(pb) & 0xf0) >> 4; - if (rm->sub_packet_cnt) { - for (x = 0; x < rm->sub_packet_cnt; x++) - rm->sub_packet_lengths[x] = get_be16(pb); - // Release first audio packet - rm->audio_pkt_cnt = rm->sub_packet_cnt - 1; - av_get_packet(pb, pkt, rm->sub_packet_lengths[0]); - flags = 2; // Mark first packet as keyframe - } - } else - av_get_packet(pb, pkt, len); - - } else - av_get_packet(pb, pkt, len); - - if( (st->discard >= AVDISCARD_NONKEY && !(flags&2)) - || st->discard >= AVDISCARD_ALL){ - av_free_packet(pkt); + if (ff_rm_parse_packet (s, s->pb, st, st->priv_data, len, pkt, + &seq, &flags, ×tamp) < 0) goto resync; - } - - pkt->stream_index = i; - -#if 0 - if (st->codec->codec_type == CODEC_TYPE_VIDEO) { - if(st->codec->codec_id == CODEC_ID_RV20){ - int seq= 128*(pkt->data[2]&0x7F) + (pkt->data[3]>>1); - av_log(NULL, AV_LOG_DEBUG, "%d %"PRId64" %d\n", timestamp, timestamp*512LL/25, seq); - seq |= (timestamp&~0x3FFF); - if(seq - timestamp > 0x2000) seq -= 0x4000; - if(seq - timestamp < -0x2000) seq += 0x4000; - } - } -#endif - pkt->pts= timestamp; - if(flags&2){ - pkt->flags |= PKT_FLAG_KEY; - if((seq&0x7F) == 1) - av_add_index_entry(st, pos, timestamp, 0, 0, AVINDEX_KEYFRAME); - } + if((flags&2) && (seq&0x7F) == 1) + av_add_index_entry(st, pos, timestamp, 0, 0, AVINDEX_KEYFRAME); } - /* for AC3, needs to swap bytes */ - if (st->codec->codec_id == CODEC_ID_AC3) { - ptr = pkt->data; - for(j=0;jsize;j+=2) { - FFSWAP(int, ptr[0], ptr[1]); - ptr += 2; - } - } return 0; } static int rm_read_close(AVFormatContext *s) { - RMContext *rm = s->priv_data; + int i; + + for (i=0;inb_streams;i++) + ff_rm_free_rmstream(s->streams[i]->priv_data); - av_free(rm->audiobuf); return 0; } @@ -640,7 +782,7 @@ static int rm_probe(AVProbeData *p) static int64_t rm_read_dts(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit) { - RMContext *rm = s->priv_data; + RMDemuxContext *rm = s->priv_data; int64_t pos, dts; int stream_index2, flags, len, h; @@ -649,7 +791,7 @@ static int64_t rm_read_dts(AVFormatContext *s, int stream_index, if(rm->old_format) return AV_NOPTS_VALUE; - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); rm->remaining_len=0; for(;;){ int seq=1; @@ -661,9 +803,9 @@ static int64_t rm_read_dts(AVFormatContext *s, int stream_index, st = s->streams[stream_index2]; if (st->codec->codec_type == CODEC_TYPE_VIDEO) { - h= get_byte(&s->pb); len--; + h= get_byte(s->pb); len--; if(!(h & 0x40)){ - seq = get_byte(&s->pb); len--; + seq = get_byte(s->pb); len--; } } @@ -674,7 +816,7 @@ static int64_t rm_read_dts(AVFormatContext *s, int stream_index, break; } - url_fskip(&s->pb, len); + url_fskip(s->pb, len); } *ppos = pos; return dts; @@ -682,8 +824,8 @@ static int64_t rm_read_dts(AVFormatContext *s, int stream_index, AVInputFormat rm_demuxer = { "rm", - "rm format", - sizeof(RMContext), + NULL_IF_CONFIG_SMALL("RealMedia format"), + sizeof(RMDemuxContext), rm_probe, rm_read_header, rm_read_packet, @@ -691,3 +833,13 @@ AVInputFormat rm_demuxer = { NULL, rm_read_dts, }; + +AVInputFormat rdt_demuxer = { + "rdt", + NULL_IF_CONFIG_SMALL("RDT demuxer"), + sizeof(RMDemuxContext), + NULL, + NULL, + NULL, + rm_read_close, +};