X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Frmdec.c;h=436a7e08f2a593735d50e15ba38ed34c5f8eede1;hb=ca51d86c96675aabf3f05c9052593b4bc8eb927f;hp=f3c3019dec2abe0372a4944b1049c0f7f3626f8e;hpb=34bddc39b4c3af9472c99a9835af4dc12160f48e;p=ffmpeg diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c index f3c3019dec2..436a7e08f2a 100644 --- a/libavformat/rmdec.c +++ b/libavformat/rmdec.c @@ -22,6 +22,7 @@ #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" #include "avformat.h" +#include "riff.h" #include "rm.h" struct RMStream { @@ -61,7 +62,7 @@ static const unsigned char sipr_swaps[38][2] = { { 67, 83 }, { 77, 80 } }; -static const unsigned char sipr_subpk_size[4] = { 29, 19, 37, 20 }; +const unsigned char ff_sipr_subpk_size[4] = { 29, 19, 37, 20 }; static inline void get_strl(ByteIOContext *pb, char *buf, int buf_size, int len) { @@ -82,6 +83,20 @@ static void get_str8(ByteIOContext *pb, char *buf, int buf_size) get_strl(pb, buf, buf_size, get_byte(pb)); } +static int rm_read_extradata(ByteIOContext *pb, AVCodecContext *avctx, unsigned size) +{ + if (size >= 1<<24) + return -1; + avctx->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) + return AVERROR(ENOMEM); + avctx->extradata_size = get_buffer(pb, avctx->extradata, size); + memset(avctx->extradata + avctx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + if (avctx->extradata_size != size) + return AVERROR(EIO); + return 0; +} + static void rm_read_metadata(AVFormatContext *s, int wide) { char buf[1024]; @@ -89,7 +104,7 @@ static void rm_read_metadata(AVFormatContext *s, int wide) 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); + av_metadata_set2(&s->metadata, ff_rm_metadata[i], buf, 0); } } @@ -110,28 +125,32 @@ static int rm_read_audio_stream_info(AVFormatContext *s, ByteIOContext *pb, { char buf[256]; uint32_t version; + int ret; /* ra type header */ - version = get_be32(pb); /* version */ - if (((version >> 16) & 0xff) == 3) { + version = get_be16(pb); /* version */ + if (version == 3) { + int header_size = get_be16(pb); int64_t startpos = url_ftell(pb); url_fskip(pb, 14); rm_read_metadata(s, 0); - if ((startpos + (version & 0xffff)) >= url_ftell(pb) + 2) { + if ((startpos + header_size) >= url_ftell(pb) + 2) { // 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)) - url_fskip(pb, (version & 0xffff) + startpos - url_ftell(pb)); + if ((startpos + header_size) > url_ftell(pb)) + url_fskip(pb, header_size + startpos - url_ftell(pb)); st->codec->sample_rate = 8000; st->codec->channels = 1; - st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_RA_144; } else { int flavor, sub_packet_h, coded_framesize, sub_packet_size; + int codecdata_length; /* old version (4) */ + url_fskip(pb, 2); /* unused */ get_be32(pb); /* .ra4 */ get_be32(pb); /* data size */ get_be16(pb); /* version2 */ @@ -145,13 +164,13 @@ static int rm_read_audio_stream_info(AVFormatContext *s, ByteIOContext *pb, st->codec->block_align= get_be16(pb); /* frame size */ ast->sub_packet_size = sub_packet_size = get_be16(pb); /* sub packet size */ get_be16(pb); /* ??? */ - if (((version >> 16) & 0xff) == 5) { + if (version == 5) { 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) { + if (version == 5) { get_be32(pb); get_buffer(pb, buf, 4); buf[4] = 0; @@ -159,12 +178,15 @@ static int rm_read_audio_stream_info(AVFormatContext *s, ByteIOContext *pb, get_str8(pb, buf, sizeof(buf)); /* desc */ get_str8(pb, buf, sizeof(buf)); /* desc */ } - st->codec->codec_type = CODEC_TYPE_AUDIO; - if (!strcmp(buf, "dnet")) { - st->codec->codec_id = CODEC_ID_AC3; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_tag = AV_RL32(buf); + st->codec->codec_id = ff_codec_get_id(ff_rm_codec_tags, + st->codec->codec_tag); + switch (st->codec->codec_id) { + case CODEC_ID_AC3: st->need_parsing = AVSTREAM_PARSE_FULL; - } else if (!strcmp(buf, "28_8")) { - st->codec->codec_id = CODEC_ID_RA_288; + break; + case CODEC_ID_RA_288: st->codec->extradata_size= 0; ast->audio_framesize = st->codec->block_align; st->codec->block_align = coded_framesize; @@ -175,10 +197,12 @@ static int rm_read_audio_stream_info(AVFormatContext *s, ByteIOContext *pb, } 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; + break; + case CODEC_ID_COOK: + case CODEC_ID_ATRAC3: + case CODEC_ID_SIPR: get_be16(pb); get_byte(pb); - if (((version >> 16) & 0xff) == 5) + if (version == 5) get_byte(pb); codecdata_length = get_be32(pb); if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ @@ -186,10 +210,6 @@ static int rm_read_audio_stream_info(AVFormatContext *s, ByteIOContext *pb, 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; - ast->audio_framesize = st->codec->block_align; if (st->codec->codec_id == CODEC_ID_SIPR) { if (flavor > 3) { @@ -197,7 +217,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, ByteIOContext *pb, flavor); return -1; } - st->codec->block_align = sipr_subpk_size[flavor]; + st->codec->block_align = ff_sipr_subpk_size[flavor]; } else { if(sub_packet_size <= 0){ av_log(s, AV_LOG_ERROR, "sub_packet_size is invalid\n"); @@ -205,9 +225,8 @@ static int rm_read_audio_stream_info(AVFormatContext *s, ByteIOContext *pb, } st->codec->block_align = ast->sub_packet_size; } - st->codec->extradata_size= codecdata_length; - st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - get_buffer(pb, st->codec->extradata, st->codec->extradata_size); + if ((ret = rm_read_extradata(pb, st->codec, codecdata_length)) < 0) + return ret; if(ast->audio_framesize >= UINT_MAX / sub_packet_h){ av_log(s, AV_LOG_ERROR, "rm->audio_framesize * sub_packet_h too large\n"); @@ -215,25 +234,23 @@ static int rm_read_audio_stream_info(AVFormatContext *s, ByteIOContext *pb, } av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h); - } else if (!strcmp(buf, "raac") || !strcmp(buf, "racp")) { - int codecdata_length; + break; + case CODEC_ID_AAC: get_be16(pb); get_byte(pb); - if (((version >> 16) & 0xff) == 5) + if (version == 5) get_byte(pb); - st->codec->codec_id = CODEC_ID_AAC; codecdata_length = get_be32(pb); if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); return -1; } if (codecdata_length >= 1) { - st->codec->extradata_size = codecdata_length - 1; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); get_byte(pb); - get_buffer(pb, st->codec->extradata, st->codec->extradata_size); + if ((ret = rm_read_extradata(pb, st->codec, codecdata_length - 1)) < 0) + return ret; } - } else { - st->codec->codec_id = CODEC_ID_NONE; + break; + default: av_strlcpy(st->codec->codec_name, buf, sizeof(st->codec->codec_name)); } if (read_all) { @@ -253,6 +270,7 @@ ff_rm_read_mdpr_codecdata (AVFormatContext *s, ByteIOContext *pb, unsigned int v; int size; int64_t codec_pos; + int ret; av_set_pts_info(st, 64, 1, 1000); codec_pos = url_ftell(pb); @@ -269,42 +287,34 @@ ff_rm_read_mdpr_codecdata (AVFormatContext *s, ByteIOContext *pb, goto skip; } st->codec->codec_tag = get_le32(pb); + st->codec->codec_id = ff_codec_get_id(ff_rm_codec_tags, + st->codec->codec_tag); // 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')) + if (st->codec->codec_id == CODEC_ID_NONE) 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; + st->codec->codec_type = AVMEDIA_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); - if (!st->codec->extradata) - return AVERROR(ENOMEM); - get_buffer(pb, st->codec->extradata, st->codec->extradata_size); + if ((ret = rm_read_extradata(pb, st->codec, codec_data_size - (url_ftell(pb) - codec_pos))) < 0) + return ret; // 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){ + //XXX: do we really need that? + switch(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; + default: + av_log(st->codec, AV_LOG_ERROR, "extra:%02X %02X %02X %02X %02X\n", st->codec->extradata[0], st->codec->extradata[1], st->codec->extradata[2], st->codec->extradata[3], st->codec->extradata[4]); + goto fail1; } } @@ -449,7 +459,7 @@ 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 */ - st->codec->codec_type = CODEC_TYPE_DATA; + st->codec->codec_type = AVMEDIA_TYPE_DATA; st->priv_data = ff_rm_alloc_rmstream(); if (ff_rm_read_mdpr_codecdata(s, s->pb, st, st->priv_data, get_be32(pb)) < 0) @@ -471,7 +481,8 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap) if (!data_off) data_off = url_ftell(pb) - 18; - if (indx_off && url_fseek(pb, indx_off, SEEK_SET) >= 0) { + if (indx_off && !url_is_streamed(pb) && !(s->flags & AVFMT_FLAG_IGNIDX) && + url_fseek(pb, indx_off, SEEK_SET) >= 0) { rm_read_index(s); url_fseek(pb, data_off + 18, SEEK_SET); } @@ -505,7 +516,7 @@ static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_ uint32_t state=0xFFFFFFFF; while(!url_feof(pb)){ - int len, num, res, i; + int len, num, i; *pos= url_ftell(pb) - 3; if(rm->remaining_len > 0){ num= rm->current_stream; @@ -532,6 +543,9 @@ static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_ if(len<0) continue; goto skip; + } else if (state == MKBETAG('D','A','T','A')) { + av_log(s, AV_LOG_WARNING, + "DATA tag in middle of chunk, file may be broken.\n"); } if(state > (unsigned)0xFFFF || state <= 12) @@ -541,7 +555,7 @@ static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_ num = get_be16(pb); *timestamp = get_be32(pb); - res= get_byte(pb); /* reserved */ + get_byte(pb); /* reserved */ *flags = get_byte(pb); /* flags */ } for(i=0;inb_streams;i++) { @@ -637,6 +651,7 @@ static int rm_assemble_video_frame(AVFormatContext *s, ByteIOContext *pb, pkt->size = vst->videobufpos + 8*(vst->cur_slice - vst->slices); pkt->pts = AV_NOPTS_VALUE; pkt->pos = vst->pktpos; + vst->slices = 0; return 0; } @@ -662,16 +677,14 @@ rm_ac3_swap_bytes (AVStream *st, AVPacket *pkt) * Perform 4-bit block reordering for SIPR data. * @todo This can be optimized, e.g. use memcpy() if data blocks are aligned */ -static void -rm_reorder_sipr_data (RMStream *ast) +void ff_rm_reorder_sipr_data(uint8_t *buf, int sub_packet_h, int framesize) { - int n, bs = ast->sub_packet_h * ast->audio_framesize * 2 / 96; // nibbles per subpacket + int n, bs = sub_packet_h * framesize * 2 / 96; // nibbles per subpacket for (n = 0; n < 38; n++) { int j; int i = bs * sipr_swaps[n][0]; int o = bs * sipr_swaps[n][1]; - uint8_t *buf = ast->pkt.data; /* swap 4bit-nibbles of block 'i' with 'o' */ for (j = 0; j < bs; j++, i++, o++) { @@ -693,11 +706,11 @@ ff_rm_parse_packet (AVFormatContext *s, ByteIOContext *pb, { RMDemuxContext *rm = s->priv_data; - if (st->codec->codec_type == CODEC_TYPE_VIDEO) { + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { rm->current_stream= st->id; if(rm_assemble_video_frame(s, pb, rm, ast, pkt, len, seq)) return -1; //got partial frame - } else if (st->codec->codec_type == CODEC_TYPE_AUDIO) { + } else if (st->codec->codec_type == AVMEDIA_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) || @@ -732,7 +745,7 @@ ff_rm_parse_packet (AVFormatContext *s, ByteIOContext *pb, if (++(ast->sub_packet_cnt) < h) return -1; if (st->codec->codec_id == CODEC_ID_SIPR) - rm_reorder_sipr_data(ast); + ff_rm_reorder_sipr_data(ast->pkt.data, h, w); ast->sub_packet_cnt = 0; rm->audio_stream_num = st->index; @@ -758,7 +771,7 @@ ff_rm_parse_packet (AVFormatContext *s, ByteIOContext *pb, pkt->stream_index = st->index; #if 0 - if (st->codec->codec_type == CODEC_TYPE_VIDEO) { + if (st->codec->codec_type == AVMEDIA_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); @@ -772,9 +785,9 @@ ff_rm_parse_packet (AVFormatContext *s, ByteIOContext *pb, pkt->pts= timestamp; if (flags & 2) - pkt->flags |= PKT_FLAG_KEY; + pkt->flags |= AV_PKT_FLAG_KEY; - return st->codec->codec_type == CODEC_TYPE_AUDIO ? rm->audio_pkt_cnt : 0; + return st->codec->codec_type == AVMEDIA_TYPE_AUDIO ? rm->audio_pkt_cnt : 0; } int @@ -796,7 +809,7 @@ ff_rm_retrieve_cache (AVFormatContext *s, ByteIOContext *pb, rm->audio_pkt_cnt--; if ((pkt->pts = ast->audiotimestamp) != AV_NOPTS_VALUE) { ast->audiotimestamp = AV_NOPTS_VALUE; - pkt->flags = PKT_FLAG_KEY; + pkt->flags = AV_PKT_FLAG_KEY; } else pkt->flags = 0; pkt->stream_index = st->index; @@ -810,13 +823,14 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt) AVStream *st; int i, len, res, seq = 1; int64_t timestamp, pos; - int old_flags, flags; + int flags; for (;;) { if (rm->audio_pkt_cnt) { // If there are queued audio packet return them first st = s->streams[rm->audio_stream_num]; ff_rm_retrieve_cache(s, s->pb, st, st->priv_data, pkt); + flags = 0; } else { if (rm->old_format) { RMStream *ast; @@ -827,6 +841,7 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt) len = !ast->audio_framesize ? RAW_PACKET_SIZE : ast->coded_framesize * ast->sub_packet_h / 2; flags = (seq++ == 1) ? 2 : 0; + pos = url_ftell(s->pb); } else { len=sync(s, ×tamp, &flags, &i, &pos); if (len > 0) @@ -836,10 +851,9 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt) if(len<0 || url_feof(s->pb)) return AVERROR(EIO); - old_flags = flags; res = ff_rm_parse_packet (s, s->pb, st, st->priv_data, len, pkt, &seq, flags, timestamp); - if((old_flags&2) && (seq&0x7F) == 1) + if((flags&2) && (seq&0x7F) == 1) av_add_index_entry(st, pos, timestamp, 0, 0, AVINDEX_KEYFRAME); if (res) continue; @@ -901,7 +915,7 @@ static int64_t rm_read_dts(AVFormatContext *s, int stream_index, return AV_NOPTS_VALUE; st = s->streams[stream_index2]; - if (st->codec->codec_type == CODEC_TYPE_VIDEO) { + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { h= get_byte(s->pb); len--; if(!(h & 0x40)){ seq = get_byte(s->pb); len--;