X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fasfdec.c;h=7d717890295b82aebd2f5a1076e6daea4e5a82e3;hb=d60c2d5216930ef98c7d4d6837d6229b37e0dcb3;hp=bb083570e0425f2ef9fcebcb5c9bdf961891837a;hpb=0989d3ad1fbd7509815208b0a5792918492d2a68;p=ffmpeg diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c index bb083570e04..7d717890295 100644 --- a/libavformat/asfdec.c +++ b/libavformat/asfdec.c @@ -20,7 +20,6 @@ */ #include "libavutil/attributes.h" -#include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/bswap.h" #include "libavutil/common.h" @@ -122,19 +121,18 @@ typedef struct ASFContext { int stream_index; // from packet header, for the subpayload case - // packet parameteres - uint64_t sub_header_offset; // offset of subplayload header + // packet parameters + uint64_t sub_header_offset; // offset of subpayload header int64_t sub_dts; uint8_t dts_delta; // for subpayloads uint32_t packet_size_internal; // packet size stored inside ASFPacket, can be 0 - int64_t dts; int64_t packet_offset; // offset of the current packet inside Data Object uint32_t pad_len; // padding after payload uint32_t rep_data_len; // packet state uint64_t sub_left; // subpayloads left or not - int nb_sub; // number of subpayloads read so far from the current ASF packet + unsigned int nb_sub; // number of subpayloads read so far from the current ASF packet uint16_t mult_sub_len; // total length of subpayloads array inside multiple payload uint64_t nb_mult_left; // multiple payloads left int return_subpayload; @@ -179,6 +177,9 @@ static int asf_read_unknown(AVFormatContext *s, const GUIDParseTable *g) uint64_t size = avio_rl64(pb); int ret; + if (size > INT64_MAX) + return AVERROR_INVALIDDATA; + if (asf->is_header) asf->unknown_size = size; asf->is_header = 0; @@ -188,8 +189,13 @@ static int asf_read_unknown(AVFormatContext *s, const GUIDParseTable *g) if ((ret = detect_unknown_subobject(s, asf->unknown_offset, asf->unknown_size)) < 0) return ret; - } else + } else { + if (size < 24) { + av_log(s, AV_LOG_ERROR, "Too small size %"PRIu64" (< 24).\n", size); + return AVERROR_INVALIDDATA; + } avio_skip(pb, size - 24); + } return 0; } @@ -256,13 +262,15 @@ static int asf_read_metadata(AVFormatContext *s, const char *title, uint16_t len AVIOContext *pb = s->pb; avio_get_str16le(pb, len, ch, buflen); - if (av_dict_set(&s->metadata, title, ch, 0) < 0) - av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); + if (ch[0]) { + if (av_dict_set(&s->metadata, title, ch, 0) < 0) + av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); + } return 0; } -static int asf_read_value(AVFormatContext *s, uint8_t *name, uint16_t name_len, +static int asf_read_value(AVFormatContext *s, const uint8_t *name, uint16_t val_len, int type, AVDictionary **met) { int ret; @@ -303,31 +311,41 @@ failed: av_freep(&value); return ret; } - -static int asf_read_generic_value(AVFormatContext *s, uint8_t *name, uint16_t name_len, - int type, AVDictionary **met) +static int asf_read_generic_value(AVIOContext *pb, int type, uint64_t *value) { - AVIOContext *pb = s->pb; - uint64_t value; - char buf[32]; switch (type) { case ASF_BOOL: - value = avio_rl32(pb); + *value = avio_rl16(pb); break; case ASF_DWORD: - value = avio_rl32(pb); + *value = avio_rl32(pb); break; case ASF_QWORD: - value = avio_rl64(pb); + *value = avio_rl64(pb); break; case ASF_WORD: - value = avio_rl16(pb); + *value = avio_rl16(pb); break; default: - av_freep(&name); return AVERROR_INVALIDDATA; } + + return 0; +} + +static int asf_set_metadata(AVFormatContext *s, const uint8_t *name, + int type, AVDictionary **met) +{ + AVIOContext *pb = s->pb; + uint64_t value; + char buf[32]; + int ret; + + ret = asf_read_generic_value(pb, type, &value); + if (ret < 0) + return ret; + snprintf(buf, sizeof(buf), "%"PRIu64, value); if (av_dict_set(met, name, buf, 0) < 0) av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n"); @@ -412,8 +430,8 @@ static int asf_read_picture(AVFormatContext *s, int len) } st->disposition |= AV_DISPOSITION_ATTACHED_PIC; - st->codec->codec_type = asf_st->type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_id = id; + st->codecpar->codec_type = asf_st->type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = id; st->attached_pic = pkt; st->attached_pic.stream_index = asf_st->index = st->index; st->attached_pic.flags |= AV_PKT_FLAG_KEY; @@ -433,11 +451,11 @@ static int asf_read_picture(AVFormatContext *s, int len) fail: av_freep(&desc); - av_free_packet(&pkt); + av_packet_unref(&pkt); return ret; } -static void get_id3_tag(AVFormatContext *s, int len) +static void get_id3_tag(AVFormatContext *s) { ID3v2ExtraMeta *id3v2_extra_meta = NULL; @@ -447,7 +465,7 @@ static void get_id3_tag(AVFormatContext *s, int len) ff_id3v2_free_extra_meta(&id3v2_extra_meta); } -static int process_metadata(AVFormatContext *s, uint8_t *name, uint16_t name_len, +static int process_metadata(AVFormatContext *s, const uint8_t *name, uint16_t name_len, uint16_t val_len, uint16_t type, AVDictionary **met) { int ret; @@ -456,26 +474,25 @@ static int process_metadata(AVFormatContext *s, uint8_t *name, uint16_t name_len if (val_len) { switch (type) { case ASF_UNICODE: - asf_read_value(s, name, name_len, val_len, type, met); + asf_read_value(s, name, val_len, type, met); break; case ASF_BYTE_ARRAY: if (!strcmp(name, "WM/Picture")) // handle cover art asf_read_picture(s, val_len); else if (!strcmp(name, "ID3")) // handle ID3 tag - get_id3_tag(s, val_len); + get_id3_tag(s); else - asf_read_value(s, name, name_len, val_len, type, met); + asf_read_value(s, name, val_len, type, met); break; case ASF_GUID: ff_get_guid(s->pb, &guid); break; default: - if ((ret = asf_read_generic_value(s, name, name_len, type, met)) < 0) + if ((ret = asf_set_metadata(s, name, type, met)) < 0) return ret; break; } } - av_freep(&name); return 0; } @@ -501,9 +518,15 @@ static int asf_read_ext_content(AVFormatContext *s, const GUIDParseTable *g) avio_get_str16le(pb, name_len, name, name_len); type = avio_rl16(pb); + // BOOL values are 16 bits long in the Metadata Object + // but 32 bits long in the Extended Content Description Object + if (type == ASF_BOOL) + type = ASF_DWORD; val_len = avio_rl16(pb); - if ((ret = process_metadata(s, name, name_len, val_len, type, &s->metadata)) < 0) + ret = process_metadata(s, name, name_len, val_len, type, &s->metadata); + av_freep(&name); + if (ret < 0) return ret; } @@ -527,13 +550,16 @@ static AVStream *find_stream(AVFormatContext *s, uint16_t st_num) return st; } -static void asf_store_aspect_ratio(AVFormatContext *s, uint8_t st_num, uint8_t *name) +static int asf_store_aspect_ratio(AVFormatContext *s, uint8_t st_num, uint8_t *name, int type) { ASFContext *asf = s->priv_data; AVIOContext *pb = s->pb; - uint16_t value = 0; + uint64_t value = 0; + int ret; - value = avio_rl16(pb); + ret = asf_read_generic_value(pb, type, &value); + if (ret < 0) + return ret; if (st_num < ASF_MAX_STREAMS) { if (!strcmp(name, "AspectRatioX")) @@ -541,6 +567,7 @@ static void asf_store_aspect_ratio(AVFormatContext *s, uint8_t st_num, uint8_t * else asf->asf_sd[st_num].aspect_ratio.den = value; } + return 0; } static int asf_read_metadata_obj(AVFormatContext *s, const GUIDParseTable *g) @@ -563,22 +590,27 @@ static int asf_read_metadata_obj(AVFormatContext *s, const GUIDParseTable *g) break; type = avio_rl16(pb); val_len = avio_rl32(pb); - name = av_malloc(name_len); + name = av_malloc(buflen); if (!name) return AVERROR(ENOMEM); avio_get_str16le(pb, name_len, name, buflen); - if (!strcmp(name, "AspectRatioX") || !strcmp(name, "AspectRatioY")) { - asf_store_aspect_ratio(s, st_num, name); + ret = asf_store_aspect_ratio(s, st_num, name, type); + if (ret < 0) { + av_freep(&name); + break; + } } else { if (st_num < ASF_MAX_STREAMS) { if ((ret = process_metadata(s, name, name_len, val_len, type, - &asf->asf_sd[st_num].asf_met)) < 0) + &asf->asf_sd[st_num].asf_met)) < 0) { + av_freep(&name); break; - } else - av_freep(&name); + } + } } + av_freep(&name); } align_position(pb, asf->offset, size); @@ -618,7 +650,7 @@ static int asf_read_properties(AVFormatContext *s, const GUIDParseTable *g) { ASFContext *asf = s->priv_data; AVIOContext *pb = s->pb; - uint64_t creation_time; + time_t creation_time; avio_rl64(pb); // read object size avio_skip(pb, 16); // skip File ID @@ -662,26 +694,26 @@ static int parse_video_info(AVIOContext *pb, AVStream *st) uint16_t size; unsigned int tag; - st->codec->width = avio_rl32(pb); - st->codec->height = avio_rl32(pb); + st->codecpar->width = avio_rl32(pb); + st->codecpar->height = avio_rl32(pb); avio_skip(pb, 1); // skip reserved flags size = avio_rl16(pb); // size of the Format Data tag = ff_get_bmp_header(pb, st); - st->codec->codec_tag = tag; - st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag); + st->codecpar->codec_tag = tag; + st->codecpar->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag); if (size > BMP_HEADER_SIZE) { int ret; - st->codec->extradata_size = size - BMP_HEADER_SIZE; - if (!(st->codec->extradata = av_malloc(st->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE))) { - st->codec->extradata_size = 0; + st->codecpar->extradata_size = size - BMP_HEADER_SIZE; + if (!(st->codecpar->extradata = av_malloc(st->codecpar->extradata_size + + AV_INPUT_BUFFER_PADDING_SIZE))) { + st->codecpar->extradata_size = 0; return AVERROR(ENOMEM); } - memset(st->codec->extradata + st->codec->extradata_size , 0, - FF_INPUT_BUFFER_PADDING_SIZE); - if ((ret = avio_read(pb, st->codec->extradata, - st->codec->extradata_size)) < 0) + memset(st->codecpar->extradata + st->codecpar->extradata_size , 0, + AV_INPUT_BUFFER_PADDING_SIZE); + if ((ret = avio_read(pb, st->codecpar->extradata, + st->codecpar->extradata_size)) < 0) return ret; } return 0; @@ -740,11 +772,12 @@ static int asf_read_stream_properties(AVFormatContext *s, const GUIDParseTable * if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 32, 1, 1000); // pts should be dword, in milliseconds - st->codec->codec_type = type; + st->codecpar->codec_type = type; asf->asf_st[asf->nb_streams] = av_mallocz(sizeof(*asf_st)); if (!asf->asf_st[asf->nb_streams]) return AVERROR(ENOMEM); asf_st = asf->asf_st[asf->nb_streams]; + asf->nb_streams++; asf_st->stream_index = stream_index; asf_st->index = st->index; asf_st->indexed = 0; @@ -756,7 +789,7 @@ static int asf_read_stream_properties(AVFormatContext *s, const GUIDParseTable * switch (type) { case AVMEDIA_TYPE_AUDIO: asf_st->type = AVMEDIA_TYPE_AUDIO; - if ((ret = ff_get_wav_header(s, pb, st->codec, ts_data_len)) < 0) + if ((ret = ff_get_wav_header(s, pb, st->codecpar, ts_data_len)) < 0) return ret; break; case AVMEDIA_TYPE_VIDEO: @@ -776,6 +809,8 @@ static int asf_read_stream_properties(AVFormatContext *s, const GUIDParseTable * asf_st->span = span; asf_st->virtual_pkt_len = avio_rl16(pb); asf_st->virtual_chunk_len = avio_rl16(pb); + if (!asf_st->virtual_chunk_len || !asf_st->virtual_pkt_len) + return AVERROR_INVALIDDATA; avio_skip(pb, err_data_len - 5); } else avio_skip(pb, err_data_len - 1); @@ -783,7 +818,6 @@ static int asf_read_stream_properties(AVFormatContext *s, const GUIDParseTable * avio_skip(pb, err_data_len); } - asf->nb_streams++; align_position(pb, asf->offset, size); return 0; @@ -832,7 +866,7 @@ static int asf_read_ext_stream_properties(AVFormatContext *s, const GUIDParseTab if (st) { st->start_time = start_time; st->duration = end_time - start_time; - st->codec->bit_rate = bitrate; + st->codecpar->bit_rate = bitrate; st->avg_frame_rate.num = 10000000; st->avg_frame_rate.den = time_per_frame; } @@ -903,7 +937,7 @@ static int asf_read_data(AVFormatContext *s, const GUIDParseTable *g) uint64_t size = asf->data_size = avio_rl64(pb); int i; - if (!asf->data_reached && pb->seekable) { + if (!asf->data_reached) { asf->data_reached = 1; asf->data_offset = asf->offset; } @@ -926,7 +960,7 @@ static int asf_read_data(AVFormatContext *s, const GUIDParseTable *g) size, asf->nb_packets); avio_skip(pb, 2); // skip reserved field asf->first_packet_offset = avio_tell(pb); - if (pb->seekable) + if (pb->seekable && !(asf->b_flags & ASF_FLAG_BROADCAST)) align_position(pb, asf->offset, asf->data_size); return 0; @@ -940,7 +974,7 @@ static int asf_read_simple_index(AVFormatContext *s, const GUIDParseTable *g) uint64_t interval; // index entry time interval in 100 ns units, usually it's 1s uint32_t pkt_num, nb_entries; int32_t prev_pkt_num = -1; - int i; + int i, ret; uint64_t size = avio_rl64(pb); // simple index objects should be ordered by stream number, this loop tries to find @@ -962,7 +996,11 @@ static int asf_read_simple_index(AVFormatContext *s, const GUIDParseTable *g) nb_entries = avio_rl32(pb); for (i = 0; i < nb_entries; i++) { pkt_num = avio_rl32(pb); - avio_skip(pb, 2); + ret = avio_skip(pb, 2); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Skipping failed in asf_read_simple_index.\n"); + return ret; + } if (prev_pkt_num != pkt_num) { av_add_index_entry(st, asf->first_packet_offset + asf->packet_size * pkt_num, av_rescale(interval, i, 10000), @@ -1101,10 +1139,32 @@ static void reset_packet(ASFPacket *asf_pkt) asf_pkt->flags = 0; asf_pkt->dts = 0; asf_pkt->duration = 0; - av_free_packet(&asf_pkt->avpkt); + av_packet_unref(&asf_pkt->avpkt); av_init_packet(&asf_pkt->avpkt); } +static int asf_read_replicated_data(AVFormatContext *s, ASFPacket *asf_pkt) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + int ret, data_size; + + if (!asf_pkt->data_size) { + data_size = avio_rl32(pb); // read media object size + if (data_size <= 0) + return AVERROR_INVALIDDATA; + if ((ret = av_new_packet(&asf_pkt->avpkt, data_size)) < 0) + return ret; + asf_pkt->data_size = asf_pkt->size_left = data_size; + } else + avio_skip(pb, 4); // reading of media object size is already done + asf_pkt->dts = avio_rl32(pb); // read presentation time + if (asf->rep_data_len && (asf->rep_data_len >= 8)) + avio_skip(pb, asf->rep_data_len - 8); // skip replicated data + + return 0; +} + static int asf_read_multiple_payload(AVFormatContext *s, AVPacket *pkt, ASFPacket *asf_pkt) { @@ -1115,7 +1175,7 @@ static int asf_read_multiple_payload(AVFormatContext *s, AVPacket *pkt, int ret; int skip = 0; - // if replicated lenght is 1, subpayloads are present + // if replicated length is 1, subpayloads are present if (asf->rep_data_len == 1) { asf->sub_left = 1; asf->state = READ_MULTI_SUB; @@ -1123,19 +1183,9 @@ static int asf_read_multiple_payload(AVFormatContext *s, AVPacket *pkt, if ((ret = asf_read_subpayload(s, pkt, 1)) < 0) return ret; } else { - if (asf->rep_data_len) { - if (!asf_pkt->data_size) { - asf_pkt->data_size = asf_pkt->size_left = avio_rl32(pb); // read media object size - if (asf_pkt->data_size <= 0) - return AVERROR_EOF; - if ((ret = av_new_packet(&asf_pkt->avpkt, asf_pkt->data_size)) < 0) - return ret; - } else - avio_skip(pb, 4); // reading of media object size is already done - asf_pkt->dts = avio_rl32(pb); // read presentation time - if (asf->rep_data_len && (asf->rep_data_len >= 8)) - avio_skip(pb, asf->rep_data_len - 8); // skip replicated data - } + if (asf->rep_data_len) + if ((ret = asf_read_replicated_data(s, asf_pkt)) < 0) + return ret; pay_len = avio_rl16(pb); // payload length should be WORD if (pay_len > asf->packet_size) { av_log(s, AV_LOG_ERROR, @@ -1152,6 +1202,8 @@ static int asf_read_multiple_payload(AVFormatContext *s, AVPacket *pkt, skip = pay_len - asf_pkt->size_left; pay_len = asf_pkt->size_left; } + if (asf_pkt->size_left <= 0) + return AVERROR_INVALIDDATA; if ((ret = avio_read(pb, p, pay_len)) < 0) return ret; if (s->key && s->keylen == 20) @@ -1164,22 +1216,22 @@ static int asf_read_multiple_payload(AVFormatContext *s, AVPacket *pkt, return 0; } -static int asf_read_single_payload(AVFormatContext *s, AVPacket *pkt, - ASFPacket *asf_pkt) +static int asf_read_single_payload(AVFormatContext *s, ASFPacket *asf_pkt) { ASFContext *asf = s->priv_data; AVIOContext *pb = s->pb; int64_t offset; uint64_t size; unsigned char *p; - int ret; + int ret, data_size; if (!asf_pkt->data_size) { - asf_pkt->data_size = asf_pkt->size_left = avio_rl32(pb); // read media object size - if (asf_pkt->data_size <= 0) + data_size = avio_rl32(pb); // read media object size + if (data_size <= 0) return AVERROR_EOF; - if ((ret = av_new_packet(&asf_pkt->avpkt, asf_pkt->data_size)) < 0) + if ((ret = av_new_packet(&asf_pkt->avpkt, data_size)) < 0) return ret; + asf_pkt->data_size = asf_pkt->size_left = data_size; } else avio_skip(pb, 4); // skip media object size asf_pkt->dts = avio_rl32(pb); // read presentation time @@ -1199,7 +1251,7 @@ static int asf_read_single_payload(AVFormatContext *s, AVPacket *pkt, return AVERROR_INVALIDDATA; } p = asf_pkt->avpkt.data + asf_pkt->data_size - asf_pkt->size_left; - if (size > asf_pkt->size_left) + if (size > asf_pkt->size_left || asf_pkt->size_left <= 0) return AVERROR_INVALIDDATA; if (asf_pkt->size_left > size) asf_pkt->size_left -= size; @@ -1233,12 +1285,23 @@ static int asf_read_payload(AVFormatContext *s, AVPacket *pkt) if (asf->stream_index == asf->asf_st[i]->stream_index) { asf_pkt = &asf->asf_st[i]->pkt; asf_pkt->stream_index = asf->asf_st[i]->index; - asf_pkt->dts = asf->dts; break; } } - if (!asf_pkt) - return AVERROR_INVALIDDATA; + if (!asf_pkt) { + if (asf->packet_offset + asf->packet_size <= asf->data_offset + asf->data_size) { + if (!asf->packet_size) { + av_log(s, AV_LOG_ERROR, "Invalid packet size 0.\n"); + return AVERROR_INVALIDDATA; + } + avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET); + av_log(s, AV_LOG_WARNING, "Skipping the stream with the invalid stream index %d.\n", + asf->stream_index); + return AVERROR(EAGAIN); + } else + return AVERROR_INVALIDDATA; + } + if (stream_num >> 7) asf_pkt->flags |= AV_PKT_FLAG_KEY; READ_LEN(asf->prop_flags & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE, @@ -1263,7 +1326,7 @@ static int asf_read_payload(AVFormatContext *s, AVPacket *pkt) if ((ret = asf_read_subpayload(s, pkt, 1)) < 0) return ret; } else { - if ((ret = asf_read_single_payload(s, pkt, asf_pkt)) < 0) + if ((ret = asf_read_single_payload(s, asf_pkt)) < 0) return ret; } } else { @@ -1295,12 +1358,14 @@ static int asf_read_packet_header(AVFormatContext *s) asf->packet_offset = avio_tell(pb); error_flags = avio_r8(pb); // read Error Correction Flags - if (error_flags & ASF_PACKET_FLAG_ERROR_CORRECTION_PRESENT) + if (error_flags & ASF_PACKET_FLAG_ERROR_CORRECTION_PRESENT) { if (!(error_flags & ASF_ERROR_CORRECTION_LENGTH_TYPE)) { size = error_flags & ASF_PACKET_ERROR_CORRECTION_DATA_SIZE; avio_skip(pb, size); } - len_flags = avio_r8(pb); + len_flags = avio_r8(pb); + } else + len_flags = error_flags; asf->prop_flags = avio_r8(pb); READ_LEN(len_flags & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE, ASF_PPI_FLAG_PACKET_LENGTH_FIELD_, asf->packet_size_internal); @@ -1354,7 +1419,7 @@ static int asf_deinterleave(AVFormatContext *s, ASFPacket *asf_pkt, int st_num) if (p > asf_pkt->avpkt.data + asf_pkt->data_size) break; } - av_free_packet(&asf_pkt->avpkt); + av_packet_unref(&asf_pkt->avpkt); asf_pkt->avpkt = pkt; return 0; @@ -1372,13 +1437,21 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) while (!pb->eof_reached) { if (asf->state == PARSE_PACKET_HEADER) { asf_read_packet_header(s); + if (pb->eof_reached) + break; if (!asf->nb_mult_left) asf->state = READ_SINGLE; else asf->state = READ_MULTI; } - if ((ret = asf_read_payload(s, pkt)) < 0) + ret = asf_read_payload(s, pkt); + if (ret == AVERROR(EAGAIN)) { + asf->state = PARSE_PACKET_HEADER; + continue; + } + else if (ret < 0) return ret; + switch (asf->state) { case READ_SINGLE: if (!asf->sub_left) @@ -1387,7 +1460,9 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) case READ_MULTI_SUB: if (!asf->sub_left && !asf->nb_mult_left) { asf->state = PARSE_PACKET_HEADER; - if (!asf->return_subpayload) + if (!asf->return_subpayload && + (avio_tell(pb) <= asf->packet_offset + + asf->packet_size - asf->pad_len)) avio_skip(pb, asf->pad_len); // skip padding if (asf->packet_offset + asf->packet_size > avio_tell(pb)) avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET); @@ -1397,9 +1472,10 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) case READ_MULTI: if (!asf->nb_mult_left) { asf->state = PARSE_PACKET_HEADER; - if (!asf->return_subpayload) { + if (!asf->return_subpayload && + (avio_tell(pb) <= asf->packet_offset + + asf->packet_size - asf->pad_len)) avio_skip(pb, asf->pad_len); // skip padding - } if (asf->packet_offset + asf->packet_size > avio_tell(pb)) avio_seek(pb, asf->packet_offset + asf->packet_size, SEEK_SET); } @@ -1438,12 +1514,15 @@ static int asf_read_close(AVFormatContext *s) ASFContext *asf = s->priv_data; int i; - for (i = 0; i < asf->nb_streams; i++) { - av_free_packet(&asf->asf_st[i]->pkt.avpkt); - av_freep(&asf->asf_st[i]); + for (i = 0; i < ASF_MAX_STREAMS; i++) { av_dict_free(&asf->asf_sd[i].asf_met); + if (i < asf->nb_streams) { + av_packet_unref(&asf->asf_st[i]->pkt.avpkt); + av_freep(&asf->asf_st[i]); + } } + asf->nb_streams = 0; return 0; } @@ -1466,7 +1545,6 @@ static void reset_packet_state(AVFormatContext *s) asf->nb_sub = 0; asf->prop_flags = 0; asf->sub_dts = 0; - asf->dts = 0; for (i = 0; i < asf->nb_streams; i++) { ASFPacket *pkt = &asf->asf_st[i]->pkt; pkt->size_left = 0; @@ -1475,7 +1553,7 @@ static void reset_packet_state(AVFormatContext *s) pkt->flags = 0; pkt->dts = 0; pkt->duration = 0; - av_free_packet(&pkt->avpkt); + av_packet_unref(&pkt->avpkt); av_init_packet(&pkt->avpkt); } } @@ -1542,11 +1620,11 @@ static int64_t asf_read_timestamp(AVFormatContext *s, int stream_index, } if (st_found) break; - av_free_packet(&pkt); + av_packet_unref(&pkt); } *pos = pkt_pos; - av_free_packet(&pkt); + av_packet_unref(&pkt); return dts; } @@ -1641,33 +1719,37 @@ static int asf_read_header(AVFormatContext *s) */ while (1) { // for the cases when object size is invalid - if (avio_tell(pb) == asf->offset) { - if (asf->data_reached) - avio_seek(pb, asf->first_packet_offset, SEEK_SET); + if (avio_tell(pb) == asf->offset) break; - } asf->offset = avio_tell(pb); if ((ret = ff_get_guid(pb, &guid)) < 0) { - if (ret == AVERROR_EOF && asf->data_reached) { - avio_seek(pb, asf->first_packet_offset, SEEK_SET); + if (ret == AVERROR_EOF && asf->data_reached) break; - } else - return ret; + else + goto failed; } g = find_guid(guid); if (g) { asf->unknown_offset = asf->offset; asf->is_header = 1; if ((ret = g->read_object(s, g)) < 0) - return ret; + goto failed; } else { size = avio_rl64(pb); align_position(pb, asf->offset, size); } - if (asf->data_reached && !pb->seekable) + if (asf->data_reached && (!pb->seekable || (asf->b_flags & ASF_FLAG_BROADCAST))) break; } + if (!asf->data_reached) { + av_log(s, AV_LOG_ERROR, "Data Object was not found.\n"); + ret = AVERROR_INVALIDDATA; + goto failed; + } + if (pb->seekable) + avio_seek(pb, asf->first_packet_offset, SEEK_SET); + for (i = 0; i < asf->nb_streams; i++) { const char *rfc1766 = asf->asf_sd[asf->asf_st[i]->lang_idx].langs; AVStream *st = s->streams[asf->asf_st[i]->index]; @@ -1688,6 +1770,10 @@ static int asf_read_header(AVFormatContext *s) } return 0; + +failed: + asf_read_close(s); + return ret; } AVInputFormat ff_asf_demuxer = {