X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fasf.c;h=695cfeca75e51336e0e49163123fef853794c4f1;hb=9686df2be543b740ec71e6ef633f312b8592813f;hp=b37bc4c76dbc5a551ee419ae6306b8dfda7b526e;hpb=629272d86f8c4dcfd6c38b9000bb6872f0a229a3;p=ffmpeg diff --git a/libavformat/asf.c b/libavformat/asf.c index b37bc4c76db..695cfeca75e 100644 --- a/libavformat/asf.c +++ b/libavformat/asf.c @@ -18,11 +18,15 @@ * 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/common.h" +#include "libavcodec/mpegaudio.h" #include "avformat.h" #include "riff.h" -#include "mpegaudio.h" #include "asf.h" -#include "common.h" +#include "asfcrypt.h" + +void ff_mms_set_stream_selection(URLContext *h, AVFormatContext *format); #undef NDEBUG #include @@ -45,7 +49,7 @@ static const GUID stream_bitrate_guid = { /* (http://get.to/sdp) */ #ifdef DEBUG #define PRINT_IF_GUID(g,cmp) \ if (!memcmp(g, &cmp, sizeof(GUID))) \ - printf("(GUID: %s) ", #cmp) + dprintf(NULL, "(GUID: %s) ", #cmp) static void print_guid(const GUID *g) { @@ -73,18 +77,20 @@ static void print_guid(const GUID *g) else PRINT_IF_GUID(g, metadata_header); else PRINT_IF_GUID(g, stream_bitrate_guid); else - printf("(GUID: unknown) "); + dprintf(NULL, "(GUID: unknown) "); for(i=0;i<16;i++) - printf(" 0x%02x,", (*g)[i]); - printf("}\n"); + dprintf(NULL, " 0x%02x,", (*g)[i]); + dprintf(NULL, "}\n"); } #undef PRINT_IF_GUID +#else +#define print_guid(g) #endif 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 @@ -139,7 +145,7 @@ 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; @@ -152,7 +158,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) get_guid(pb, &g); if (memcmp(&g, &asf_header, sizeof(GUID))) - goto fail; + return -1; get_le64(pb); get_le32(pb); get_byte(pb); @@ -161,11 +167,9 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) for(;;) { get_guid(pb, &g); gsize = get_le64(pb); -#ifdef DEBUG - printf("%08"PRIx64": ", url_ftell(pb) - 24); + dprintf(s, "%08"PRIx64": ", url_ftell(pb) - 24); print_guid(&g); - printf(" size=0x%"PRIx64"\n", gsize); -#endif + dprintf(s, " size=0x%"PRIx64"\n", gsize); if (!memcmp(&g, &data_header, sizeof(GUID))) { asf->data_object_offset = url_ftell(pb); // if not streaming, gsize is not unlimited (how?), and there is enough space in the file.. @@ -177,14 +181,14 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) break; } if (gsize < 24) - goto fail; + return -1; if (!memcmp(&g, &file_header, sizeof(GUID))) { get_guid(pb, &asf->hdr.guid); asf->hdr.file_size = get_le64(pb); asf->hdr.create_time = get_le64(pb); asf->nb_packets = get_le64(pb); - asf->hdr.send_time = get_le64(pb); asf->hdr.play_time = get_le64(pb); + asf->hdr.send_time = get_le64(pb); asf->hdr.preroll = get_le32(pb); asf->hdr.ignore = get_le32(pb); asf->hdr.flags = get_le32(pb); @@ -193,26 +197,28 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) asf->hdr.max_bitrate = get_le32(pb); asf->packet_size = asf->hdr.max_pktsize; } else if (!memcmp(&g, &stream_header, sizeof(GUID))) { - int type, type_specific_size, sizeX; + enum CodecType type; + int type_specific_size, sizeX; uint64_t total_size; unsigned int tag1; - int64_t pos1, pos2; + int64_t pos1, pos2, start_time; int test_for_ext_stream_audio, is_dvr_ms_audio=0; pos1 = url_ftell(pb); st = av_new_stream(s, 0); if (!st) - goto fail; + return AVERROR(ENOMEM); av_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */ asf_st = av_mallocz(sizeof(ASFStream)); if (!asf_st) - goto fail; + return AVERROR(ENOMEM); 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); @@ -222,12 +228,12 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) } else if (!memcmp(&g, &video_stream, sizeof(GUID))) { type = CODEC_TYPE_VIDEO; } else if (!memcmp(&g, &command_stream, sizeof(GUID))) { - type = CODEC_TYPE_UNKNOWN; + type = CODEC_TYPE_DATA; } else if (!memcmp(&g, &ext_stream_embed_stream_header, sizeof(GUID))) { test_for_ext_stream_audio = 1; type = CODEC_TYPE_UNKNOWN; } else { - goto fail; + return -1; } get_guid(pb, &g); total_size = get_le64(pb); @@ -259,7 +265,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) 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_id = CODEC_ID_PROBE; st->codec->codec_tag = 0; } st->need_parsing = AVSTREAM_PARSE_FULL; @@ -310,7 +316,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec->height = get_le32(pb); /* not available for asf */ get_le16(pb); /* panes */ - st->codec->bits_per_sample = get_le16(pb); /* depth */ + st->codec->bits_per_coded_sample = get_le16(pb); /* depth */ tag1 = get_le32(pb); url_fskip(pb, 20); // av_log(NULL, AV_LOG_DEBUG, "size:%d tsize:%d sizeX:%d\n", size, total_size, sizeX); @@ -324,7 +330,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) /* Extract palette from extradata if bpp <= 8 */ /* This code assumes that extradata contains only palette */ /* This is true for all paletted codecs implemented in ffmpeg */ - if (st->codec->extradata_size && (st->codec->bits_per_sample <= 8)) { + if (st->codec->extradata_size && (st->codec->bits_per_coded_sample <= 8)) { st->codec->palctrl = av_mallocz(sizeof(AVPaletteControl)); #ifdef WORDS_BIGENDIAN for (i = 0; i < FFMIN(st->codec->extradata_size, AVPALETTE_SIZE)/4; i++) @@ -369,7 +375,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; @@ -385,11 +391,16 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) get_str16_nolen(pb, name_len, name, sizeof(name)); value_type = get_le16(pb); value_len = get_le16(pb); - if ((value_type == 0) || (value_type == 1)) // unicode or byte + if (value_type <= 1) // unicode or byte { 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/Track")) { + 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; @@ -401,12 +412,13 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) } else url_fskip(pb, value_len); } - if ((value_type >= 2) && (value_type <= 5)) // boolean or DWORD or QWORD or WORD + else if (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; - } + }else + url_fskip(pb, value_len); } } else if (!memcmp(&g, &metadata_header, sizeof(GUID))) { int n, stream_num, name_len, value_len, value_type, value_num; @@ -502,7 +514,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) } #endif } else if (url_feof(pb)) { - goto fail; + return -1; } else { url_fseek(pb, gsize - 24, SEEK_CUR); } @@ -512,7 +524,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) get_byte(pb); get_byte(pb); if (url_feof(pb)) - goto fail; + return -1; asf->data_offset = url_ftell(pb); asf->packet_size_left = 0; @@ -520,29 +532,18 @@ 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){ - AVCodecContext *codec= s->streams[stream_num]->codec; - if (!codec->bit_rate) - codec->bit_rate = bitrate[i]; + AVStream *st = s->streams[stream_num]; + if (!st->codec->bit_rate) + st->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, + av_reduce(&st->sample_aspect_ratio.num, + &st->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); +//av_log(NULL, AV_LOG_ERROR, "dar %d:%d sar=%d:%d\n", dar[i].num, dar[i].den, st->sample_aspect_ratio.num, st->sample_aspect_ratio.den); } } return 0; - - fail: - for(i=0;inb_streams;i++) { - AVStream *st = s->streams[i]; - if (st) { - av_free(st->priv_data); - av_free(st->codec->extradata); - } - av_free(st); - } - return -1; } #define DO_2BITS(bits, var, defval) \ @@ -561,12 +562,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){ @@ -625,9 +626,7 @@ static int asf_get_packet(AVFormatContext *s) if (packet_length < asf->hdr.min_pktsize) padsize += asf->hdr.min_pktsize - packet_length; asf->packet_padsize = padsize; -#ifdef DEBUG - printf("packet: size=%d padsize=%d left=%d\n", asf->packet_size, asf->packet_padsize, asf->packet_size_left); -#endif + dprintf(s, "packet: size=%d padsize=%d left=%d\n", asf->packet_size, asf->packet_padsize, asf->packet_size_left); return 0; } @@ -637,7 +636,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; @@ -673,7 +672,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; @@ -710,11 +709,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) { @@ -724,10 +723,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) @@ -757,7 +756,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); @@ -773,6 +772,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){ @@ -783,7 +791,7 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) /* new packet */ av_new_packet(&asf_st->pkt, asf->packet_obj_size); asf_st->seq = asf->packet_seq; - asf_st->pkt.pts = asf->packet_frag_timestamp; + asf_st->pkt.dts = asf->packet_frag_timestamp; asf_st->pkt.stream_index = asf->stream_index; asf_st->pkt.pos = asf_st->packet_pos= asf->packet_pos; @@ -813,13 +821,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; ipkt.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); @@ -855,18 +879,6 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) return 0; } -static int asf_read_close(AVFormatContext *s) -{ - int i; - - for(i=0;inb_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 @@ -905,6 +917,18 @@ 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;inb_streams;i++) { + AVStream *st = s->streams[i]; + 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; @@ -921,7 +945,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); @@ -965,21 +989,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;ipb); - 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; @@ -989,7 +1013,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) @@ -1002,6 +1026,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); @@ -1019,10 +1052,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; @@ -1040,7 +1073,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; @@ -1048,7 +1081,7 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int AVInputFormat asf_demuxer = { "asf", - "asf format", + NULL_IF_CONFIG_SMALL("ASF format"), sizeof(ASFContext), asf_probe, asf_read_header,