X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fasfdec.c;h=e1f33317740302c0cbc23ba595281467c0143b95;hb=6ac6e3d1237475427ecc448d6cb2d67617687997;hp=7f254d096b21ddf054f0cc32c6ccb86c4359cb56;hpb=277a28e8fc39cdc8bc69ed11532205f6f92a66ad;p=ffmpeg diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c index 7f254d096b2..e1f33317740 100644 --- a/libavformat/asfdec.c +++ b/libavformat/asfdec.c @@ -35,6 +35,7 @@ void ff_mms_set_stream_selection(URLContext *h, AVFormatContext *format); #undef NDEBUG #include +#define ASF_MAX_STREAMS 127 #define FRAME_HEADER_SIZE 17 // Fix Me! FRAME_HEADER_SIZE may be different. @@ -82,6 +83,7 @@ static void print_guid(const ff_asf_guid *g) else PRINT_IF_GUID(g, ff_asf_ext_stream_embed_stream_header); else PRINT_IF_GUID(g, ff_asf_ext_stream_audio_stream); else PRINT_IF_GUID(g, ff_asf_metadata_header); + else PRINT_IF_GUID(g, ff_asf_marker_header); else PRINT_IF_GUID(g, stream_bitrate_guid); else PRINT_IF_GUID(g, ff_asf_language_guid); else @@ -122,9 +124,12 @@ static void get_str16(ByteIOContext *pb, char *buf, int buf_size) static void get_str16_nolen(ByteIOContext *pb, int len, char *buf, int buf_size) { char* q = buf; - for (; len > 1; len -= 2) { + while (len > 1) { uint8_t tmp; - PUT_UTF8(get_le16(pb), tmp, if (q - buf < buf_size - 1) *q++ = tmp;) + uint32_t ch; + + GET_UTF16(ch, (len -= 2) >= 0 ? get_le16(pb) : 0, break;) + PUT_UTF8(ch, tmp, if (q - buf < buf_size - 1) *q++ = tmp;) } if (len > 0) url_fskip(pb, len); @@ -152,19 +157,28 @@ static int get_value(ByteIOContext *pb, int type){ static void get_tag(AVFormatContext *s, const char *key, int type, int len) { - char value[1024]; - if (type <= 1) { // unicode or byte - get_str16_nolen(s->pb, len, value, sizeof(value)); - } else if (type <= 5) { // boolean or DWORD or QWORD or WORD + char *value; + + if ((unsigned)len >= (UINT_MAX - 1)/2) + return; + + value = av_malloc(2*len+1); + if (!value) + return; + + if (type == 0) { // UTF16-LE + get_str16_nolen(s->pb, len, value, 2*len + 1); + } else if (type > 1 && type <= 5) { // boolean or DWORD or QWORD or WORD uint64_t num = get_value(s->pb, type); - snprintf(value, sizeof(value), "%"PRIu64, num); + snprintf(value, len, "%"PRIu64, num); } else { url_fskip(s->pb, len); + av_freep(&value); + av_log(s, AV_LOG_DEBUG, "Unsupported value type %d in tag %s.\n", type, key); return; } - if (!strncmp(key, "WM/", 3)) - key += 3; - av_metadata_set(&s->metadata, key, value); + av_metadata_set2(&s->metadata, key, value, 0); + av_freep(&value); } static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) @@ -191,9 +205,10 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) get_byte(pb); memset(&asf->asfid2avid, -1, sizeof(asf->asfid2avid)); for(;;) { + uint64_t gpos= url_ftell(pb); get_guid(pb, &g); gsize = get_le64(pb); - dprintf(s, "%08"PRIx64": ", url_ftell(pb) - 24); + dprintf(s, "%08"PRIx64": ", gpos); print_guid(&g); dprintf(s, " size=0x%"PRIx64"\n", gsize); if (!guidcmp(&g, &ff_asf_data_header)) { @@ -221,15 +236,20 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) asf->hdr.min_pktsize = get_le32(pb); asf->hdr.max_pktsize = get_le32(pb); asf->hdr.max_bitrate = get_le32(pb); - asf->packet_size = asf->hdr.max_pktsize; + s->packet_size = asf->hdr.max_pktsize; } else if (!guidcmp(&g, &ff_asf_stream_header)) { - enum CodecType type; + enum AVMediaType type; int type_specific_size, sizeX; uint64_t total_size; unsigned int tag1; int64_t pos1, pos2, start_time; int test_for_ext_stream_audio, is_dvr_ms_audio=0; + if (s->nb_streams == ASF_MAX_STREAMS) { + av_log(s, AV_LOG_ERROR, "too many streams\n"); + return AVERROR(EINVAL); + } + pos1 = url_ftell(pb); st = av_new_stream(s, 0); @@ -245,21 +265,24 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) asf_st->stream_language_index = 128; // invalid stream index means no language info if(!(asf->hdr.flags & 0x01)) { // if we aren't streaming... - st->duration = asf->hdr.send_time / + st->duration = asf->hdr.play_time / (10000000 / 1000) - start_time; } get_guid(pb, &g); test_for_ext_stream_audio = 0; if (!guidcmp(&g, &ff_asf_audio_stream)) { - type = CODEC_TYPE_AUDIO; + type = AVMEDIA_TYPE_AUDIO; } else if (!guidcmp(&g, &ff_asf_video_stream)) { - type = CODEC_TYPE_VIDEO; + type = AVMEDIA_TYPE_VIDEO; + } else if (!guidcmp(&g, &ff_asf_jfif_media)) { + type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = CODEC_ID_MJPEG; } else if (!guidcmp(&g, &ff_asf_command_stream)) { - type = CODEC_TYPE_DATA; + type = AVMEDIA_TYPE_DATA; } else if (!guidcmp(&g, &ff_asf_ext_stream_embed_stream_header)) { test_for_ext_stream_audio = 1; - type = CODEC_TYPE_UNKNOWN; + type = AVMEDIA_TYPE_UNKNOWN; } else { return -1; } @@ -276,7 +299,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) if (test_for_ext_stream_audio) { get_guid(pb, &g); if (!guidcmp(&g, &ff_asf_ext_stream_audio_stream)) { - type = CODEC_TYPE_AUDIO; + type = AVMEDIA_TYPE_AUDIO; is_dvr_ms_audio=1; get_guid(pb, &g); get_le32(pb); @@ -288,8 +311,8 @@ 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); + if (type == AVMEDIA_TYPE_AUDIO) { + ff_get_wav_header(pb, st->codec, type_specific_size); if (is_dvr_ms_audio) { // codec_id and codec_tag are unreliable in dvr_ms // files. Set them later by probing stream. @@ -338,7 +361,8 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec->frame_size = 1; break; } - } else if (type == CODEC_TYPE_VIDEO) { + } else if (type == AVMEDIA_TYPE_VIDEO && + gsize - (url_ftell(pb) - pos1 + 24) >= 51) { get_le32(pb); get_le32(pb); get_byte(pb); @@ -364,9 +388,9 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) /* This is true for all paletted codecs implemented in ffmpeg */ if (st->codec->extradata_size && (st->codec->bits_per_coded_sample <= 8)) { st->codec->palctrl = av_mallocz(sizeof(AVPaletteControl)); -#ifdef WORDS_BIGENDIAN +#if HAVE_BIGENDIAN for (i = 0; i < FFMIN(st->codec->extradata_size, AVPALETTE_SIZE)/4; i++) - st->codec->palctrl->palette[i] = bswap_32(((uint32_t*)st->codec->extradata)[i]); + st->codec->palctrl->palette[i] = av_bswap32(((uint32_t*)st->codec->extradata)[i]); #else memcpy(st->codec->palctrl->palette, st->codec->extradata, FFMIN(st->codec->extradata_size, AVPALETTE_SIZE)); @@ -375,9 +399,17 @@ 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->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag1); + if(tag1 == MKTAG('D', 'V', 'R', ' ')){ st->need_parsing = AVSTREAM_PARSE_FULL; + // issue658 containse wrong w/h and MS even puts a fake seq header with wrong w/h in extradata while a correct one is in te stream. maximum lameness + st->codec->width = + st->codec->height = 0; + av_freep(&st->codec->extradata); + st->codec->extradata_size=0; + } + if(st->codec->codec_id == CODEC_ID_H264) + st->need_parsing = AVSTREAM_PARSE_FULL_ONCE; } pos2 = url_ftell(pb); url_fskip(pb, gsize - (pos2 - pos1 + 24)); @@ -428,10 +460,22 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) char name[1024]; name_len = get_le16(pb); + if (name_len%2) // must be even, broken lavf versions wrote len-1 + name_len += 1; get_str16_nolen(pb, name_len, name, sizeof(name)); value_type = get_le16(pb); value_len = get_le16(pb); - get_tag(s, name, value_type, value_len); + if (!value_type && value_len%2) + value_len += 1; + /** + * My sample has that stream set to 0 maybe that mean the container. + * Asf stream count start at 1. I am using 0 to the container value since it's unused + */ + if (!strcmp(name, "AspectRatioX")){ + dar[0].num= get_value(s->pb, value_type); + } else if(!strcmp(name, "AspectRatioY")){ + dar[0].den= get_value(s->pb, value_type); + } else get_tag(s, name, value_type, value_len); } } else if (!guidcmp(&g, &ff_asf_metadata_header)) { int n, stream_num, name_len, value_len, value_type, value_num; @@ -499,11 +543,39 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) // there could be a optional stream properties object to follow // if so the next iteration will pick it up + continue; } else if (!guidcmp(&g, &ff_asf_head1_guid)) { int v1, v2; get_guid(pb, &g); v1 = get_le32(pb); v2 = get_le16(pb); + continue; + } else if (!guidcmp(&g, &ff_asf_marker_header)) { + int i, count, name_len; + char name[1024]; + + get_le64(pb); // reserved 16 bytes + get_le64(pb); // ... + count = get_le32(pb); // markers count + get_le16(pb); // reserved 2 bytes + name_len = get_le16(pb); // name length + for(i=0;ikeylen) { + if (!guidcmp(&g, &ff_asf_content_encryption)) { + av_log(s, AV_LOG_WARNING, "DRM protected stream detected, decoding will likely fail!\n"); + } else if (!guidcmp(&g, &ff_asf_ext_content_encryption)) { + av_log(s, AV_LOG_WARNING, "Ext DRM protected stream detected, decoding will likely fail!\n"); + } else if (!guidcmp(&g, &ff_asf_digital_signature)) { + av_log(s, AV_LOG_WARNING, "Digital signature detected, decoding will likely fail!\n"); + } + } } + if(url_ftell(pb) != gpos + gsize) + av_log(s, AV_LOG_DEBUG, "gpos mismatch our pos=%"PRIu64", end=%"PRIu64"\n", url_ftell(pb)-gpos, gsize); + url_fseek(pb, gpos + gsize, SEEK_SET); } get_guid(pb, &g); get_le64(pb); @@ -551,11 +634,16 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) 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) + if (dar[i].num > 0 && dar[i].den > 0){ av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den, dar[i].num, dar[i].den, INT_MAX); -//av_log(s, 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); + } else if ((dar[0].num > 0) && (dar[0].den > 0) && (st->codec->codec_type==CODEC_TYPE_VIDEO)) // Use ASF container value if the stream doesn't AR set. + av_reduce(&st->sample_aspect_ratio.num, + &st->sample_aspect_ratio.den, + dar[0].num, dar[0].den, INT_MAX); + +//av_log(s, AV_LOG_INFO, "i=%d, st->codec->codec_type:%d, dar %d:%d sar=%d:%d\n", i, st->codec->codec_type, dar[i].num, dar[i].den, st->sample_aspect_ratio.num, st->sample_aspect_ratio.den); // copy and convert language codes to the frontend if (asf->streams[i].stream_language_index < 128) { @@ -564,7 +652,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) const char primary_tag[3] = { rfc1766[0], rfc1766[1], '\0' }; // ignore country code if any const char *iso6392 = av_convert_lang_to(primary_tag, AV_LANG_ISO639_2_BIBL); if (iso6392) - av_metadata_set(&st->metadata, "language", iso6392); + av_metadata_set2(&st->metadata, "language", iso6392, 0); } } } @@ -586,7 +674,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) * Load a single ASF packet into the demuxer. * @param s demux context * @param pb context to read data from - * @returns 0 on success, <0 on error + * @return 0 on success, <0 on error */ static int ff_asf_get_packet(AVFormatContext *s, ByteIOContext *pb) { @@ -595,7 +683,10 @@ static int ff_asf_get_packet(AVFormatContext *s, ByteIOContext *pb) int rsize = 8; int c, d, e, off; - off= (url_ftell(pb) - s->data_offset) % asf->packet_size + 3; + // if we do not know packet size, allow skipping up to 32 kB + off= 32768; + if (s->packet_size > 0) + off= (url_ftell(pb) - s->data_offset) % s->packet_size + 3; c=d=e=-1; while(off-- > 0){ @@ -606,6 +697,14 @@ static int ff_asf_get_packet(AVFormatContext *s, ByteIOContext *pb) } if (c != 0x82) { + /** + * This code allows handling of -EAGAIN at packet boundaries (i.e. + * if the packet sync code above triggers -EAGAIN). This does not + * imply complete -EAGAIN handling support at random positions in + * the stream. + */ + if (url_ferror(pb) == AVERROR(EAGAIN)) + return AVERROR(EAGAIN); if (!url_feof(pb)) av_log(s, AV_LOG_ERROR, "ff asf bad header %x at:%"PRId64"\n", c, url_ftell(pb)); } @@ -625,12 +724,12 @@ static int ff_asf_get_packet(AVFormatContext *s, ByteIOContext *pb) asf->packet_flags = c; asf->packet_property = d; - DO_2BITS(asf->packet_flags >> 5, packet_length, asf->packet_size); + DO_2BITS(asf->packet_flags >> 5, packet_length, s->packet_size); DO_2BITS(asf->packet_flags >> 1, padsize, 0); // sequence ignored DO_2BITS(asf->packet_flags >> 3, padsize, 0); // padding length //the following checks prevent overflows and infinite loops - if(packet_length >= (1U<<29)){ + if(!packet_length || packet_length >= (1U<<29)){ av_log(s, AV_LOG_ERROR, "invalid packet_length %d at:%"PRId64"\n", packet_length, url_ftell(pb)); return -1; } @@ -654,7 +753,7 @@ static int ff_asf_get_packet(AVFormatContext *s, ByteIOContext *pb) if (packet_length < asf->hdr.min_pktsize) padsize += asf->hdr.min_pktsize - packet_length; asf->packet_padsize = padsize; - dprintf(s, "packet: size=%d padsize=%d left=%d\n", asf->packet_size, asf->packet_padsize, asf->packet_size_left); + dprintf(s, "packet: size=%d padsize=%d left=%d\n", s->packet_size, asf->packet_padsize, asf->packet_size_left); return 0; } @@ -738,7 +837,7 @@ static int asf_read_frame_header(AVFormatContext *s, ByteIOContext *pb){ * @param s demux context * @param pb context to read data from * @param pkt pointer to store packet data into - * @returns 0 if data was stored in pkt, <0 on error or 1 if more ASF + * @return 0 if data was stored in pkt, <0 on error or 1 if more ASF * packets need to be loaded (through asf_get_packet()) */ static int ff_asf_parse_packet(AVFormatContext *s, ByteIOContext *pb, AVPacket *pkt) @@ -825,17 +924,17 @@ static int ff_asf_parse_packet(AVFormatContext *s, ByteIOContext *pb, AVPacket * asf_st->pkt.pos = asf_st->packet_pos= asf->packet_pos; //printf("new packet: stream:%d key:%d packet_key:%d audio:%d size:%d\n", -//asf->stream_index, asf->packet_key_frame, asf_st->pkt.flags & PKT_FLAG_KEY, -//s->streams[asf->stream_index]->codec->codec_type == CODEC_TYPE_AUDIO, asf->packet_obj_size); - if (s->streams[asf->stream_index]->codec->codec_type == CODEC_TYPE_AUDIO) +//asf->stream_index, asf->packet_key_frame, asf_st->pkt.flags & AV_PKT_FLAG_KEY, +//s->streams[asf->stream_index]->codec->codec_type == AVMEDIA_TYPE_AUDIO, asf->packet_obj_size); + if (s->streams[asf->stream_index]->codec->codec_type == AVMEDIA_TYPE_AUDIO) asf->packet_key_frame = 1; if (asf->packet_key_frame) - asf_st->pkt.flags |= PKT_FLAG_KEY; + asf_st->pkt.flags |= AV_PKT_FLAG_KEY; } /* read data */ //printf("READ PACKET s:%d os:%d o:%d,%d l:%d DATA:%p\n", - // asf->packet_size, asf_st->pkt.size, asf->packet_frag_offset, + // s->packet_size, asf_st->pkt.size, asf->packet_frag_offset, // asf_st->frag_offset, asf->packet_frag_size, asf_st->pkt.data); asf->packet_size_left -= asf->packet_frag_size; if (asf->packet_size_left < 0) @@ -978,19 +1077,19 @@ static int asf_read_close(AVFormatContext *s) static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit) { - ASFContext *asf = s->priv_data; AVPacket pkt1, *pkt = &pkt1; ASFStream *asf_st; int64_t pts; int64_t pos= *ppos; int i; - int64_t start_pos[s->nb_streams]; + int64_t start_pos[ASF_MAX_STREAMS]; for(i=0; inb_streams; i++){ start_pos[i]= pos; } - pos= (pos+asf->packet_size-1-s->data_offset)/asf->packet_size*asf->packet_size+ s->data_offset; + if (s->packet_size > 0) + pos= (pos+s->packet_size-1-s->data_offset)/s->packet_size*s->packet_size+ s->data_offset; *ppos= pos; url_fseek(s->pb, pos, SEEK_SET); @@ -1005,12 +1104,12 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, pts= pkt->pts; av_free_packet(pkt); - if(pkt->flags&PKT_FLAG_KEY){ + if(pkt->flags&AV_PKT_FLAG_KEY){ i= pkt->stream_index; asf_st= s->streams[i]->priv_data; -// assert((asf_st->packet_pos - s->data_offset) % asf->packet_size == 0); +// assert((asf_st->packet_pos - s->data_offset) % s->packet_size == 0); pos= asf_st->packet_pos; av_add_index_entry(s->streams[i], pos, pts, pkt->size, pos - start_pos[i] + 1, AVINDEX_KEYFRAME); @@ -1037,7 +1136,7 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index) url_fseek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET); get_guid(s->pb, &g); if (!guidcmp(&g, &index_guid)) { - int64_t itime; + int64_t itime, last_pos=-1; int pct, ict; int64_t av_unused gsize= get_le64(s->pb); get_guid(s->pb, &g); @@ -1049,11 +1148,14 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index) for (i=0;ipb); int pktct =get_le16(s->pb); - int64_t pos = s->data_offset + asf->packet_size*(int64_t)pktnum; + int64_t pos = s->data_offset + s->packet_size*(int64_t)pktnum; int64_t index_pts= av_rescale(itime, i, 10000); + if(pos != last_pos){ av_log(s, AV_LOG_DEBUG, "pktnum:%d, pktct:%d\n", pktnum, pktct); - av_add_index_entry(s->streams[stream_index], pos, index_pts, asf->packet_size, 0, AVINDEX_KEYFRAME); + av_add_index_entry(s->streams[stream_index], pos, index_pts, s->packet_size, 0, AVINDEX_KEYFRAME); + last_pos=pos; + } } asf->index_read= 1; } @@ -1067,7 +1169,7 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int int64_t pos; int index; - if (asf->packet_size <= 0) + if (s->packet_size <= 0) return -1; /* Try using the protocol's read_seek if available */