+ ff_asf_guid g;
+ enum AVMediaType type;
+ int type_specific_size, sizeX;
+ 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 = avio_tell(pb);
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
+ asf_st = av_mallocz(sizeof(ASFStream));
+ if (!asf_st)
+ return AVERROR(ENOMEM);
+ st->priv_data = asf_st;
+ st->start_time = 0;
+ start_time = asf->hdr.preroll;
+
+ 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.play_time /
+ (10000000 / 1000) - start_time;
+ }
+ ff_get_guid(pb, &g);
+
+ test_for_ext_stream_audio = 0;
+ if (!ff_guidcmp(&g, &ff_asf_audio_stream)) {
+ type = AVMEDIA_TYPE_AUDIO;
+ } else if (!ff_guidcmp(&g, &ff_asf_video_stream)) {
+ type = AVMEDIA_TYPE_VIDEO;
+ } else if (!ff_guidcmp(&g, &ff_asf_jfif_media)) {
+ type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_MJPEG;
+ } else if (!ff_guidcmp(&g, &ff_asf_command_stream)) {
+ type = AVMEDIA_TYPE_DATA;
+ } else if (!ff_guidcmp(&g, &ff_asf_ext_stream_embed_stream_header)) {
+ test_for_ext_stream_audio = 1;
+ type = AVMEDIA_TYPE_UNKNOWN;
+ } else {
+ return -1;
+ }
+ ff_get_guid(pb, &g);
+ avio_skip(pb, 8); /* total_size */
+ type_specific_size = avio_rl32(pb);
+ avio_rl32(pb);
+ st->id = avio_rl16(pb) & 0x7f; /* stream id */
+ // mapping of asf ID to AV stream ID;
+ asf->asfid2avid[st->id] = s->nb_streams - 1;
+
+ avio_rl32(pb);
+
+ if (test_for_ext_stream_audio) {
+ ff_get_guid(pb, &g);
+ if (!ff_guidcmp(&g, &ff_asf_ext_stream_audio_stream)) {
+ type = AVMEDIA_TYPE_AUDIO;
+ is_dvr_ms_audio = 1;
+ ff_get_guid(pb, &g);
+ avio_rl32(pb);
+ avio_rl32(pb);
+ avio_rl32(pb);
+ ff_get_guid(pb, &g);
+ avio_rl32(pb);
+ }
+ }
+
+ st->codec->codec_type = type;
+ if (type == AVMEDIA_TYPE_AUDIO) {
+ int ret = ff_get_wav_header(pb, st->codec, type_specific_size);
+ if (ret < 0)
+ return ret;
+ 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 = AV_CODEC_ID_PROBE;
+ st->codec->codec_tag = 0;
+ }
+ if (st->codec->codec_id == AV_CODEC_ID_AAC)
+ st->need_parsing = AVSTREAM_PARSE_NONE;
+ else
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+ /* We have to init the frame size at some point .... */
+ pos2 = avio_tell(pb);
+ if (size >= (pos2 + 8 - pos1 + 24)) {
+ asf_st->ds_span = avio_r8(pb);
+ asf_st->ds_packet_size = avio_rl16(pb);
+ asf_st->ds_chunk_size = avio_rl16(pb);
+ avio_rl16(pb); // ds_data_size
+ avio_r8(pb); // ds_silence_data
+ }
+ if (asf_st->ds_span > 1) {
+ if (!asf_st->ds_chunk_size ||
+ (asf_st->ds_packet_size / asf_st->ds_chunk_size <= 1) ||
+ asf_st->ds_packet_size % asf_st->ds_chunk_size)
+ asf_st->ds_span = 0; // disable descrambling
+ }
+ } else if (type == AVMEDIA_TYPE_VIDEO &&
+ size - (avio_tell(pb) - pos1 + 24) >= 51) {
+ avio_rl32(pb);
+ avio_rl32(pb);
+ avio_r8(pb);
+ avio_rl16(pb); /* size */
+ sizeX = avio_rl32(pb); /* size */
+ st->codec->width = avio_rl32(pb);
+ st->codec->height = avio_rl32(pb);
+ /* not available for asf */
+ avio_rl16(pb); /* panes */
+ st->codec->bits_per_coded_sample = avio_rl16(pb); /* depth */
+ tag1 = avio_rl32(pb);
+ avio_skip(pb, 20);
+ if (sizeX > 40) {
+ st->codec->extradata_size = sizeX - 40;
+ st->codec->extradata = av_mallocz(st->codec->extradata_size +
+ FF_INPUT_BUFFER_PADDING_SIZE);
+ avio_read(pb, st->codec->extradata, st->codec->extradata_size);
+ }
+
+ /* Extract palette from extradata if bpp <= 8 */
+ /* This code assumes that extradata contains only palette */
+ /* This is true for all paletted codecs implemented in libavcodec */
+ if (st->codec->extradata_size && (st->codec->bits_per_coded_sample <= 8)) {
+#if HAVE_BIGENDIAN
+ int i;
+ for (i = 0; i < FFMIN(st->codec->extradata_size, AVPALETTE_SIZE) / 4; i++)
+ asf_st->palette[i] = av_bswap32(((uint32_t *)st->codec->extradata)[i]);
+#else
+ memcpy(asf_st->palette, st->codec->extradata,
+ FFMIN(st->codec->extradata_size, AVPALETTE_SIZE));
+#endif
+ asf_st->palette_changed = 1;
+ }
+
+ st->codec->codec_tag = tag1;
+ 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 contains wrong w/h and MS even puts a fake seq header
+ * with wrong w/h in extradata while a correct one is in the 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 == AV_CODEC_ID_H264)
+ st->need_parsing = AVSTREAM_PARSE_FULL_ONCE;
+ }
+ pos2 = avio_tell(pb);
+ avio_skip(pb, size - (pos2 - pos1 + 24));
+
+ return 0;
+}
+
+static int asf_read_ext_stream_properties(AVFormatContext *s, int64_t size)
+{
+ ASFContext *asf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ ff_asf_guid g;
+ int ext_len, payload_ext_ct, stream_ct, i;
+ uint32_t leak_rate, stream_num;
+ unsigned int stream_languageid_index;
+
+ avio_rl64(pb); // starttime
+ avio_rl64(pb); // endtime
+ leak_rate = avio_rl32(pb); // leak-datarate
+ avio_rl32(pb); // bucket-datasize
+ avio_rl32(pb); // init-bucket-fullness
+ avio_rl32(pb); // alt-leak-datarate
+ avio_rl32(pb); // alt-bucket-datasize
+ avio_rl32(pb); // alt-init-bucket-fullness
+ avio_rl32(pb); // max-object-size
+ avio_rl32(pb); // flags (reliable,seekable,no_cleanpoints?,resend-live-cleanpoints, rest of bits reserved)
+ stream_num = avio_rl16(pb); // stream-num
+
+ stream_languageid_index = avio_rl16(pb); // stream-language-id-index
+ if (stream_num < 128)
+ asf->streams[stream_num].stream_language_index = stream_languageid_index;
+
+ avio_rl64(pb); // avg frametime in 100ns units
+ stream_ct = avio_rl16(pb); // stream-name-count
+ payload_ext_ct = avio_rl16(pb); // payload-extension-system-count
+
+ if (stream_num < 128)
+ asf->stream_bitrates[stream_num] = leak_rate;
+
+ for (i = 0; i < stream_ct; i++) {
+ avio_rl16(pb);
+ ext_len = avio_rl16(pb);
+ avio_skip(pb, ext_len);
+ }
+
+ for (i = 0; i < payload_ext_ct; i++) {
+ ff_get_guid(pb, &g);
+ avio_skip(pb, 2);
+ ext_len = avio_rl32(pb);
+ avio_skip(pb, ext_len);
+ }
+
+ return 0;
+}
+
+static int asf_read_content_desc(AVFormatContext *s, int64_t size)
+{
+ AVIOContext *pb = s->pb;
+ int len1, len2, len3, len4, len5;
+
+ len1 = avio_rl16(pb);
+ len2 = avio_rl16(pb);
+ len3 = avio_rl16(pb);
+ len4 = avio_rl16(pb);
+ len5 = avio_rl16(pb);
+ get_tag(s, "title", 0, len1, 32);
+ get_tag(s, "author", 0, len2, 32);
+ get_tag(s, "copyright", 0, len3, 32);
+ get_tag(s, "comment", 0, len4, 32);
+ avio_skip(pb, len5);
+
+ return 0;
+}
+
+static int asf_read_ext_content_desc(AVFormatContext *s, int64_t size)
+{
+ AVIOContext *pb = s->pb;
+ ASFContext *asf = s->priv_data;
+ int desc_count, i, ret;
+
+ desc_count = avio_rl16(pb);
+ for (i = 0; i < desc_count; i++) {
+ int name_len, value_type, value_len;
+ char name[1024];
+
+ name_len = avio_rl16(pb);
+ if (name_len % 2) // must be even, broken lavf versions wrote len-1
+ name_len += 1;
+ if ((ret = avio_get_str16le(pb, name_len, name, sizeof(name))) < name_len)
+ avio_skip(pb, name_len - ret);
+ value_type = avio_rl16(pb);
+ value_len = avio_rl16(pb);
+ 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 starts at 1. I am using 0 to the container value
+ * since it's unused. */
+ if (!strcmp(name, "AspectRatioX"))
+ asf->dar[0].num = get_value(s->pb, value_type, 32);
+ else if (!strcmp(name, "AspectRatioY"))
+ asf->dar[0].den = get_value(s->pb, value_type, 32);
+ else
+ get_tag(s, name, value_type, value_len, 32);
+ }
+
+ return 0;
+}
+
+static int asf_read_language_list(AVFormatContext *s, int64_t size)
+{
+ AVIOContext *pb = s->pb;
+ ASFContext *asf = s->priv_data;
+ int j, ret;
+ int stream_count = avio_rl16(pb);
+ for (j = 0; j < stream_count; j++) {
+ char lang[6];
+ unsigned int lang_len = avio_r8(pb);
+ if ((ret = avio_get_str16le(pb, lang_len, lang,
+ sizeof(lang))) < lang_len)
+ avio_skip(pb, lang_len - ret);
+ if (j < 128)
+ av_strlcpy(asf->stream_languages[j], lang,
+ sizeof(*asf->stream_languages));
+ }