diff options
Diffstat (limited to 'contrib/ffmpeg/libavformat/asf.c')
-rw-r--r-- | contrib/ffmpeg/libavformat/asf.c | 182 |
1 files changed, 124 insertions, 58 deletions
diff --git a/contrib/ffmpeg/libavformat/asf.c b/contrib/ffmpeg/libavformat/asf.c index 498f6e79e..30330c535 100644 --- a/contrib/ffmpeg/libavformat/asf.c +++ b/contrib/ffmpeg/libavformat/asf.c @@ -23,6 +23,9 @@ #include "mpegaudio.h" #include "asf.h" #include "common.h" +#include "asfcrypt.h" + +extern void ff_mms_set_stream_selection(URLContext *h, AVFormatContext *format); #undef NDEBUG #include <assert.h> @@ -84,7 +87,7 @@ static void print_guid(const GUID *g) static void get_guid(ByteIOContext *s, GUID *g) { assert(sizeof(*g) == 16); - get_buffer(s, g, sizeof(*g)); + get_buffer(s, *g, sizeof(*g)); } #if 0 @@ -119,9 +122,6 @@ static void get_str16_nolen(ByteIOContext *pb, int len, char *buf, int buf_size) static int asf_probe(AVProbeData *pd) { /* check file header */ - if (pd->buf_size <= 32) - return 0; - if (!memcmp(pd->buf, &asf_header, sizeof(GUID))) return AVPROBE_SCORE_MAX; else @@ -142,14 +142,16 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) { ASFContext *asf = s->priv_data; GUID g; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVStream *st; ASFStream *asf_st; int size, i; int64_t gsize; AVRational dar[128]; + uint32_t bitrate[128]; memset(dar, 0, sizeof(dar)); + memset(bitrate, 0, sizeof(bitrate)); get_guid(pb, &g); if (memcmp(&g, &asf_header, sizeof(GUID))) @@ -197,8 +199,8 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) int type, type_specific_size, sizeX; uint64_t total_size; unsigned int tag1; - int64_t pos1, pos2; - int test_for_ext_stream_audio; + int64_t pos1, pos2, start_time; + int test_for_ext_stream_audio, is_dvr_ms_audio=0; pos1 = url_ftell(pb); @@ -210,10 +212,11 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) if (!asf_st) goto fail; st->priv_data = asf_st; - st->start_time = asf->hdr.preroll; + start_time = asf->hdr.preroll; + if(!(asf->hdr.flags & 0x01)) { // if we aren't streaming... st->duration = asf->hdr.send_time / - (10000000 / 1000) - st->start_time; + (10000000 / 1000) - start_time; } get_guid(pb, &g); @@ -244,6 +247,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) get_guid(pb, &g); if (!memcmp(&g, &ext_stream_audio_stream, sizeof(GUID))) { type = CODEC_TYPE_AUDIO; + is_dvr_ms_audio=1; get_guid(pb, &g); get_le32(pb); get_le32(pb); @@ -256,7 +260,13 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec->codec_type = type; if (type == CODEC_TYPE_AUDIO) { get_wav_header(pb, st->codec, type_specific_size); - st->need_parsing = 1; + if (is_dvr_ms_audio) { + // codec_id and codec_tag are unreliable in dvr_ms + // files. Set them later by probing stream. + st->codec->codec_id = CODEC_ID_NONE; + st->codec->codec_tag = 0; + } + st->need_parsing = AVSTREAM_PARSE_FULL; /* We have to init the frame size at some point .... */ pos2 = url_ftell(pb); if (gsize >= (pos2 + 8 - pos1 + 24)) { @@ -333,7 +343,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec->codec_tag = tag1; st->codec->codec_id = codec_get_id(codec_bmp_tags, tag1); if(tag1 == MKTAG('D', 'V', 'R', ' ')) - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; } pos2 = url_ftell(pb); url_fskip(pb, gsize - (pos2 - pos1 + 24)); @@ -363,7 +373,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) bitrate= get_le32(pb); stream_id= (flags & 0x7f); // av_log(NULL, AV_LOG_ERROR, "flags: 0x%x stream id %d, bitrate %d\n", flags, stream_id, bitrate); - asf->stream_bitrates[stream_id-1]= bitrate; + asf->stream_bitrates[stream_id]= bitrate; } } else if (!memcmp(&g, &extended_content_header, sizeof(GUID))) { int desc_count, i; @@ -383,12 +393,27 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) { if (!strcmp(name,"WM/AlbumTitle")) get_str16_nolen(pb, value_len, s->album, sizeof(s->album)); else if(!strcmp(name,"WM/Genre" )) get_str16_nolen(pb, value_len, s->genre, sizeof(s->genre)); + else if(!strcmp(name,"WM/Year" )) { + char year[8]; + get_str16_nolen(pb, value_len, year, sizeof(year)); + s->year = atoi(year); + } + else if(!strcmp(name,"WM/Track") && s->track == 0) { + char track[8]; + get_str16_nolen(pb, value_len, track, sizeof(track)); + s->track = strtol(track, NULL, 10) + 1; + } + else if(!strcmp(name,"WM/TrackNumber")) { + char track[8]; + get_str16_nolen(pb, value_len, track, sizeof(track)); + s->track = strtol(track, NULL, 10); + } else url_fskip(pb, value_len); } if ((value_type >= 2) && (value_type <= 5)) // boolean or DWORD or QWORD or WORD { value_num= get_value(pb, value_type); - if (!strcmp(name,"WM/Track" )) s->track = value_num + 1; + if (!strcmp(name,"WM/Track" ) && s->track == 0) s->track = value_num + 1; if (!strcmp(name,"WM/TrackNumber")) s->track = value_num; } } @@ -407,7 +432,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) get_str16_nolen(pb, name_len, name, sizeof(name)); //av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d <%s>\n", i, stream_num, name_len, value_type, value_len, name); - value_num= get_le16(pb);//we should use get_value() here but it doesnt work 2 is le16 here but le32 elsewhere + value_num= get_le16(pb);//we should use get_value() here but it does not work 2 is le16 here but le32 elsewhere url_fskip(pb, value_len - 2); if(stream_num<128){ @@ -417,13 +442,13 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) } } else if (!memcmp(&g, &ext_stream_header, sizeof(GUID))) { int ext_len, payload_ext_ct, stream_ct; - uint32_t ext_d; + uint32_t ext_d, leak_rate, stream_num; int64_t pos_ex_st; pos_ex_st = url_ftell(pb); get_le64(pb); // starttime get_le64(pb); // endtime - get_le32(pb); // leak-datarate + leak_rate = get_le32(pb); // leak-datarate get_le32(pb); // bucket-datasize get_le32(pb); // init-bucket-fullness get_le32(pb); // alt-leak-datarate @@ -431,12 +456,15 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) get_le32(pb); // alt-init-bucket-fullness get_le32(pb); // max-object-size get_le32(pb); // flags (reliable,seekable,no_cleanpoints?,resend-live-cleanpoints, rest of bits reserved) - get_le16(pb); // stream-num + stream_num = get_le16(pb); // stream-num get_le16(pb); // stream-language-id-index get_le64(pb); // avg frametime in 100ns units stream_ct = get_le16(pb); //stream-name-count payload_ext_ct = get_le16(pb); //payload-extension-system-count + if (stream_num < 128) + bitrate[stream_num] = leak_rate; + for (i=0; i<stream_ct; i++){ get_le16(pb); ext_len = get_le16(pb); @@ -500,11 +528,14 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) for(i=0; i<128; i++){ int stream_num= asf->asfid2avid[i]; - if(stream_num>=0 && dar[i].num>0 && dar[i].den>0){ + if(stream_num>=0){ AVCodecContext *codec= s->streams[stream_num]->codec; - av_reduce(&codec->sample_aspect_ratio.num, - &codec->sample_aspect_ratio.den, - dar[i].num, dar[i].den, INT_MAX); + if (!codec->bit_rate) + codec->bit_rate = bitrate[i]; + if (dar[i].num > 0 && dar[i].den > 0) + av_reduce(&codec->sample_aspect_ratio.num, + &codec->sample_aspect_ratio.den, + dar[i].num, dar[i].den, INT_MAX); //av_log(NULL, AV_LOG_ERROR, "dar %d:%d sar=%d:%d\n", dar[i].num, dar[i].den, codec->sample_aspect_ratio.num, codec->sample_aspect_ratio.den); } } @@ -539,12 +570,12 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) static int asf_get_packet(AVFormatContext *s) { ASFContext *asf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; uint32_t packet_length, padsize; int rsize = 8; int c, d, e, off; - off= (url_ftell(&s->pb) - s->data_offset) % asf->packet_size + 3; + off= (url_ftell(s->pb) - s->data_offset) % asf->packet_size + 3; c=d=e=-1; while(off-- > 0){ @@ -615,7 +646,7 @@ static int asf_get_packet(AVFormatContext *s) */ static int asf_read_frame_header(AVFormatContext *s){ ASFContext *asf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int rsize = 1; int num = get_byte(pb); int64_t ts0, ts1; @@ -651,7 +682,7 @@ static int asf_read_frame_header(AVFormatContext *s){ url_fskip(pb, asf->packet_replic_size - 8); rsize += asf->packet_replic_size; // FIXME - check validity } else if (asf->packet_replic_size==1){ - // multipacket - frag_offset is begining timestamp + // multipacket - frag_offset is beginning timestamp asf->packet_time_start = asf->packet_frag_offset; asf->packet_frag_offset = 0; asf->packet_frag_timestamp = asf->packet_timestamp; @@ -688,11 +719,11 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) { ASFContext *asf = s->priv_data; ASFStream *asf_st = 0; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; //static int pc = 0; for (;;) { if(url_feof(pb)) - return AVERROR_IO; + return AVERROR(EIO); if (asf->packet_size_left < FRAME_HEADER_SIZE || asf->packet_segments < 1) { //asf->packet_size_left <= asf->packet_padsize) { @@ -702,10 +733,10 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) /* fail safe */ url_fskip(pb, ret); - asf->packet_pos= url_ftell(&s->pb); + asf->packet_pos= url_ftell(s->pb); if (asf->data_object_size != (uint64_t)-1 && (asf->packet_pos - asf->data_object_offset >= asf->data_object_size)) - return AVERROR_IO; /* Do not exceed the size of the data object */ + return AVERROR(EIO); /* Do not exceed the size of the data object */ ret = asf_get_packet(s); //printf("READ ASF PACKET %d r:%d c:%d\n", ret, asf->packet_size_left, pc++); if (ret < 0) @@ -735,7 +766,7 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) asf_st = asf->asf_st; if (asf->packet_replic_size == 1) { - // frag_offset is here used as the begining timestamp + // frag_offset is here used as the beginning timestamp asf->packet_frag_timestamp = asf->packet_time_start; asf->packet_time_start += asf->packet_time_delta; asf->packet_obj_size = asf->packet_frag_size = get_byte(pb); @@ -751,6 +782,15 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) asf->packet_multi_size -= asf->packet_obj_size; //printf("COMPRESS size %d %d %d ms:%d\n", asf->packet_obj_size, asf->packet_frag_timestamp, asf->packet_size_left, asf->packet_multi_size); } + if( /*asf->packet_frag_size == asf->packet_obj_size*/ + asf_st->frag_offset + asf->packet_frag_size <= asf_st->pkt.size + && asf_st->frag_offset + asf->packet_frag_size > asf->packet_obj_size){ + av_log(s, AV_LOG_INFO, "ignoring invalid packet_obj_size (%d %d %d %d)\n", + asf_st->frag_offset, asf->packet_frag_size, + asf->packet_obj_size, asf_st->pkt.size); + asf->packet_obj_size= asf_st->pkt.size; + } + if ( asf_st->pkt.size != asf->packet_obj_size || asf_st->frag_offset + asf->packet_frag_size > asf_st->pkt.size) { //FIXME is this condition sufficient? if(asf_st->pkt.data){ @@ -791,13 +831,29 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) get_buffer(pb, asf_st->pkt.data + asf->packet_frag_offset, asf->packet_frag_size); + if (s->key && s->keylen == 20) + ff_asfcrypt_dec(s->key, asf_st->pkt.data + asf->packet_frag_offset, + asf->packet_frag_size); asf_st->frag_offset += asf->packet_frag_size; /* test if whole packet is read */ if (asf_st->frag_offset == asf_st->pkt.size) { + //workaround for macroshit radio DVR-MS files + if( s->streams[asf->stream_index]->codec->codec_id == CODEC_ID_MPEG2VIDEO + && asf_st->pkt.size > 100){ + int i; + for(i=0; i<asf_st->pkt.size && !asf_st->pkt.data[i]; i++); + if(i == asf_st->pkt.size){ + av_log(s, AV_LOG_DEBUG, "discarding ms fart\n"); + asf_st->frag_offset = 0; + av_free_packet(&asf_st->pkt); + continue; + } + } + /* return packet */ if (asf_st->ds_span > 1) { if(asf_st->pkt.size != asf_st->ds_packet_size * asf_st->ds_span){ - av_log(s, AV_LOG_ERROR, "pkt.size != ds_packet_size * ds_span\n"); + av_log(s, AV_LOG_ERROR, "pkt.size != ds_packet_size * ds_span (%d %d %d)\n", asf_st->pkt.size, asf_st->ds_packet_size, asf_st->ds_span); }else{ /* packet descrambling */ uint8_t *newdata = av_malloc(asf_st->pkt.size); @@ -833,18 +889,6 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) return 0; } -static int asf_read_close(AVFormatContext *s) -{ - int i; - - for(i=0;i<s->nb_streams;i++) { - AVStream *st = s->streams[i]; - av_free(st->priv_data); - av_free(st->codec->palctrl); - } - return 0; -} - // Added to support seeking after packets have been read // If information is not reset, read_packet fails due to // leftover information from previous reads @@ -883,6 +927,19 @@ static void asf_reset_header(AVFormatContext *s) asf->asf_st= NULL; } +static int asf_read_close(AVFormatContext *s) +{ + int i; + + asf_reset_header(s); + for(i=0;i<s->nb_streams;i++) { + AVStream *st = s->streams[i]; + av_free(st->priv_data); + av_free(st->codec->palctrl); + } + return 0; +} + static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit) { ASFContext *asf = s->priv_data; @@ -899,7 +956,7 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, pos= (pos+asf->packet_size-1-s->data_offset)/asf->packet_size*asf->packet_size+ s->data_offset; *ppos= pos; - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); //printf("asf_read_pts\n"); asf_reset_header(s); @@ -943,21 +1000,21 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index) int i; int pct,ict; - current_pos = url_ftell(&s->pb); + current_pos = url_ftell(s->pb); - url_fseek(&s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET); - get_guid(&s->pb, &g); + url_fseek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET); + get_guid(s->pb, &g); if (!memcmp(&g, &index_guid, sizeof(GUID))) { - gsize = get_le64(&s->pb); - get_guid(&s->pb, &g); - itime=get_le64(&s->pb); - pct=get_le32(&s->pb); - ict=get_le32(&s->pb); + gsize = get_le64(s->pb); + get_guid(s->pb, &g); + itime=get_le64(s->pb); + pct=get_le32(s->pb); + ict=get_le32(s->pb); av_log(NULL, AV_LOG_DEBUG, "itime:0x%"PRIx64", pct:%d, ict:%d\n",itime,pct,ict); for (i=0;i<ict;i++){ - int pktnum=get_le32(&s->pb); - int pktct =get_le16(&s->pb); + int pktnum=get_le32(s->pb); + int pktct =get_le16(s->pb); av_log(NULL, AV_LOG_DEBUG, "pktnum:%d, pktct:%d\n", pktnum, pktct); pos=s->data_offset + asf->packet_size*(int64_t)pktnum; @@ -967,7 +1024,7 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index) } asf->index_read= 1; } - url_fseek(&s->pb, current_pos, SEEK_SET); + url_fseek(s->pb, current_pos, SEEK_SET); } static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags) @@ -980,6 +1037,15 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int if (asf->packet_size <= 0) return -1; + /* Try using the protocol's read_seek if available */ + if(s->pb) { + int ret = av_url_read_fseek(s->pb, stream_index, pts, flags); + if(ret >= 0) + asf_reset_header(s); + if (ret != AVERROR(ENOSYS)) + return ret; + } + if (!asf->index_read) asf_build_simple_index(s, stream_index); @@ -997,10 +1063,10 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int // various attempts to find key frame have failed so far // asf_reset_header(s); - // url_fseek(&s->pb, pos, SEEK_SET); + // url_fseek(s->pb, pos, SEEK_SET); // key_pos = pos; // for(i=0;i<16;i++){ - // pos = url_ftell(&s->pb); + // pos = url_ftell(s->pb); // if (av_read_frame(s, &pkt) < 0){ // av_log(s, AV_LOG_INFO, "seek failed\n"); // return -1; @@ -1018,7 +1084,7 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int /* do the seek */ av_log(NULL, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos); - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); } asf_reset_header(s); return 0; |