asf.c 40.1 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1
/*
2
 * ASF compatible demuxer
3
 * Copyright (c) 2000, 2001 Fabrice Bellard.
Fabrice Bellard's avatar
Fabrice Bellard committed
4
 *
5 6 7
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Fabrice Bellard's avatar
Fabrice Bellard committed
20
 */
21 22 23

#include "libavutil/common.h"
#include "libavcodec/mpegaudio.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
24
#include "avformat.h"
25
#include "riff.h"
26
#include "asf.h"
27
#include "asfcrypt.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
28

29 30
extern void ff_mms_set_stream_selection(URLContext *h, AVFormatContext *format);

Michael Niedermayer's avatar
Michael Niedermayer committed
31 32 33
#undef NDEBUG
#include <assert.h>

34
#define FRAME_HEADER_SIZE 17
35
// Fix Me! FRAME_HEADER_SIZE may be different.
36

Fabrice Bellard's avatar
Fabrice Bellard committed
37
static const GUID index_guid = {
Michael Niedermayer's avatar
Michael Niedermayer committed
38
    0x90, 0x08, 0x00, 0x33, 0xb1, 0xe5, 0xcf, 0x11, 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb
Fabrice Bellard's avatar
Fabrice Bellard committed
39 40
};

41 42 43
static const GUID stream_bitrate_guid = { /* (http://get.to/sdp) */
    0xce, 0x75, 0xf8, 0x7b, 0x8d, 0x46, 0xd1, 0x11, 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2
};
Fabrice Bellard's avatar
Fabrice Bellard committed
44 45 46 47 48 49
/**********************************/
/* decoding */

//#define DEBUG

#ifdef DEBUG
François Revol's avatar
François Revol committed
50 51
#define PRINT_IF_GUID(g,cmp) \
if (!memcmp(g, &cmp, sizeof(GUID))) \
52
    dprintf(NULL, "(GUID: %s) ", #cmp)
François Revol's avatar
François Revol committed
53

Fabrice Bellard's avatar
Fabrice Bellard committed
54 55 56
static void print_guid(const GUID *g)
{
    int i;
François Revol's avatar
François Revol committed
57 58 59 60 61 62 63
    PRINT_IF_GUID(g, asf_header);
    else PRINT_IF_GUID(g, file_header);
    else PRINT_IF_GUID(g, stream_header);
    else PRINT_IF_GUID(g, audio_stream);
    else PRINT_IF_GUID(g, audio_conceal_none);
    else PRINT_IF_GUID(g, video_stream);
    else PRINT_IF_GUID(g, video_conceal_none);
64
    else PRINT_IF_GUID(g, command_stream);
François Revol's avatar
François Revol committed
65 66 67 68 69 70 71 72
    else PRINT_IF_GUID(g, comment_header);
    else PRINT_IF_GUID(g, codec_comment_header);
    else PRINT_IF_GUID(g, codec_comment1_header);
    else PRINT_IF_GUID(g, data_header);
    else PRINT_IF_GUID(g, index_guid);
    else PRINT_IF_GUID(g, head1_guid);
    else PRINT_IF_GUID(g, head2_guid);
    else PRINT_IF_GUID(g, my_guid);
73 74 75 76
    else PRINT_IF_GUID(g, ext_stream_header);
    else PRINT_IF_GUID(g, extended_content_header);
    else PRINT_IF_GUID(g, ext_stream_embed_stream_header);
    else PRINT_IF_GUID(g, ext_stream_audio_stream);
77
    else PRINT_IF_GUID(g, metadata_header);
78
    else PRINT_IF_GUID(g, stream_bitrate_guid);
François Revol's avatar
François Revol committed
79
    else
80
        dprintf(NULL, "(GUID: unknown) ");
Michael Niedermayer's avatar
Michael Niedermayer committed
81
    for(i=0;i<16;i++)
82 83
        dprintf(NULL, " 0x%02x,", (*g)[i]);
    dprintf(NULL, "}\n");
Fabrice Bellard's avatar
Fabrice Bellard committed
84
}
85
#undef PRINT_IF_GUID
86 87
#else
#define print_guid(g)
Fabrice Bellard's avatar
Fabrice Bellard committed
88 89 90 91
#endif

static void get_guid(ByteIOContext *s, GUID *g)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
92
    assert(sizeof(*g) == 16);
93
    get_buffer(s, *g, sizeof(*g));
Fabrice Bellard's avatar
Fabrice Bellard committed
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
}

#if 0
static void get_str16(ByteIOContext *pb, char *buf, int buf_size)
{
    int len, c;
    char *q;

    len = get_le16(pb);
    q = buf;
    while (len > 0) {
        c = get_le16(pb);
        if ((q - buf) < buf_size - 1)
            *q++ = c;
        len--;
    }
    *q = '\0';
}
#endif

static void get_str16_nolen(ByteIOContext *pb, int len, char *buf, int buf_size)
{
116 117 118 119 120
    char* q = buf;
    len /= 2;
    while (len--) {
        uint8_t tmp;
        PUT_UTF8(get_le16(pb), tmp, if (q - buf < buf_size - 1) *q++ = tmp;)
Fabrice Bellard's avatar
Fabrice Bellard committed
121 122 123 124
    }
    *q = '\0';
}

Fabrice Bellard's avatar
Fabrice Bellard committed
125 126 127
static int asf_probe(AVProbeData *pd)
{
    /* check file header */
Michael Niedermayer's avatar
Michael Niedermayer committed
128
    if (!memcmp(pd->buf, &asf_header, sizeof(GUID)))
Fabrice Bellard's avatar
Fabrice Bellard committed
129 130 131 132 133
        return AVPROBE_SCORE_MAX;
    else
        return 0;
}

134 135 136 137 138 139 140 141 142 143
static int get_value(ByteIOContext *pb, int type){
    switch(type){
        case 2: return get_le32(pb);
        case 3: return get_le32(pb);
        case 4: return get_le64(pb);
        case 5: return get_le16(pb);
        default:return INT_MIN;
    }
}

Fabrice Bellard's avatar
Fabrice Bellard committed
144 145
static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
Fabrice Bellard's avatar
Fabrice Bellard committed
146
    ASFContext *asf = s->priv_data;
Fabrice Bellard's avatar
Fabrice Bellard committed
147
    GUID g;
148
    ByteIOContext *pb = s->pb;
Fabrice Bellard's avatar
Fabrice Bellard committed
149 150
    AVStream *st;
    ASFStream *asf_st;
151
    int size, i;
152
    int64_t gsize;
153
    AVRational dar[128];
154
    uint32_t bitrate[128];
155 156

    memset(dar, 0, sizeof(dar));
157
    memset(bitrate, 0, sizeof(bitrate));
Fabrice Bellard's avatar
Fabrice Bellard committed
158 159 160

    get_guid(pb, &g);
    if (memcmp(&g, &asf_header, sizeof(GUID)))
161
        return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
162 163 164 165
    get_le64(pb);
    get_le32(pb);
    get_byte(pb);
    get_byte(pb);
166
    memset(&asf->asfid2avid, -1, sizeof(asf->asfid2avid));
Fabrice Bellard's avatar
Fabrice Bellard committed
167 168 169
    for(;;) {
        get_guid(pb, &g);
        gsize = get_le64(pb);
170
        dprintf(s, "%08"PRIx64": ", url_ftell(pb) - 24);
Fabrice Bellard's avatar
Fabrice Bellard committed
171
        print_guid(&g);
172
        dprintf(s, "  size=0x%"PRIx64"\n", gsize);
173 174 175 176 177 178 179 180 181 182
        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..
            if (!(asf->hdr.flags & 0x01) && gsize >= 100) {
                asf->data_object_size = gsize - 24;
            } else {
                asf->data_object_size = (uint64_t)-1;
            }
            break;
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
183
        if (gsize < 24)
184
            return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
185
        if (!memcmp(&g, &file_header, sizeof(GUID))) {
186
            get_guid(pb, &asf->hdr.guid);
187 188
            asf->hdr.file_size          = get_le64(pb);
            asf->hdr.create_time        = get_le64(pb);
189
            asf->nb_packets             = get_le64(pb);
190
            asf->hdr.play_time          = get_le64(pb);
191
            asf->hdr.send_time          = get_le64(pb);
192 193 194 195 196 197 198
            asf->hdr.preroll            = get_le32(pb);
            asf->hdr.ignore             = get_le32(pb);
            asf->hdr.flags              = get_le32(pb);
            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;
Fabrice Bellard's avatar
Fabrice Bellard committed
199
        } else if (!memcmp(&g, &stream_header, sizeof(GUID))) {
200 201
            int type, type_specific_size, sizeX;
            uint64_t total_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
202
            unsigned int tag1;
203
            int64_t pos1, pos2, start_time;
John Donaghy's avatar
John Donaghy committed
204
            int test_for_ext_stream_audio, is_dvr_ms_audio=0;
205

Fabrice Bellard's avatar
Fabrice Bellard committed
206 207
            pos1 = url_ftell(pb);

208
            st = av_new_stream(s, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
209
            if (!st)
210
                return AVERROR(ENOMEM);
211
            av_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
Fabrice Bellard's avatar
Fabrice Bellard committed
212 213
            asf_st = av_mallocz(sizeof(ASFStream));
            if (!asf_st)
214
                return AVERROR(ENOMEM);
Fabrice Bellard's avatar
Fabrice Bellard committed
215
            st->priv_data = asf_st;
216 217
            start_time = asf->hdr.preroll;

218 219
            if(!(asf->hdr.flags & 0x01)) { // if we aren't streaming...
                st->duration = asf->hdr.send_time /
220
                    (10000000 / 1000) - start_time;
221
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
222
            get_guid(pb, &g);
223 224

            test_for_ext_stream_audio = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
225 226 227 228
            if (!memcmp(&g, &audio_stream, sizeof(GUID))) {
                type = CODEC_TYPE_AUDIO;
            } else if (!memcmp(&g, &video_stream, sizeof(GUID))) {
                type = CODEC_TYPE_VIDEO;
229
            } else if (!memcmp(&g, &command_stream, sizeof(GUID))) {
230
                type = CODEC_TYPE_DATA;
231 232 233
            } else if (!memcmp(&g, &ext_stream_embed_stream_header, sizeof(GUID))) {
                test_for_ext_stream_audio = 1;
                type = CODEC_TYPE_UNKNOWN;
Fabrice Bellard's avatar
Fabrice Bellard committed
234
            } else {
235
                return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
236 237 238
            }
            get_guid(pb, &g);
            total_size = get_le64(pb);
239
            type_specific_size = get_le32(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
240
            get_le32(pb);
241
            st->id = get_le16(pb) & 0x7f; /* stream id */
242
            // mapping of asf ID to AV stream ID;
243
            asf->asfid2avid[st->id] = s->nb_streams - 1;
244

Fabrice Bellard's avatar
Fabrice Bellard committed
245
            get_le32(pb);
246 247 248 249 250

            if (test_for_ext_stream_audio) {
                get_guid(pb, &g);
                if (!memcmp(&g, &ext_stream_audio_stream, sizeof(GUID))) {
                    type = CODEC_TYPE_AUDIO;
John Donaghy's avatar
John Donaghy committed
251
                    is_dvr_ms_audio=1;
252 253 254 255 256 257 258 259 260
                    get_guid(pb, &g);
                    get_le32(pb);
                    get_le32(pb);
                    get_le32(pb);
                    get_guid(pb, &g);
                    get_le32(pb);
                }
            }

261
            st->codec->codec_type = type;
Fabrice Bellard's avatar
Fabrice Bellard committed
262
            if (type == CODEC_TYPE_AUDIO) {
263
                get_wav_header(pb, st->codec, type_specific_size);
John Donaghy's avatar
John Donaghy committed
264 265 266
                if (is_dvr_ms_audio) {
                    // codec_id and codec_tag are unreliable in dvr_ms
                    // files. Set them later by probing stream.
267
                    st->codec->codec_id = CODEC_ID_PROBE;
John Donaghy's avatar
John Donaghy committed
268 269
                    st->codec->codec_tag = 0;
                }
270
                st->need_parsing = AVSTREAM_PARSE_FULL;
271 272
                /* We have to init the frame size at some point .... */
                pos2 = url_ftell(pb);
Michael Niedermayer's avatar
Michael Niedermayer committed
273
                if (gsize >= (pos2 + 8 - pos1 + 24)) {
274 275 276
                    asf_st->ds_span = get_byte(pb);
                    asf_st->ds_packet_size = get_le16(pb);
                    asf_st->ds_chunk_size = get_le16(pb);
277 278
                    get_le16(pb); //ds_data_size
                    get_byte(pb); //ds_silence_data
279 280 281 282 283 284
                }
                //printf("Descrambling: ps:%d cs:%d ds:%d s:%d  sd:%d\n",
                //       asf_st->ds_packet_size, asf_st->ds_chunk_size,
                //       asf_st->ds_data_size, asf_st->ds_span, asf_st->ds_silence_data);
                if (asf_st->ds_span > 1) {
                    if (!asf_st->ds_chunk_size
285 286
                        || (asf_st->ds_packet_size/asf_st->ds_chunk_size <= 1)
                        || asf_st->ds_packet_size % asf_st->ds_chunk_size)
287 288
                        asf_st->ds_span = 0; // disable descrambling
                }
289
                switch (st->codec->codec_id) {
290
                case CODEC_ID_MP3:
291
                    st->codec->frame_size = MPA_FRAME_SIZE;
292 293 294 295 296 297 298 299 300
                    break;
                case CODEC_ID_PCM_S16LE:
                case CODEC_ID_PCM_S16BE:
                case CODEC_ID_PCM_U16LE:
                case CODEC_ID_PCM_U16BE:
                case CODEC_ID_PCM_S8:
                case CODEC_ID_PCM_U8:
                case CODEC_ID_PCM_ALAW:
                case CODEC_ID_PCM_MULAW:
301
                    st->codec->frame_size = 1;
302 303 304
                    break;
                default:
                    /* This is probably wrong, but it prevents a crash later */
305
                    st->codec->frame_size = 1;
306 307
                    break;
                }
308
            } else if (type == CODEC_TYPE_VIDEO) {
309
                get_le32(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
310 311 312
                get_le32(pb);
                get_byte(pb);
                size = get_le16(pb); /* size */
313
                sizeX= get_le32(pb); /* size */
314
                st->codec->width = get_le32(pb);
315
                st->codec->height = get_le32(pb);
316
                /* not available for asf */
Fabrice Bellard's avatar
Fabrice Bellard committed
317
                get_le16(pb); /* panes */
318
                st->codec->bits_per_coded_sample = get_le16(pb); /* depth */
Fabrice Bellard's avatar
Fabrice Bellard committed
319
                tag1 = get_le32(pb);
320
                url_fskip(pb, 20);
321 322
//                av_log(NULL, AV_LOG_DEBUG, "size:%d tsize:%d sizeX:%d\n", size, total_size, sizeX);
                size= sizeX;
323 324 325 326 327
                if (size > 40) {
                    st->codec->extradata_size = size - 40;
                    st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
                    get_buffer(pb, st->codec->extradata, st->codec->extradata_size);
                }
328 329 330 331

        /* 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 */
332
        if (st->codec->extradata_size && (st->codec->bits_per_coded_sample <= 8)) {
333
            st->codec->palctrl = av_mallocz(sizeof(AVPaletteControl));
334
#ifdef WORDS_BIGENDIAN
335 336
            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]);
337
#else
338 339
            memcpy(st->codec->palctrl->palette, st->codec->extradata,
                   FFMIN(st->codec->extradata_size, AVPALETTE_SIZE));
340
#endif
341
            st->codec->palctrl->palette_changed = 1;
342 343
        }

344
                st->codec->codec_tag = tag1;
345
                st->codec->codec_id = codec_get_id(codec_bmp_tags, tag1);
346
                if(tag1 == MKTAG('D', 'V', 'R', ' '))
347
                    st->need_parsing = AVSTREAM_PARSE_FULL;
Fabrice Bellard's avatar
Fabrice Bellard committed
348 349 350 351 352 353 354 355 356 357 358
            }
            pos2 = url_ftell(pb);
            url_fskip(pb, gsize - (pos2 - pos1 + 24));
        } else if (!memcmp(&g, &comment_header, sizeof(GUID))) {
            int len1, len2, len3, len4, len5;

            len1 = get_le16(pb);
            len2 = get_le16(pb);
            len3 = get_le16(pb);
            len4 = get_le16(pb);
            len5 = get_le16(pb);
359 360
            get_str16_nolen(pb, len1, s->title    , sizeof(s->title));
            get_str16_nolen(pb, len2, s->author   , sizeof(s->author));
Fabrice Bellard's avatar
Fabrice Bellard committed
361
            get_str16_nolen(pb, len3, s->copyright, sizeof(s->copyright));
362
            get_str16_nolen(pb, len4, s->comment  , sizeof(s->comment));
363
            url_fskip(pb, len5);
364 365 366 367 368 369 370 371 372 373 374 375 376
        } else if (!memcmp(&g, &stream_bitrate_guid, sizeof(GUID))) {
            int stream_count = get_le16(pb);
            int j;

//            av_log(NULL, AV_LOG_ERROR, "stream bitrate properties\n");
//            av_log(NULL, AV_LOG_ERROR, "streams %d\n", streams);
            for(j = 0; j < stream_count; j++) {
                int flags, bitrate, stream_id;

                flags= get_le16(pb);
                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);
377
                asf->stream_bitrates[stream_id]= bitrate;
378
            }
379 380 381 382 383 384
       } else if (!memcmp(&g, &extended_content_header, sizeof(GUID))) {
                int desc_count, i;

                desc_count = get_le16(pb);
                for(i=0;i<desc_count;i++)
                {
385 386
                        int name_len,value_type,value_len;
                        uint64_t value_num = 0;
387
                        char name[1024];
388 389

                        name_len = get_le16(pb);
390
                        get_str16_nolen(pb, name_len, name, sizeof(name));
391 392
                        value_type = get_le16(pb);
                        value_len = get_le16(pb);
Michael Niedermayer's avatar
Michael Niedermayer committed
393
                        if (value_type <= 1) // unicode or byte
394
                        {
Michael Niedermayer's avatar
Michael Niedermayer committed
395 396
                                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));
397 398 399 400 401
                                else if(!strcmp(name,"WM/Year"      )) {
                                    char year[8];
                                    get_str16_nolen(pb, value_len, year, sizeof(year));
                                    s->year = atoi(year);
                                }
402
                                else if(!strcmp(name,"WM/Track") && s->track == 0) {
403 404 405 406 407 408 409 410 411
                                    char track[8];
                                    get_str16_nolen(pb, value_len, track, sizeof(track));
                                    s->track = strtol(track, NULL, 10) + 1;
                                }
                                else if(!strcmp(name,"WM/TrackNumber")) {
                                    char track[8];
                                    get_str16_nolen(pb, value_len, track, sizeof(track));
                                    s->track = strtol(track, NULL, 10);
                                }
Michael Niedermayer's avatar
Michael Niedermayer committed
412
                                else url_fskip(pb, value_len);
413
                        }
Michael Niedermayer's avatar
Michael Niedermayer committed
414
                        else if (value_type <= 5) // boolean or DWORD or QWORD or WORD
415
                        {
416
                                value_num= get_value(pb, value_type);
417
                                if (!strcmp(name,"WM/Track"      ) && s->track == 0) s->track = value_num + 1;
418
                                if (!strcmp(name,"WM/TrackNumber")) s->track = value_num;
419 420
                        }else
                            url_fskip(pb, value_len);
421
                }
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
        } else if (!memcmp(&g, &metadata_header, sizeof(GUID))) {
            int n, stream_num, name_len, value_len, value_type, value_num;
            n = get_le16(pb);

            for(i=0;i<n;i++) {
                char name[1024];

                get_le16(pb); //lang_list_index
                stream_num= get_le16(pb);
                name_len=   get_le16(pb);
                value_type= get_le16(pb);
                value_len=  get_le32(pb);

                get_str16_nolen(pb, name_len, name, sizeof(name));
//av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d <%s>\n", i, stream_num, name_len, value_type, value_len, name);
Diego Biurrun's avatar
Diego Biurrun committed
437
                value_num= get_le16(pb);//we should use get_value() here but it does not work 2 is le16 here but le32 elsewhere
438 439 440 441 442 443 444
                url_fskip(pb, value_len - 2);

                if(stream_num<128){
                    if     (!strcmp(name, "AspectRatioX")) dar[stream_num].num= value_num;
                    else if(!strcmp(name, "AspectRatioY")) dar[stream_num].den= value_num;
                }
            }
445 446
        } else if (!memcmp(&g, &ext_stream_header, sizeof(GUID))) {
            int ext_len, payload_ext_ct, stream_ct;
447
            uint32_t ext_d, leak_rate, stream_num;
Måns Rullgård's avatar
Måns Rullgård committed
448
            int64_t pos_ex_st;
449 450
            pos_ex_st = url_ftell(pb);

451 452
            get_le64(pb); // starttime
            get_le64(pb); // endtime
453
            leak_rate = get_le32(pb); // leak-datarate
454 455 456 457 458 459 460
            get_le32(pb); // bucket-datasize
            get_le32(pb); // init-bucket-fullness
            get_le32(pb); // alt-leak-datarate
            get_le32(pb); // alt-bucket-datasize
            get_le32(pb); // alt-init-bucket-fullness
            get_le32(pb); // max-object-size
            get_le32(pb); // flags (reliable,seekable,no_cleanpoints?,resend-live-cleanpoints, rest of bits reserved)
461
            stream_num = get_le16(pb); // stream-num
462 463 464 465
            get_le16(pb); // stream-language-id-index
            get_le64(pb); // avg frametime in 100ns units
            stream_ct = get_le16(pb); //stream-name-count
            payload_ext_ct = get_le16(pb); //payload-extension-system-count
466

467 468 469
            if (stream_num < 128)
                bitrate[stream_num] = leak_rate;

470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
            for (i=0; i<stream_ct; i++){
                get_le16(pb);
                ext_len = get_le16(pb);
                url_fseek(pb, ext_len, SEEK_CUR);
            }

            for (i=0; i<payload_ext_ct; i++){
                get_guid(pb, &g);
                ext_d=get_le16(pb);
                ext_len=get_le32(pb);
                url_fseek(pb, ext_len, SEEK_CUR);
            }

            // there could be a optional stream properties object to follow
            // if so the next iteration will pick it up
Fabrice Bellard's avatar
Fabrice Bellard committed
485 486 487 488 489
        } else if (!memcmp(&g, &head1_guid, sizeof(GUID))) {
            int v1, v2;
            get_guid(pb, &g);
            v1 = get_le32(pb);
            v2 = get_le16(pb);
490
#if 0
Fabrice Bellard's avatar
Fabrice Bellard committed
491 492 493 494 495 496 497
        } else if (!memcmp(&g, &codec_comment_header, sizeof(GUID))) {
            int len, v1, n, num;
            char str[256], *q;
            char tag[16];

            get_guid(pb, &g);
            print_guid(&g);
498

Fabrice Bellard's avatar
Fabrice Bellard committed
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
            n = get_le32(pb);
            for(i=0;i<n;i++) {
                num = get_le16(pb); /* stream number */
                get_str16(pb, str, sizeof(str));
                get_str16(pb, str, sizeof(str));
                len = get_le16(pb);
                q = tag;
                while (len > 0) {
                    v1 = get_byte(pb);
                    if ((q - tag) < sizeof(tag) - 1)
                        *q++ = v1;
                    len--;
                }
                *q = '\0';
            }
#endif
        } else if (url_feof(pb)) {
516
            return -1;
Fabrice Bellard's avatar
Fabrice Bellard committed
517 518 519 520 521 522 523 524
        } else {
            url_fseek(pb, gsize - 24, SEEK_CUR);
        }
    }
    get_guid(pb, &g);
    get_le64(pb);
    get_byte(pb);
    get_byte(pb);
525
    if (url_feof(pb))
526
        return -1;
527
    asf->data_offset = url_ftell(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
528 529
    asf->packet_size_left = 0;

530 531 532

    for(i=0; i<128; i++){
        int stream_num= asf->asfid2avid[i];
533
        if(stream_num>=0){
534 535 536
            AVStream *st = s->streams[stream_num];
            if (!st->codec->bit_rate)
                st->codec->bit_rate = bitrate[i];
537
            if (dar[i].num > 0 && dar[i].den > 0)
538 539
                av_reduce(&st->sample_aspect_ratio.num,
                          &st->sample_aspect_ratio.den,
540
                          dar[i].num, dar[i].den, INT_MAX);
541
//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);
542 543 544
        }
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
545 546 547
    return 0;
}

548 549 550 551 552 553 554 555 556
#define DO_2BITS(bits, var, defval) \
    switch (bits & 3) \
    { \
    case 3: var = get_le32(pb); rsize += 4; break; \
    case 2: var = get_le16(pb); rsize += 2; break; \
    case 1: var = get_byte(pb); rsize++; break; \
    default: var = defval; break; \
    }

557 558 559 560
/**
 *
 * @return <0 in case of an error
 */
Fabrice Bellard's avatar
Fabrice Bellard committed
561 562 563
static int asf_get_packet(AVFormatContext *s)
{
    ASFContext *asf = s->priv_data;
564
    ByteIOContext *pb = s->pb;
565
    uint32_t packet_length, padsize;
566
    int rsize = 8;
567 568
    int c, d, e, off;

569
    off= (url_ftell(s->pb) - s->data_offset) % asf->packet_size + 3;
570 571 572 573 574 575 576 577

    c=d=e=-1;
    while(off-- > 0){
        c=d; d=e;
        e= get_byte(pb);
        if(c == 0x82 && !d && !e)
            break;
    }
578

579
    if (c != 0x82) {
580
        if (!url_feof(pb))
581
            av_log(s, AV_LOG_ERROR, "ff asf bad header %x  at:%"PRId64"\n", c, url_ftell(pb));
582
    }
583
    if ((c & 0x8f) == 0x82) {
584
        if (d || e) {
585
            if (!url_feof(pb))
586
                av_log(s, AV_LOG_ERROR, "ff asf bad non zero\n");
587
            return -1;
588
        }
589
        c= get_byte(pb);
590
        d= get_byte(pb);
591 592 593
        rsize+=3;
    }else{
        url_fseek(pb, -1, SEEK_CUR); //FIXME
Fabrice Bellard's avatar
Fabrice Bellard committed
594
    }
595

596 597
    asf->packet_flags    = c;
    asf->packet_property = d;
598 599 600 601 602

    DO_2BITS(asf->packet_flags >> 5, packet_length, asf->packet_size);
    DO_2BITS(asf->packet_flags >> 1, padsize, 0); // sequence ignored
    DO_2BITS(asf->packet_flags >> 3, padsize, 0); // padding length

603 604 605
    //the following checks prevent overflows and infinite loops
    if(packet_length >= (1U<<29)){
        av_log(s, AV_LOG_ERROR, "invalid packet_length %d at:%"PRId64"\n", packet_length, url_ftell(pb));
606
        return -1;
607
    }
608
    if(padsize >= packet_length){
609
        av_log(s, AV_LOG_ERROR, "invalid padsize %d at:%"PRId64"\n", padsize, url_ftell(pb));
610
        return -1;
611 612
    }

613
    asf->packet_timestamp = get_le32(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
614
    get_le16(pb); /* duration */
615
    // rsize has at least 11 bytes which have to be present
616 617

    if (asf->packet_flags & 0x01) {
618
        asf->packet_segsizetype = get_byte(pb); rsize++;
619 620
        asf->packet_segments = asf->packet_segsizetype & 0x3f;
    } else {
621
        asf->packet_segments = 1;
622 623 624
        asf->packet_segsizetype = 0x80;
    }
    asf->packet_size_left = packet_length - padsize - rsize;
625 626
    if (packet_length < asf->hdr.min_pktsize)
        padsize += asf->hdr.min_pktsize - packet_length;
627
    asf->packet_padsize = padsize;
628
    dprintf(s, "packet: size=%d padsize=%d  left=%d\n", asf->packet_size, asf->packet_padsize, asf->packet_size_left);
Fabrice Bellard's avatar
Fabrice Bellard committed
629 630 631
    return 0;
}

632 633 634 635 636 637
/**
 *
 * @return <0 if error
 */
static int asf_read_frame_header(AVFormatContext *s){
    ASFContext *asf = s->priv_data;
638
    ByteIOContext *pb = s->pb;
639 640
    int rsize = 1;
    int num = get_byte(pb);
641
    int64_t ts0, ts1;
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657

    asf->packet_segments--;
    asf->packet_key_frame = num >> 7;
    asf->stream_index = asf->asfid2avid[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);
    DO_2BITS(asf->packet_property, asf->packet_replic_size, 0);
//printf("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 (asf->packet_replic_size >= 8) {
        asf->packet_obj_size = get_le32(pb);
        if(asf->packet_obj_size >= (1<<24) || asf->packet_obj_size <= 0){
            av_log(s, AV_LOG_ERROR, "packet_obj_size invalid\n");
            return -1;
        }
        asf->packet_frag_timestamp = get_le32(pb); // timestamp
658 659 660 661 662 663 664 665 666 667 668 669 670 671
        if(asf->packet_replic_size >= 8+38+4){
//            for(i=0; i<asf->packet_replic_size-8; i++)
//                av_log(s, AV_LOG_DEBUG, "%02X ",get_byte(pb));
//            av_log(s, AV_LOG_DEBUG, "\n");
            url_fskip(pb, 10);
            ts0= get_le64(pb);
            ts1= get_le64(pb);
            url_fskip(pb, 12);
            get_le32(pb);
            url_fskip(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
            url_fskip(pb, asf->packet_replic_size - 8);
672 673
        rsize += asf->packet_replic_size; // FIXME - check validity
    } else if (asf->packet_replic_size==1){
674
        // multipacket - frag_offset is beginning timestamp
675 676 677 678 679 680 681 682 683 684 685 686
        asf->packet_time_start = asf->packet_frag_offset;
        asf->packet_frag_offset = 0;
        asf->packet_frag_timestamp = asf->packet_timestamp;

        asf->packet_time_delta = get_byte(pb);
        rsize++;
    }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;
    }
    if (asf->packet_flags & 0x01) {
        DO_2BITS(asf->packet_segsizetype >> 6, asf->packet_frag_size, 0); // 0 is illegal
687 688 689 690
        if(asf->packet_frag_size > asf->packet_size_left - rsize){
            av_log(s, AV_LOG_ERROR, "packet_frag_size is invalid\n");
            return -1;
        }
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
        //printf("Fragsize %d\n", asf->packet_frag_size);
    } else {
        asf->packet_frag_size = asf->packet_size_left - rsize;
        //printf("Using rest  %d %d %d\n", 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;
    }
    asf->packet_size_left -= rsize;
    //printf("___objsize____  %d   %d    rs:%d\n", asf->packet_obj_size, asf->packet_frag_offset, rsize);

    return 0;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
707 708 709
static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    ASFContext *asf = s->priv_data;
710
    ASFStream *asf_st = 0;
711
    ByteIOContext *pb = s->pb;
712
    //static int pc = 0;
713
    for (;;) {
714
        if(url_feof(pb))
715
            return AVERROR(EIO);
716 717 718 719
        if (asf->packet_size_left < FRAME_HEADER_SIZE
            || asf->packet_segments < 1) {
            //asf->packet_size_left <= asf->packet_padsize) {
            int ret = asf->packet_size_left + asf->packet_padsize;
720
            //printf("PacketLeftSize:%d  Pad:%d Pos:%"PRId64"\n", asf->packet_size_left, asf->packet_padsize, url_ftell(pb));
721
            assert(ret>=0);
722 723
            /* fail safe */
            url_fskip(pb, ret);
724

725
            asf->packet_pos= url_ftell(s->pb);
726 727
            if (asf->data_object_size != (uint64_t)-1 &&
                (asf->packet_pos - asf->data_object_offset >= asf->data_object_size))
728
                return AVERROR(EIO); /* Do not exceed the size of the data object */
729 730
            ret = asf_get_packet(s);
            //printf("READ ASF PACKET  %d   r:%d   c:%d\n", ret, asf->packet_size_left, pc++);
731 732
            if (ret < 0)
                assert(asf->packet_size_left < FRAME_HEADER_SIZE || asf->packet_segments < 1);
733
            asf->packet_time_start = 0;
734
            continue;
735 736
        }
        if (asf->packet_time_start == 0) {
737 738
            if(asf_read_frame_header(s) < 0){
                asf->packet_segments= 0;
739
                continue;
740
            }
741
            if (asf->stream_index < 0
742 743 744
                || s->streams[asf->stream_index]->discard >= AVDISCARD_ALL
                || (!asf->packet_key_frame && s->streams[asf->stream_index]->discard >= AVDISCARD_NONKEY)
                ) {
745
                asf->packet_time_start = 0;
746 747 748
                /* unhandled packet (should not happen) */
                url_fskip(pb, asf->packet_frag_size);
                asf->packet_size_left -= asf->packet_frag_size;
749
                if(asf->stream_index < 0)
750
                    av_log(s, AV_LOG_ERROR, "ff asf skip %d (unknown stream)\n", asf->packet_frag_size);
751
                continue;
752 753 754 755 756 757
            }
            asf->asf_st = s->streams[asf->stream_index]->priv_data;
        }
        asf_st = asf->asf_st;

        if (asf->packet_replic_size == 1) {
758
            // frag_offset is here used as the beginning timestamp
759 760 761 762
            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);
            asf->packet_size_left--;
763
            asf->packet_multi_size--;
764 765 766 767 768
            if (asf->packet_multi_size < asf->packet_obj_size)
            {
                asf->packet_time_start = 0;
                url_fskip(pb, asf->packet_multi_size);
                asf->packet_size_left -= asf->packet_multi_size;
769
                continue;
770 771 772 773
            }
            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);
        }
774 775 776 777 778 779 780 781 782
        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;
        }

Michael Niedermayer's avatar
Michael Niedermayer committed
783 784
        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?
785 786 787 788 789
            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->frag_offset = 0;
                av_free_packet(&asf_st->pkt);
            }
790 791 792 793 794
            /* 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.stream_index = asf->stream_index;
795 796 797
            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",
Michael Niedermayer's avatar
Michael Niedermayer committed
798
//asf->stream_index, asf->packet_key_frame, asf_st->pkt.flags & PKT_FLAG_KEY,
799
//s->streams[asf->stream_index]->codec->codec_type == CODEC_TYPE_AUDIO, asf->packet_obj_size);
800 801 802 803 804 805 806 807 808 809 810 811
            if (s->streams[asf->stream_index]->codec->codec_type == CODEC_TYPE_AUDIO)
                asf->packet_key_frame = 1;
            if (asf->packet_key_frame)
                asf_st->pkt.flags |= 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,
        //       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)
812
            continue;
813 814 815 816 817 818 819 820

        if(   asf->packet_frag_offset >= asf_st->pkt.size
           || asf->packet_frag_size > asf_st->pkt.size - asf->packet_frag_offset){
            av_log(s, AV_LOG_ERROR, "packet fragment position invalid %u,%u not in %u\n",
                asf->packet_frag_offset, asf->packet_frag_size, asf_st->pkt.size);
            continue;
        }

821 822
        get_buffer(pb, asf_st->pkt.data + asf->packet_frag_offset,
                   asf->packet_frag_size);
823 824 825
        if (s->key && s->keylen == 20)
            ff_asfcrypt_dec(s->key, asf_st->pkt.data + asf->packet_frag_offset,
                            asf->packet_frag_size);
826 827 828
        asf_st->frag_offset += asf->packet_frag_size;
        /* test if whole packet is read */
        if (asf_st->frag_offset == asf_st->pkt.size) {
829 830 831 832 833 834 835 836 837 838 839 840 841
            //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; i<asf_st->pkt.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;
                }
            }

842 843
            /* return packet */
            if (asf_st->ds_span > 1) {
844
              if(asf_st->pkt.size != asf_st->ds_packet_size * asf_st->ds_span){
Michael Niedermayer's avatar
Michael Niedermayer committed
845
                    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);
846
              }else{
847
                /* packet descrambling */
848
                uint8_t *newdata = av_malloc(asf_st->pkt.size);
849 850 851 852 853 854 855 856
                if (newdata) {
                    int offset = 0;
                    while (offset < asf_st->pkt.size) {
                        int off = offset / asf_st->ds_chunk_size;
                        int row = off / asf_st->ds_span;
                        int col = off % asf_st->ds_span;
                        int idx = row + col * asf_st->ds_packet_size / asf_st->ds_chunk_size;
                        //printf("off:%d  row:%d  col:%d  idx:%d\n", off, row, col, idx);
857 858 859

                        assert(offset + asf_st->ds_chunk_size <= asf_st->pkt.size);
                        assert(idx+1 <= asf_st->pkt.size / asf_st->ds_chunk_size);
860 861 862 863 864 865 866 867
                        memcpy(newdata + offset,
                               asf_st->pkt.data + idx * asf_st->ds_chunk_size,
                               asf_st->ds_chunk_size);
                        offset += asf_st->ds_chunk_size;
                    }
                    av_free(asf_st->pkt.data);
                    asf_st->pkt.data = newdata;
                }
868
              }
869 870
            }
            asf_st->frag_offset = 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
871
            *pkt= asf_st->pkt;
872 873 874 875 876
            //printf("packet %d %d\n", asf_st->pkt.size, asf->packet_frag_size);
            asf_st->pkt.size = 0;
            asf_st->pkt.data = 0;
            break; // packet completed
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
877 878 879 880
    }
    return 0;
}

881 882 883 884 885 886
// Added to support seeking after packets have been read
// If information is not reset, read_packet fails due to
// leftover information from previous reads
static void asf_reset_header(AVFormatContext *s)
{
    ASFContext *asf = s->priv_data;
Michael Niedermayer's avatar
Michael Niedermayer committed
887 888
    ASFStream *asf_st;
    int i;
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908

    asf->packet_nb_frames = 0;
    asf->packet_size_left = 0;
    asf->packet_segments = 0;
    asf->packet_flags = 0;
    asf->packet_property = 0;
    asf->packet_timestamp = 0;
    asf->packet_segsizetype = 0;
    asf->packet_segments = 0;
    asf->packet_seq = 0;
    asf->packet_replic_size = 0;
    asf->packet_key_frame = 0;
    asf->packet_padsize = 0;
    asf->packet_frag_offset = 0;
    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;
909

Michael Niedermayer's avatar
Michael Niedermayer committed
910 911 912 913 914 915 916
    for(i=0; i<s->nb_streams; i++){
        asf_st= s->streams[i]->priv_data;
        av_free_packet(&asf_st->pkt);
        asf_st->frag_offset=0;
        asf_st->seq=0;
    }
    asf->asf_st= NULL;
917 918
}

919 920 921 922 923 924 925 926 927 928 929 930
static int asf_read_close(AVFormatContext *s)
{
    int i;

    asf_reset_header(s);
    for(i=0;i<s->nb_streams;i++) {
        AVStream *st = s->streams[i];
        av_free(st->codec->palctrl);
    }
    return 0;
}

931
static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit)
932 933 934
{
    ASFContext *asf = s->priv_data;
    AVPacket pkt1, *pkt = &pkt1;
Michael Niedermayer's avatar
Michael Niedermayer committed
935
    ASFStream *asf_st;
Michael Niedermayer's avatar
Michael Niedermayer committed
936
    int64_t pts;
Michael Niedermayer's avatar
Michael Niedermayer committed
937
    int64_t pos= *ppos;
938 939
    int i;
    int64_t start_pos[s->nb_streams];
940

941 942 943
    for(i=0; i<s->nb_streams; i++){
        start_pos[i]= pos;
    }
944

945 946
    pos= (pos+asf->packet_size-1-s->data_offset)/asf->packet_size*asf->packet_size+ s->data_offset;
    *ppos= pos;
947
    url_fseek(s->pb, pos, SEEK_SET);
948

Michael Niedermayer's avatar
Michael Niedermayer committed
949 950
//printf("asf_read_pts\n");
    asf_reset_header(s);
951
    for(;;){
Michael Niedermayer's avatar
Michael Niedermayer committed
952
        if (av_read_frame(s, pkt) < 0){
953
            av_log(s, AV_LOG_INFO, "asf_read_pts failed\n");
954
            return AV_NOPTS_VALUE;
Michael Niedermayer's avatar
Michael Niedermayer committed
955
        }
956

Michael Niedermayer's avatar
Michael Niedermayer committed
957
        pts= pkt->pts;
Michael Niedermayer's avatar
Michael Niedermayer committed
958 959

        av_free_packet(pkt);
960 961 962 963 964
        if(pkt->flags&PKT_FLAG_KEY){
            i= pkt->stream_index;

            asf_st= s->streams[i]->priv_data;

965
//            assert((asf_st->packet_pos - s->data_offset) % asf->packet_size == 0);
966
            pos= asf_st->packet_pos;
967

968
            av_add_index_entry(s->streams[i], pos, pts, pkt->size, pos - start_pos[i] + 1, AVINDEX_KEYFRAME);
969
            start_pos[i]= asf_st->packet_pos + 1;
970

971 972 973 974 975 976
            if(pkt->stream_index == stream_index)
               break;
        }
    }

    *ppos= pos;
977
//printf("found keyframe at %"PRId64" stream %d stamp:%"PRId64"\n", *ppos, stream_index, pts);
Michael Niedermayer's avatar
Michael Niedermayer committed
978 979

    return pts;
980 981
}

982 983 984 985 986 987 988 989 990
static void asf_build_simple_index(AVFormatContext *s, int stream_index)
{
    GUID g;
    ASFContext *asf = s->priv_data;
    int64_t gsize, itime;
    int64_t pos, current_pos, index_pts;
    int i;
    int pct,ict;

991
    current_pos = url_ftell(s->pb);
992

993 994
    url_fseek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET);
    get_guid(s->pb, &g);
995
    if (!memcmp(&g, &index_guid, sizeof(GUID))) {
996 997 998 999 1000
        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);
1001
        av_log(NULL, AV_LOG_DEBUG, "itime:0x%"PRIx64", pct:%d, ict:%d\n",itime,pct,ict);
1002 1003

        for (i=0;i<ict;i++){
1004 1005
            int pktnum=get_le32(s->pb);
            int pktct =get_le16(s->pb);
1006 1007 1008 1009 1010 1011 1012
            av_log(NULL, AV_LOG_DEBUG, "pktnum:%d, pktct:%d\n", pktnum, pktct);

            pos=s->data_offset + asf->packet_size*(int64_t)pktnum;
            index_pts=av_rescale(itime, i, 10000);

            av_add_index_entry(s->streams[stream_index], pos, index_pts, asf->packet_size, 0, AVINDEX_KEYFRAME);
        }
1013
        asf->index_read= 1;
1014
    }
1015
    url_fseek(s->pb, current_pos, SEEK_SET);
1016 1017
}

1018
static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags)
1019
{
1020
    ASFContext *asf = s->priv_data;
1021 1022 1023
    AVStream *st = s->streams[stream_index];
    int64_t pos;
    int index;
1024

Michael Niedermayer's avatar
Michael Niedermayer committed
1025
    if (asf->packet_size <= 0)
1026 1027
        return -1;

1028
    /* Try using the protocol's read_seek if available */
1029
    if(s->pb) {
1030 1031 1032
        int ret = av_url_read_fseek(s->pb, stream_index, pts, flags);
        if(ret >= 0)
            asf_reset_header(s);
1033
        if (ret != AVERROR(ENOSYS))
Aurelien Jacobs's avatar
Aurelien Jacobs committed
1034
            return ret;
1035 1036
    }

1037
    if (!asf->index_read)
1038 1039
        asf_build_simple_index(s, stream_index);

1040
    if(!(asf->index_read && st->index_entries)){
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
        if(av_seek_frame_binary(s, stream_index, pts, flags)<0)
            return -1;
    }else{
        index= av_index_search_timestamp(st, pts, flags);
        if(index<0)
            return -1;

        /* find the position */
        pos = st->index_entries[index].pos;
        pts = st->index_entries[index].timestamp;

    // various attempts to find key frame have failed so far
    //    asf_reset_header(s);
1054
    //    url_fseek(s->pb, pos, SEEK_SET);
1055 1056
    //    key_pos = pos;
    //     for(i=0;i<16;i++){
1057
    //         pos = url_ftell(s->pb);
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
    //         if (av_read_frame(s, &pkt) < 0){
    //             av_log(s, AV_LOG_INFO, "seek failed\n");
    //             return -1;
    //         }
    //         asf_st = s->streams[stream_index]->priv_data;
    //         pos += st->parser->frame_offset;
    //
    //         if (pkt.size > b) {
    //             b = pkt.size;
    //             key_pos = pos;
    //         }
    //
    //         av_free_packet(&pkt);
    //     }

        /* do the seek */
1074
        av_log(NULL, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos);
1075
        url_fseek(s->pb, pos, SEEK_SET);
1076
    }
1077 1078
    asf_reset_header(s);
    return 0;
1079 1080
}

1081
AVInputFormat asf_demuxer = {
Fabrice Bellard's avatar
Fabrice Bellard committed
1082
    "asf",
1083
    NULL_IF_CONFIG_SMALL("ASF format"),
Fabrice Bellard's avatar
Fabrice Bellard committed
1084 1085 1086 1087 1088
    sizeof(ASFContext),
    asf_probe,
    asf_read_header,
    asf_read_packet,
    asf_read_close,
1089
    asf_read_seek,
1090
    asf_read_pts,
Fabrice Bellard's avatar
Fabrice Bellard committed
1091
};