Merge commit '5f408333601a827054335f309defcb246a532b21'
[ffmpeg.git] / libavformat / asfdec.c
index b99cb02..72865c1 100644 (file)
@@ -2,20 +2,20 @@
  * ASF compatible demuxer
  * Copyright (c) 2000, 2001 Fabrice Bellard
  *
- * This file is part of Libav.
+ * This file is part of FFmpeg.
  *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
@@ -68,7 +68,6 @@ typedef struct {
     unsigned int packet_frag_size;
     int64_t packet_frag_timestamp;
     int packet_multi_size;
-    int packet_obj_size;
     int packet_time_delta;
     int packet_time_start;
     int64_t packet_pos;
@@ -96,12 +95,8 @@ static const AVClass asf_class = {
 #include <assert.h>
 
 #define ASF_MAX_STREAMS 127
-#define FRAME_HEADER_SIZE 17
-// Fix Me! FRAME_HEADER_SIZE may be different.
-
-static const ff_asf_guid index_guid = {
-    0x90, 0x08, 0x00, 0x33, 0xb1, 0xe5, 0xcf, 0x11, 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb
-};
+#define FRAME_HEADER_SIZE 16
+// Fix Me! FRAME_HEADER_SIZE may be different. (17 is known to be too large)
 
 #ifdef DEBUG
 static const ff_asf_guid stream_bitrate_guid = { /* (http://get.to/sdp) */
@@ -127,7 +122,7 @@ static void print_guid(ff_asf_guid *g)
     else PRINT_IF_GUID(g, ff_asf_codec_comment_header);
     else PRINT_IF_GUID(g, ff_asf_codec_comment1_header);
     else PRINT_IF_GUID(g, ff_asf_data_header);
-    else PRINT_IF_GUID(g, index_guid);
+    else PRINT_IF_GUID(g, ff_asf_simple_index_header);
     else PRINT_IF_GUID(g, ff_asf_head1_guid);
     else PRINT_IF_GUID(g, ff_asf_head2_guid);
     else PRINT_IF_GUID(g, ff_asf_my_guid);
@@ -281,16 +276,20 @@ static void get_tag(AVFormatContext *s, const char *key, int type, int len, int
 {
     char *value;
     int64_t off = avio_tell(s->pb);
+#define LEN 22
 
-    if ((unsigned)len >= (UINT_MAX - 1) / 2)
+    if ((unsigned)len >= (UINT_MAX - LEN) / 2)
         return;
 
-    value = av_malloc(2 * len + 1);
+    value = av_malloc(2 * len + LEN);
     if (!value)
         goto finish;
 
     if (type == 0) {         // UTF16-LE
         avio_get_str16le(s->pb, len, value, 2 * len + 1);
+    } else if (type == -1) { // ASCII
+        avio_read(s->pb, value, len);
+        value[len]=0;
     } else if (type == 1) {  // byte array
         if (!strcmp(key, "WM/Picture")) { // handle cover art
             asf_read_picture(s, len);
@@ -302,7 +301,7 @@ static void get_tag(AVFormatContext *s, const char *key, int type, int len, int
         goto finish;
     } else if (type > 1 && type <= 5) {  // boolean or DWORD or QWORD or WORD
         uint64_t num = get_value(s->pb, type, type2_size);
-        snprintf(value, len, "%"PRIu64, num);
+        snprintf(value, LEN, "%"PRIu64, num);
     } else if (type == 6) { // (don't) handle GUID
         av_log(s, AV_LOG_DEBUG, "Unsupported GUID value in tag %s.\n", key);
         goto finish;
@@ -367,17 +366,12 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
     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 /
+        int64_t fsize = avio_size(pb);
+        if (fsize <= 0 || (int64_t)asf->hdr.file_size <= 0 || FFABS(fsize - (int64_t)asf->hdr.file_size) < 10000)
+            st->duration = asf->hdr.play_time /
                        (10000000 / 1000) - start_time;
     }
     ff_get_guid(pb, &g);
@@ -405,6 +399,7 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
     st->id = avio_rl16(pb) & 0x7f; /* stream id */
     // mapping of asf ID to AV stream ID;
     asf->asfid2avid[st->id] = s->nb_streams - 1;
+    asf_st = &asf->streams[st->id];
 
     avio_rl32(pb);
 
@@ -430,7 +425,7 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
         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->request_probe    = 1;
             st->codec->codec_tag = 0;
         }
         if (st->codec->codec_id == AV_CODEC_ID_AAC)
@@ -467,9 +462,11 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
         tag1                             = avio_rl32(pb);
         avio_skip(pb, 20);
         if (sizeX > 40) {
-            st->codec->extradata_size = sizeX - 40;
+            st->codec->extradata_size = ffio_limit(pb, sizeX - 40);
             st->codec->extradata      = av_mallocz(st->codec->extradata_size +
                                                    FF_INPUT_BUFFER_PADDING_SIZE);
+            if (!st->codec->extradata)
+                return AVERROR(ENOMEM);
             avio_read(pb, st->codec->extradata, st->codec->extradata_size);
         }
 
@@ -538,8 +535,10 @@ static int asf_read_ext_stream_properties(AVFormatContext *s, int64_t size)
     stream_ct      = avio_rl16(pb); // stream-name-count
     payload_ext_ct = avio_rl16(pb); // payload-extension-system-count
 
-    if (stream_num < 128)
+    if (stream_num < 128) {
         asf->stream_bitrates[stream_num] = leak_rate;
+        asf->streams[stream_num].payload_ext_ct = 0;
+    }
 
     for (i = 0; i < stream_ct; i++) {
         avio_rl16(pb);
@@ -548,10 +547,18 @@ static int asf_read_ext_stream_properties(AVFormatContext *s, int64_t size)
     }
 
     for (i = 0; i < payload_ext_ct; i++) {
+        int size;
         ff_get_guid(pb, &g);
-        avio_skip(pb, 2);
+        size = avio_rl16(pb);
         ext_len = avio_rl32(pb);
         avio_skip(pb, ext_len);
+        if (stream_num < 128 && i < FF_ARRAY_ELEMS(asf->streams[stream_num].payload)) {
+            ASFPayload *p = &asf->streams[stream_num].payload[i];
+            p->type = g[0];
+            p->size = size;
+            av_log(s, AV_LOG_DEBUG, "Payload extension %x %d\n", g[0], p->size );
+            asf->streams[stream_num].payload_ext_ct ++;
+        }
     }
 
     return 0;
@@ -715,12 +722,16 @@ static int asf_read_header(AVFormatContext *s)
 
     ff_get_guid(pb, &g);
     if (ff_guidcmp(&g, &ff_asf_header))
-        return -1;
+        return AVERROR_INVALIDDATA;
     avio_rl64(pb);
     avio_rl32(pb);
     avio_r8(pb);
     avio_r8(pb);
     memset(&asf->asfid2avid, -1, sizeof(asf->asfid2avid));
+
+    for (i = 0; i<128; i++)
+        asf->streams[i].stream_language_index = 128; // invalid stream index means no language info
+
     for (;;) {
         uint64_t gpos = avio_tell(pb);
         ff_get_guid(pb, &g);
@@ -737,7 +748,7 @@ static int asf_read_header(AVFormatContext *s)
             break;
         }
         if (gsize < 24)
-            return -1;
+            return AVERROR_INVALIDDATA;
         if (!ff_guidcmp(&g, &ff_asf_file_header)) {
             int ret = asf_read_file_properties(s, gsize);
             if (ret < 0)
@@ -766,19 +777,30 @@ static int asf_read_header(AVFormatContext *s)
             continue;
         } else if (!ff_guidcmp(&g, &ff_asf_marker_header)) {
             asf_read_marker(s, gsize);
-        } else if (pb->eof_reached) {
-            return -1;
+        } else if (url_feof(pb)) {
+            return AVERROR_EOF;
         } else {
             if (!s->keylen) {
                 if (!ff_guidcmp(&g, &ff_asf_content_encryption)) {
+                    unsigned int len;
+                    AVPacket pkt;
                     av_log(s, AV_LOG_WARNING,
                            "DRM protected stream detected, decoding will likely fail!\n");
+                    len= avio_rl32(pb);
+                    av_log(s, AV_LOG_DEBUG, "Secret data:\n");
+                    av_get_packet(pb, &pkt, len); av_hex_dump_log(s, AV_LOG_DEBUG, pkt.data, pkt.size); av_free_packet(&pkt);
+                    len= avio_rl32(pb);
+                    get_tag(s, "ASF_Protection_Type", -1, len, 32);
+                    len= avio_rl32(pb);
+                    get_tag(s, "ASF_Key_ID", -1, len, 32);
+                    len= avio_rl32(pb);
+                    get_tag(s, "ASF_License_URL", -1, len, 32);
                 } else if (!ff_guidcmp(&g, &ff_asf_ext_content_encryption)) {
                     av_log(s, AV_LOG_WARNING,
                            "Ext DRM protected stream detected, decoding will likely fail!\n");
+                    av_dict_set(&s->metadata, "encryption", "ASF Extended Content Encryption", 0);
                 } else if (!ff_guidcmp(&g, &ff_asf_digital_signature)) {
-                    av_log(s, AV_LOG_WARNING,
-                           "Digital signature detected, decoding will likely fail!\n");
+                    av_log(s, AV_LOG_INFO, "Digital signature detected!\n");
                 }
             }
         }
@@ -792,8 +814,8 @@ static int asf_read_header(AVFormatContext *s)
     avio_rl64(pb);
     avio_r8(pb);
     avio_r8(pb);
-    if (pb->eof_reached)
-        return -1;
+    if (url_feof(pb))
+        return AVERROR_EOF;
     asf->data_offset      = avio_tell(pb);
     asf->packet_size_left = 0;
 
@@ -892,20 +914,20 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb)
          * the stream. */
         if (pb->error == AVERROR(EAGAIN))
             return AVERROR(EAGAIN);
-        if (!pb->eof_reached)
+        if (!url_feof(pb))
             av_log(s, AV_LOG_ERROR,
                    "ff asf bad header %x  at:%"PRId64"\n", c, avio_tell(pb));
     }
     if ((c & 0x8f) == 0x82) {
         if (d || e) {
-            if (!pb->eof_reached)
+            if (!url_feof(pb))
                 av_log(s, AV_LOG_ERROR, "ff asf bad non zero\n");
-            return -1;
+            return AVERROR_INVALIDDATA;
         }
         c      = avio_r8(pb);
         d      = avio_r8(pb);
         rsize += 3;
-    } else if (!pb->eof_reached) {
+    } else if(!url_feof(pb)) {
         avio_seek(pb, -1, SEEK_CUR); // FIXME
     }
 
@@ -921,12 +943,12 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb)
         av_log(s, AV_LOG_ERROR,
                "invalid packet_length %d at:%"PRId64"\n",
                packet_length, avio_tell(pb));
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
     if (padsize >= packet_length) {
         av_log(s, AV_LOG_ERROR,
                "invalid padsize %d at:%"PRId64"\n", padsize, avio_tell(pb));
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
 
     asf->packet_timestamp = avio_rl32(pb);
@@ -946,7 +968,7 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb)
         av_log(s, AV_LOG_ERROR,
                "invalid packet header length %d for pktlen %d-%d at %"PRId64"\n",
                rsize, packet_length, padsize, avio_tell(pb));
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
     asf->packet_size_left = packet_length - padsize - rsize;
     if (packet_length < asf->hdr.min_pktsize)
@@ -964,13 +986,16 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb)
 static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb)
 {
     ASFContext *asf = s->priv_data;
+    ASFStream *asfst;
     int rsize       = 1;
     int num         = avio_r8(pb);
-    int64_t ts0;
+    int i;
+    int64_t ts0, ts1 av_unused;
 
     asf->packet_segments--;
     asf->packet_key_frame = num >> 7;
     asf->stream_index     = asf->asfid2avid[num & 0x7f];
+    asfst                 = &asf->streams[num & 0x7f];
     // sequence should be ignored!
     DO_2BITS(asf->packet_property >> 4, asf->packet_seq, 0);
     DO_2BITS(asf->packet_property >> 2, asf->packet_frag_offset, 0);
@@ -978,26 +1003,62 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb)
     av_dlog(asf, "key:%d stream:%d seq:%d offset:%d replic_size:%d\n",
             asf->packet_key_frame, asf->stream_index, asf->packet_seq,
             asf->packet_frag_offset, asf->packet_replic_size);
+    if (rsize+(int64_t)asf->packet_replic_size > asf->packet_size_left) {
+        av_log(s, AV_LOG_ERROR, "packet_replic_size %d is invalid\n", asf->packet_replic_size);
+        return AVERROR_INVALIDDATA;
+    }
     if (asf->packet_replic_size >= 8) {
-        asf->packet_obj_size = avio_rl32(pb);
-        if (asf->packet_obj_size >= (1 << 24) || asf->packet_obj_size <= 0) {
+        int64_t end = avio_tell(pb) + asf->packet_replic_size;
+        AVRational aspect;
+        asfst->packet_obj_size = avio_rl32(pb);
+        if (asfst->packet_obj_size >= (1 << 24) || asfst->packet_obj_size <= 0) {
             av_log(s, AV_LOG_ERROR, "packet_obj_size invalid\n");
-            return -1;
+            asfst->packet_obj_size = 0;
+            return AVERROR_INVALIDDATA;
         }
         asf->packet_frag_timestamp = avio_rl32(pb); // timestamp
-        if (asf->packet_replic_size >= 8 + 38 + 4) {
-            avio_skip(pb, 10);
-            ts0 = avio_rl64(pb);
-            avio_skip(pb, 8);
-            avio_skip(pb, 12);
-            avio_rl32(pb);
-            avio_skip(pb, asf->packet_replic_size - 8 - 38 - 4);
-            if (ts0 != -1)
-                asf->packet_frag_timestamp = ts0 / 10000;
-            else
-                asf->packet_frag_timestamp = AV_NOPTS_VALUE;
-        } else
-            avio_skip(pb, asf->packet_replic_size - 8);
+
+        for (i = 0; i < asfst->payload_ext_ct; i++) {
+            ASFPayload *p = &asfst->payload[i];
+            int size = p->size;
+            int64_t payend;
+            if (size == 0xFFFF)
+                size = avio_rl16(pb);
+            payend = avio_tell(pb) + size;
+            if (payend > end) {
+                av_log(s, AV_LOG_ERROR, "too long payload\n");
+                break;
+            }
+            switch (p->type) {
+            case 0x50:
+//              duration = avio_rl16(pb);
+                break;
+            case 0x54:
+                aspect.num = avio_r8(pb);
+                aspect.den = avio_r8(pb);
+                if (aspect.num > 0 && aspect.den > 0 && asf->stream_index >= 0) {
+                    s->streams[asf->stream_index]->sample_aspect_ratio = aspect;
+                }
+                break;
+            case 0x2A:
+                avio_skip(pb, 8);
+                ts0 = avio_rl64(pb);
+                ts1 = avio_rl64(pb);
+                if (ts0!= -1) asf->packet_frag_timestamp = ts0/10000;
+                else          asf->packet_frag_timestamp = AV_NOPTS_VALUE;
+                break;
+            case 0x5B:
+            case 0xB7:
+            case 0xCC:
+            case 0xC0:
+            case 0xA0:
+                //unknown
+                break;
+            }
+            avio_seek(pb, payend, SEEK_SET);
+        }
+
+        avio_seek(pb, end, SEEK_SET);
         rsize += asf->packet_replic_size; // FIXME - check validity
     } else if (asf->packet_replic_size == 1) {
         // multipacket - frag_offset is beginning timestamp
@@ -1010,18 +1071,18 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb)
     } else if (asf->packet_replic_size != 0) {
         av_log(s, AV_LOG_ERROR, "unexpected packet_replic_size of %d\n",
                asf->packet_replic_size);
-        return -1;
+        return AVERROR_INVALIDDATA;
     }
     if (asf->packet_flags & 0x01) {
         DO_2BITS(asf->packet_segsizetype >> 6, asf->packet_frag_size, 0); // 0 is illegal
         if (rsize > asf->packet_size_left) {
             av_log(s, AV_LOG_ERROR, "packet_replic_size is invalid\n");
-            return -1;
+            return AVERROR_INVALIDDATA;
         } else if (asf->packet_frag_size > asf->packet_size_left - rsize) {
             if (asf->packet_frag_size > asf->packet_size_left - rsize + asf->packet_padsize) {
                 av_log(s, AV_LOG_ERROR, "packet_frag_size is invalid (%d-%d)\n",
                        asf->packet_size_left, rsize);
-                return -1;
+                return AVERROR_INVALIDDATA;
             } else {
                 int diff = asf->packet_frag_size - (asf->packet_size_left - rsize);
                 asf->packet_size_left += diff;
@@ -1029,16 +1090,12 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb)
             }
         }
     } else {
-        if (rsize > asf->packet_size_left) {
-            av_log(s, AV_LOG_ERROR, "packet_replic_size is invalid\n");
-            return -1;
-        }
         asf->packet_frag_size = asf->packet_size_left - rsize;
     }
     if (asf->packet_replic_size == 1) {
         asf->packet_multi_size = asf->packet_frag_size;
         if (asf->packet_multi_size > asf->packet_size_left)
-            return -1;
+            return AVERROR_INVALIDDATA;
     }
     asf->packet_size_left -= rsize;
 
@@ -1060,8 +1117,7 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
     ASFStream *asf_st = 0;
     for (;;) {
         int ret;
-
-        if (pb->eof_reached)
+        if (url_feof(pb))
             return AVERROR_EOF;
 
         if (asf->packet_size_left < FRAME_HEADER_SIZE ||
@@ -1086,7 +1142,7 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
             if (asf->stream_index < 0 ||
                 s->streams[asf->stream_index]->discard >= AVDISCARD_ALL ||
                 (!asf->packet_key_frame &&
-                 s->streams[asf->stream_index]->discard >= AVDISCARD_NONKEY)) {
+                 (s->streams[asf->stream_index]->discard >= AVDISCARD_NONKEY || asf->streams[s->streams[asf->stream_index]->id].skip_to_key))) {
                 asf->packet_time_start = 0;
                 /* unhandled packet (should not happen) */
                 avio_skip(pb, asf->packet_frag_size);
@@ -1096,7 +1152,8 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
                            asf->packet_frag_size);
                 continue;
             }
-            asf->asf_st = s->streams[asf->stream_index]->priv_data;
+            asf->asf_st = &asf->streams[s->streams[asf->stream_index]->id];
+            asf->asf_st->skip_to_key = 0;
         }
         asf_st = asf->asf_st;
         av_assert0(asf_st);
@@ -1105,37 +1162,30 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
             // 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 = avio_r8(pb);
+            asf_st->packet_obj_size    = asf->packet_frag_size = avio_r8(pb);
             asf->packet_size_left--;
             asf->packet_multi_size--;
-            if (asf->packet_multi_size < asf->packet_obj_size) {
+            if (asf->packet_multi_size < asf_st->packet_obj_size) {
                 asf->packet_time_start = 0;
                 avio_skip(pb, asf->packet_multi_size);
                 asf->packet_size_left -= asf->packet_multi_size;
                 continue;
             }
-            asf->packet_multi_size -= asf->packet_obj_size;
-        }
-        if (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;
+            asf->packet_multi_size -= asf_st->packet_obj_size;
         }
 
-        if (asf_st->pkt.size != asf->packet_obj_size ||
+        if (asf_st->pkt.size != asf_st->packet_obj_size ||
             // FIXME is this condition sufficient?
             asf_st->frag_offset + asf->packet_frag_size > asf_st->pkt.size) {
             if (asf_st->pkt.data) {
                 av_log(s, AV_LOG_INFO,
                        "freeing incomplete packet size %d, new %d\n",
-                       asf_st->pkt.size, asf->packet_obj_size);
+                       asf_st->pkt.size, asf_st->packet_obj_size);
                 asf_st->frag_offset = 0;
                 av_free_packet(&asf_st->pkt);
             }
             /* new packet */
-            av_new_packet(&asf_st->pkt, asf->packet_obj_size);
+            av_new_packet(&asf_st->pkt, asf_st->packet_obj_size);
             asf_st->seq              = asf->packet_seq;
             asf_st->pkt.dts          = asf->packet_frag_timestamp - asf->hdr.preroll;
             asf_st->pkt.stream_index = asf->stream_index;
@@ -1156,7 +1206,7 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
                     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);
+                    asf_st->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)
@@ -1311,21 +1361,34 @@ static void asf_reset_header(AVFormatContext *s)
     asf->packet_frag_size      = 0;
     asf->packet_frag_timestamp = 0;
     asf->packet_multi_size     = 0;
-    asf->packet_obj_size       = 0;
     asf->packet_time_delta     = 0;
     asf->packet_time_start     = 0;
 
-    for (i = 0; i < s->nb_streams; i++) {
-        asf_st = s->streams[i]->priv_data;
-        if (!asf_st)
-            continue;
+    for (i = 0; i < 128; i++) {
+        asf_st = &asf->streams[i];
         av_free_packet(&asf_st->pkt);
+        asf_st->packet_obj_size = 0;
         asf_st->frag_offset = 0;
         asf_st->seq         = 0;
     }
     asf->asf_st = NULL;
 }
 
+static void skip_to_key(AVFormatContext *s)
+{
+    ASFContext *asf = s->priv_data;
+    int i;
+
+    for (i = 0; i < 128; i++) {
+        int j = asf->asfid2avid[i];
+        ASFStream *asf_st = &asf->streams[i];
+        if (j < 0 || s->streams[j]->codec->codec_type != AVMEDIA_TYPE_VIDEO)
+            continue;
+
+        asf_st->skip_to_key = 1;
+    }
+}
+
 static int asf_read_close(AVFormatContext *s)
 {
     asf_reset_header(s);
@@ -1336,6 +1399,7 @@ 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;
@@ -1351,11 +1415,13 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index,
               s->packet_size * s->packet_size +
               s->data_offset;
     *ppos = pos;
-    avio_seek(s->pb, pos, SEEK_SET);
+    if (avio_seek(s->pb, pos, SEEK_SET) < 0)
+        return AV_NOPTS_VALUE;
 
+    ff_read_frame_flush(s);
     asf_reset_header(s);
     for (;;) {
-        if (asf_read_packet(s, pkt) < 0) {
+        if (av_read_frame(s, pkt) < 0) {
             av_log(s, AV_LOG_INFO, "asf_read_pts failed\n");
             return AV_NOPTS_VALUE;
         }
@@ -1366,8 +1432,7 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index,
         if (pkt->flags & AV_PKT_FLAG_KEY) {
             i = pkt->stream_index;
 
-            asf_st = s->streams[i]->priv_data;
-            av_assert0(asf_st);
+            asf_st = &asf->streams[s->streams[i]->id];
 
 //            assert((asf_st->packet_pos - s->data_offset) % s->packet_size == 0);
             pos = asf_st->packet_pos;
@@ -1390,17 +1455,21 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index)
     ff_asf_guid g;
     ASFContext *asf     = s->priv_data;
     int64_t current_pos = avio_tell(s->pb);
-    int i;
 
-    avio_seek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET);
+    if(avio_seek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET) < 0) {
+        asf->index_read= -1;
+        return;
+    }
+
     ff_get_guid(s->pb, &g);
 
     /* the data object can be followed by other top-level objects,
      * skip them until the simple index object is reached */
-    while (ff_guidcmp(&g, &index_guid)) {
+    while (ff_guidcmp(&g, &ff_asf_simple_index_header)) {
         int64_t gsize = avio_rl64(s->pb);
-        if (gsize < 24 || s->pb->eof_reached) {
+        if (gsize < 24 || url_feof(s->pb)) {
             avio_seek(s->pb, current_pos, SEEK_SET);
+            asf->index_read= -1;
             return;
         }
         avio_skip(s->pb, gsize - 24);
@@ -1410,6 +1479,7 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index)
     {
         int64_t itime, last_pos = -1;
         int pct, ict;
+        int i;
         int64_t av_unused gsize = avio_rl64(s->pb);
         ff_get_guid(s->pb, &g);
         itime = avio_rl64(s->pb);
@@ -1432,7 +1502,7 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index)
                 last_pos = pos;
             }
         }
-        asf->index_read = ict > 0;
+        asf->index_read = ict > 1;
     }
     avio_seek(s->pb, current_pos, SEEK_SET);
 }
@@ -1442,8 +1512,6 @@ static int asf_read_seek(AVFormatContext *s, int stream_index,
 {
     ASFContext *asf = s->priv_data;
     AVStream *st    = s->streams[stream_index];
-    int64_t pos;
-    int index;
 
     if (s->packet_size <= 0)
         return -1;
@@ -1460,16 +1528,18 @@ static int asf_read_seek(AVFormatContext *s, int stream_index,
     if (!asf->index_read)
         asf_build_simple_index(s, stream_index);
 
-    if ((asf->index_read && st->index_entries)) {
-        index = av_index_search_timestamp(st, pts, flags);
+    if ((asf->index_read > 0 && st->index_entries)) {
+        int index = av_index_search_timestamp(st, pts, flags);
         if (index >= 0) {
             /* find the position */
-            pos = st->index_entries[index].pos;
+            uint64_t pos = st->index_entries[index].pos;
 
             /* do the seek */
             av_log(s, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos);
-            avio_seek(s->pb, pos, SEEK_SET);
+            if(avio_seek(s->pb, pos, SEEK_SET) < 0)
+                return -1;
             asf_reset_header(s);
+            skip_to_key(s);
             return 0;
         }
     }
@@ -1477,6 +1547,7 @@ static int asf_read_seek(AVFormatContext *s, int stream_index,
     if (ff_seek_frame_binary(s, stream_index, pts, flags) < 0)
         return -1;
     asf_reset_header(s);
+    skip_to_key(s);
     return 0;
 }