asf.c 25.9 KB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
1
/*
2
 * ASF compatible decoder.
3
 * Copyright (c) 2000, 2001 Fabrice Bellard.
Fabrice Bellard's avatar
Fabrice Bellard committed
4
 *
5 6 7 8
 * This library 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 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
9
 *
10
 * This library is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
14
 *
15 16 17
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Fabrice Bellard's avatar
Fabrice Bellard committed
18 19 20
 */
#include "avformat.h"
#include "avi.h"
21
#include "mpegaudio.h"
22
#include "asf.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
23

Michael Niedermayer's avatar
Michael Niedermayer committed
24 25 26
#undef NDEBUG
#include <assert.h>

27 28 29
#define FRAME_HEADER_SIZE 17
// Fix Me! FRAME_HEADER_SIZE may be different. 

Fabrice Bellard's avatar
Fabrice Bellard committed
30 31 32 33 34 35 36 37 38 39
static const GUID index_guid = {
    0x33000890, 0xe5b1, 0x11cf, { 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb },
};

/**********************************/
/* decoding */

//#define DEBUG

#ifdef DEBUG
François Revol's avatar
François Revol committed
40 41 42 43
#define PRINT_IF_GUID(g,cmp) \
if (!memcmp(g, &cmp, sizeof(GUID))) \
    printf("(GUID: %s) ", #cmp)

Fabrice Bellard's avatar
Fabrice Bellard committed
44 45 46
static void print_guid(const GUID *g)
{
    int i;
François Revol's avatar
François Revol committed
47 48 49 50 51 52 53 54 55 56 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);
    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);
    else
        printf("(GUID: unknown) ");
Fabrice Bellard's avatar
Fabrice Bellard committed
64
    printf("0x%08x, 0x%04x, 0x%04x, {", g->v1, g->v2, g->v3);
65
    for(i=0;i<8;i++)
Fabrice Bellard's avatar
Fabrice Bellard committed
66 67 68
        printf(" 0x%02x,", g->v4[i]);
    printf("}\n");
}
François Revol's avatar
François Revol committed
69
#undef PRINT_IF_GUID(g,cmp)
Fabrice Bellard's avatar
Fabrice Bellard committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
#endif

static void get_guid(ByteIOContext *s, GUID *g)
{
    int i;

    g->v1 = get_le32(s);
    g->v2 = get_le16(s);
    g->v3 = get_le16(s);
    for(i=0;i<8;i++)
        g->v4[i] = get_byte(s);
}

#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)
{
    int c;
    char *q;

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

Fabrice Bellard's avatar
Fabrice Bellard committed
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
static int asf_probe(AVProbeData *pd)
{
    GUID g;
    const unsigned char *p;
    int i;

    /* check file header */
    if (pd->buf_size <= 32)
        return 0;
    p = pd->buf;
    g.v1 = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
    p += 4;
    g.v2 = p[0] | (p[1] << 8);
    p += 2;
    g.v3 = p[0] | (p[1] << 8);
    p += 2;
    for(i=0;i<8;i++)
        g.v4[i] = *p++;

    if (!memcmp(&g, &asf_header, sizeof(GUID)))
        return AVPROBE_SCORE_MAX;
    else
        return 0;
}

Fabrice Bellard's avatar
Fabrice Bellard committed
141 142
static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
Fabrice Bellard's avatar
Fabrice Bellard committed
143
    ASFContext *asf = s->priv_data;
Fabrice Bellard's avatar
Fabrice Bellard committed
144 145 146 147
    GUID g;
    ByteIOContext *pb = &s->pb;
    AVStream *st;
    ASFStream *asf_st;
148
    int size, i;
149
    int64_t gsize;
Fabrice Bellard's avatar
Fabrice Bellard committed
150

151 152
    av_set_pts_info(s, 32, 1, 1000); /* 32 bit pts in ms */

Fabrice Bellard's avatar
Fabrice Bellard committed
153 154 155 156 157 158 159
    get_guid(pb, &g);
    if (memcmp(&g, &asf_header, sizeof(GUID)))
        goto fail;
    get_le64(pb);
    get_le32(pb);
    get_byte(pb);
    get_byte(pb);
160
    memset(&asf->asfid2avid, -1, sizeof(asf->asfid2avid));
Fabrice Bellard's avatar
Fabrice Bellard committed
161 162 163 164 165 166 167 168 169 170 171
    for(;;) {
        get_guid(pb, &g);
        gsize = get_le64(pb);
#ifdef DEBUG
        printf("%08Lx: ", url_ftell(pb) - 24);
        print_guid(&g);
        printf("  size=0x%Lx\n", gsize);
#endif
        if (gsize < 24)
            goto fail;
        if (!memcmp(&g, &file_header, sizeof(GUID))) {
172 173 174 175 176 177 178 179 180 181 182 183
            get_guid(pb, &asf->hdr.guid);
	    asf->hdr.file_size		= get_le64(pb);
	    asf->hdr.create_time	= get_le64(pb);
	    asf->hdr.packets_count	= get_le64(pb);
	    asf->hdr.play_time		= get_le64(pb);
	    asf->hdr.send_time		= get_le64(pb);
	    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);
184 185
	    asf->packet_size = asf->hdr.max_pktsize;
            asf->nb_packets = asf->hdr.packets_count;
Fabrice Bellard's avatar
Fabrice Bellard committed
186
        } else if (!memcmp(&g, &stream_header, sizeof(GUID))) {
187
            int type, total_size, type_specific_size;
Fabrice Bellard's avatar
Fabrice Bellard committed
188
            unsigned int tag1;
189
            int64_t pos1, pos2;
190

Fabrice Bellard's avatar
Fabrice Bellard committed
191 192
            pos1 = url_ftell(pb);

193
            st = av_new_stream(s, 0);
Fabrice Bellard's avatar
Fabrice Bellard committed
194 195 196 197 198 199
            if (!st)
                goto fail;
            asf_st = av_mallocz(sizeof(ASFStream));
            if (!asf_st)
                goto fail;
            st->priv_data = asf_st;
200 201 202
            st->start_time = asf->hdr.preroll / (10000000 / AV_TIME_BASE);
	    st->duration = (asf->hdr.send_time - asf->hdr.preroll) / 
                (10000000 / AV_TIME_BASE);
Fabrice Bellard's avatar
Fabrice Bellard committed
203 204 205 206 207 208 209 210 211 212
            get_guid(pb, &g);
            if (!memcmp(&g, &audio_stream, sizeof(GUID))) {
                type = CODEC_TYPE_AUDIO;
            } else if (!memcmp(&g, &video_stream, sizeof(GUID))) {
                type = CODEC_TYPE_VIDEO;
            } else {
                goto fail;
            }
            get_guid(pb, &g);
            total_size = get_le64(pb);
213
            type_specific_size = get_le32(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
214
            get_le32(pb);
215 216
	    st->id = get_le16(pb) & 0x7f; /* stream id */
            // mapping of asf ID to AV stream ID;
217
            asf->asfid2avid[st->id] = s->nb_streams - 1;
218

Fabrice Bellard's avatar
Fabrice Bellard committed
219
            get_le32(pb);
220
	    st->codec.codec_type = type;
221 222 223
            /* 1 fps default (XXX: put 0 fps instead) */
            st->codec.frame_rate = 1; 
            st->codec.frame_rate_base = 1;
Fabrice Bellard's avatar
Fabrice Bellard committed
224
            if (type == CODEC_TYPE_AUDIO) {
225
                get_wav_header(pb, &st->codec, type_specific_size);
226
                st->need_parsing = 1;
227 228
		/* We have to init the frame size at some point .... */
		pos2 = url_ftell(pb);
229
		if (gsize > (pos2 + 8 - pos1 + 24)) {
230 231 232 233 234 235 236 237 238
		    asf_st->ds_span = get_byte(pb);
		    asf_st->ds_packet_size = get_le16(pb);
		    asf_st->ds_chunk_size = get_le16(pb);
		    asf_st->ds_data_size = get_le16(pb);
		    asf_st->ds_silence_data = get_byte(pb);
		}
		//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);
239
		if (asf_st->ds_span > 1) {
240 241 242 243
		    if (!asf_st->ds_chunk_size
			|| (asf_st->ds_packet_size/asf_st->ds_chunk_size <= 1))
			asf_st->ds_span = 0; // disable descrambling
		}
244
                switch (st->codec.codec_id) {
245
                case CODEC_ID_MP3:
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
                    st->codec.frame_size = MPA_FRAME_SIZE;
                    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:
                    st->codec.frame_size = 1;
                    break;
                default:
                    /* This is probably wrong, but it prevents a crash later */
                    st->codec.frame_size = 1;
                    break;
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
263
            } else {
264
		get_le32(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
265 266 267 268 269
                get_le32(pb);
                get_byte(pb);
                size = get_le16(pb); /* size */
                get_le32(pb); /* size */
                st->codec.width = get_le32(pb);
270 271
		st->codec.height = get_le32(pb);
                /* not available for asf */
Fabrice Bellard's avatar
Fabrice Bellard committed
272
                get_le16(pb); /* panes */
Zdenek Kabelac's avatar
Zdenek Kabelac committed
273
		st->codec.bits_per_sample = get_le16(pb); /* depth */
Fabrice Bellard's avatar
Fabrice Bellard committed
274
                tag1 = get_le32(pb);
275 276
		url_fskip(pb, 20);
		if (size > 40) {
277 278 279
		    st->codec.extradata_size = size - 40;
		    st->codec.extradata = av_mallocz(st->codec.extradata_size);
		    get_buffer(pb, st->codec.extradata, st->codec.extradata_size);
280
		}
281 282 283 284 285 286 287

        /* 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 */
        if (st->codec.extradata_size && (st->codec.bits_per_sample <= 8)) {
            st->codec.palctrl = av_mallocz(sizeof(AVPaletteControl));
#ifdef WORDS_BIGENDIAN
288 289
            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]);
290 291 292 293 294 295 296
#else
            memcpy(st->codec.palctrl->palette, st->codec.extradata,
                   FFMIN(st->codec.extradata_size, AVPALETTE_SIZE));
#endif
            st->codec.palctrl->palette_changed = 1;
        }

297
                st->codec.codec_tag = tag1;
298
		st->codec.codec_id = codec_get_id(codec_bmp_tags, tag1);
Fabrice Bellard's avatar
Fabrice Bellard committed
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
            }
            pos2 = url_ftell(pb);
            url_fskip(pb, gsize - (pos2 - pos1 + 24));
        } else if (!memcmp(&g, &data_header, sizeof(GUID))) {
            break;
        } 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);
            get_str16_nolen(pb, len1, s->title, sizeof(s->title));
            get_str16_nolen(pb, len2, s->author, sizeof(s->author));
            get_str16_nolen(pb, len3, s->copyright, sizeof(s->copyright));
            get_str16_nolen(pb, len4, s->comment, sizeof(s->comment));
316
	    url_fskip(pb, len5);
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
       } 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++)
                {
                        int name_len,value_type,value_len,value_num = 0;
                        char *name, *value;

                        name_len = get_le16(pb);
                        name = (char *)av_mallocz(name_len);
                        get_str16_nolen(pb, name_len, name, name_len);
                        value_type = get_le16(pb);
                        value_len = get_le16(pb);
                        if ((value_type == 0) || (value_type == 1)) // unicode or byte
                        {
                                value = (char *)av_mallocz(value_len);
                                get_str16_nolen(pb, value_len, value, value_len);
                                if (strcmp(name,"WM/AlbumTitle")==0) { strcpy(s->album, value); }
                                av_free(value);
                        }
                        if ((value_type >= 2) || (value_type <= 5)) // boolean or DWORD or QWORD or WORD
                        {
                                if (value_type==2) value_num = get_le32(pb);
                                if (value_type==3) value_num = get_le32(pb);
                                if (value_type==4) value_num = get_le64(pb);
                                if (value_type==5) value_num = get_le16(pb);
                                if (strcmp(name,"WM/Track")==0) s->track = value_num + 1;
                                if (strcmp(name,"WM/TrackNumber")==0) s->track = value_num;
                        }
                        av_free(name);
                }
Fabrice Bellard's avatar
Fabrice Bellard committed
349 350 351 352 353 354 355 356 357 358 359 360 361
#if 0
        } else if (!memcmp(&g, &head1_guid, sizeof(GUID))) {
            int v1, v2;
            get_guid(pb, &g);
            v1 = get_le32(pb);
            v2 = get_le16(pb);
        } 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);
362

Fabrice Bellard's avatar
Fabrice Bellard committed
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
            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)) {
            goto fail;
        } else {
            url_fseek(pb, gsize - 24, SEEK_CUR);
        }
    }
    get_guid(pb, &g);
    get_le64(pb);
    get_byte(pb);
    get_byte(pb);
389 390 391
    if (url_feof(pb))
        goto fail;
    asf->data_offset = url_ftell(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
392 393 394 395 396
    asf->packet_size_left = 0;

    return 0;

 fail:
Zdenek Kabelac's avatar
Zdenek Kabelac committed
397
     for(i=0;i<s->nb_streams;i++) {
Fabrice Bellard's avatar
Fabrice Bellard committed
398
        AVStream *st = s->streams[i];
Zdenek Kabelac's avatar
Zdenek Kabelac committed
399
	if (st) {
400
	    av_free(st->priv_data);
Zdenek Kabelac's avatar
Zdenek Kabelac committed
401 402
            av_free(st->codec.extradata);
	}
403
        av_free(st);
Fabrice Bellard's avatar
Fabrice Bellard committed
404 405 406 407
    }
    return -1;
}

408 409 410 411 412 413 414 415 416
#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; \
    }

Fabrice Bellard's avatar
Fabrice Bellard committed
417 418 419 420
static int asf_get_packet(AVFormatContext *s)
{
    ASFContext *asf = s->priv_data;
    ByteIOContext *pb = &s->pb;
421
    uint32_t packet_length, padsize;
Michael Niedermayer's avatar
Michael Niedermayer committed
422 423 424
    int rsize = 9;
    int c;
    
425 426
    if((url_ftell(&s->pb) - s->data_offset) % asf->packet_size)
        return -1;
Michael Niedermayer's avatar
Michael Niedermayer committed
427 428 429
    assert((url_ftell(&s->pb) - s->data_offset) % asf->packet_size == 0);
    
    c = get_byte(pb);
430
    if (c != 0x82) {
431
        if (!url_feof(pb))
432
	    av_log(s, AV_LOG_ERROR, "ff asf bad header %x  at:%lld\n", c, url_ftell(pb));
433 434
    }
    if ((c & 0x0f) == 2) { // always true for now
435
	if (get_le16(pb) != 0) {
436
            if (!url_feof(pb))
437
		av_log(s, AV_LOG_ERROR, "ff asf bad non zero\n");
438 439
	    return -EIO;
	}
Michael Niedermayer's avatar
Michael Niedermayer committed
440 441 442 443 444
        rsize+=2;
/*    }else{
        if (!url_feof(pb))
	    printf("ff asf bad header %x  at:%lld\n", c, url_ftell(pb));
	return -EIO;*/
Fabrice Bellard's avatar
Fabrice Bellard committed
445
    }
446 447 448 449 450 451 452 453 454

    asf->packet_flags = get_byte(pb);
    asf->packet_property = get_byte(pb);

    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

    asf->packet_timestamp = get_le32(pb);
Fabrice Bellard's avatar
Fabrice Bellard committed
455
    get_le16(pb); /* duration */
456
    // rsize has at least 11 bytes which have to be present
457 458 459 460 461 462 463 464 465

    if (asf->packet_flags & 0x01) {
	asf->packet_segsizetype = get_byte(pb); rsize++;
        asf->packet_segments = asf->packet_segsizetype & 0x3f;
    } else {
	asf->packet_segments = 1;
        asf->packet_segsizetype = 0x80;
    }
    asf->packet_size_left = packet_length - padsize - rsize;
466 467
    if (packet_length < asf->hdr.min_pktsize)
        padsize += asf->hdr.min_pktsize - packet_length;
468
    asf->packet_padsize = padsize;
Fabrice Bellard's avatar
Fabrice Bellard committed
469
#ifdef DEBUG
470
    printf("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
471 472 473 474 475 476 477
#endif
    return 0;
}

static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    ASFContext *asf = s->priv_data;
478
    ASFStream *asf_st = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
479
    ByteIOContext *pb = &s->pb;
480
    //static int pc = 0;
481 482
    for (;;) {
	int rsize = 0;
483
	if (asf->packet_size_left < FRAME_HEADER_SIZE
484
	    || asf->packet_segments < 1) {
485
	    //asf->packet_size_left <= asf->packet_padsize) {
486 487 488 489
	    int ret = asf->packet_size_left + asf->packet_padsize;
	    //printf("PacketLeftSize:%d  Pad:%d Pos:%Ld\n", asf->packet_size_left, asf->packet_padsize, url_ftell(pb));
	    /* fail safe */
	    url_fskip(pb, ret);
Michael Niedermayer's avatar
Michael Niedermayer committed
490
            asf->packet_pos= url_ftell(&s->pb);
491 492
	    ret = asf_get_packet(s);
	    //printf("READ ASF PACKET  %d   r:%d   c:%d\n", ret, asf->packet_size_left, pc++);
493
	    if (ret < 0 || url_feof(pb))
494
		return -EIO;
495
            asf->packet_time_start = 0;
496 497
            continue;
	}
498
	if (asf->packet_time_start == 0) {
499
	    /* read frame header */
500 501
            int num = get_byte(pb);
	    asf->packet_segments--;
502 503 504 505 506 507 508
	    rsize++;
	    asf->packet_key_frame = (num & 0x80) >> 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);
Michael Niedermayer's avatar
Michael Niedermayer committed
509
//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);
510
	    if (asf->packet_replic_size > 1) {
511
                assert(asf->packet_replic_size >= 8);
512 513 514
                // it should be always at least 8 bytes - FIXME validate
		asf->packet_obj_size = get_le32(pb);
		asf->packet_frag_timestamp = get_le32(pb); // timestamp
515 516
		if (asf->packet_replic_size > 8)
		    url_fskip(pb, asf->packet_replic_size - 8);
517
		rsize += asf->packet_replic_size; // FIXME - check validity
518
	    } else if (asf->packet_replic_size==1){
519
		// multipacket - frag_offset is begining timestamp
520 521 522
		asf->packet_time_start = asf->packet_frag_offset;
                asf->packet_frag_offset = 0;
		asf->packet_frag_timestamp = asf->packet_timestamp;
523

524 525 526 527 528
                asf->packet_time_delta = get_byte(pb);
		rsize++;
	    }else{
                assert(asf->packet_replic_size==0);
            }
529 530
	    if (asf->packet_flags & 0x01) {
		DO_2BITS(asf->packet_segsizetype >> 6, asf->packet_frag_size, 0); // 0 is illegal
531
#undef DO_2BITS
532 533 534 535 536
		//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);
	    }
537
	    if (asf->packet_replic_size == 1) {
538
		asf->packet_multi_size = asf->packet_frag_size;
539
		if (asf->packet_multi_size > asf->packet_size_left) {
540 541 542 543
		    asf->packet_segments = 0;
                    continue;
		}
	    }
544 545
	    asf->packet_size_left -= rsize;
	    //printf("___objsize____  %d   %d    rs:%d\n", asf->packet_obj_size, asf->packet_frag_offset, rsize);
546 547 548 549 550 551

	    if (asf->stream_index < 0) {
                asf->packet_time_start = 0;
		/* unhandled packet (should not happen) */
		url_fskip(pb, asf->packet_frag_size);
		asf->packet_size_left -= asf->packet_frag_size;
552
		av_log(s, AV_LOG_ERROR, "ff asf skip %d  %d\n", asf->packet_frag_size, num & 0x7f);
553 554 555
                continue;
	    }
	    asf->asf_st = s->streams[asf->stream_index]->priv_data;
556 557 558 559 560 561 562 563 564
	}
	asf_st = asf->asf_st;

	if ((asf->packet_frag_offset != asf_st->frag_offset
	     || (asf->packet_frag_offset
		 && asf->packet_seq != asf_st->seq)) // seq should be ignored
	   ) {
	    /* cannot continue current packet: free it */
	    // FIXME better check if packet was already allocated
565
	    av_log(s, AV_LOG_INFO, "ff asf parser skips: %d - %d     o:%d - %d    %d %d   fl:%d\n",
566
		   asf_st->pkt.size,
567
		   asf->packet_obj_size,
568 569
		   asf->packet_frag_offset, asf_st->frag_offset,
		   asf->packet_seq, asf_st->seq, asf->packet_frag_size);
570
	    if (asf_st->pkt.size)
571 572 573 574
		av_free_packet(&asf_st->pkt);
	    asf_st->frag_offset = 0;
	    if (asf->packet_frag_offset != 0) {
		url_fskip(pb, asf->packet_frag_size);
575
		av_log(s, AV_LOG_INFO, "ff asf parser skiping %db\n", asf->packet_frag_size);
576
		asf->packet_size_left -= asf->packet_frag_size;
577 578 579
		continue;
	    }
	}
580 581
	if (asf->packet_replic_size == 1) {
	    // frag_offset is here used as the begining timestamp
582
	    asf->packet_frag_timestamp = asf->packet_time_start;
583
	    asf->packet_time_start += asf->packet_time_delta;
584
	    asf->packet_obj_size = asf->packet_frag_size = get_byte(pb);
585 586 587 588 589 590 591 592 593 594 595
	    asf->packet_size_left--;
            asf->packet_multi_size--;
	    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;
                continue;
	    }
	    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);
596 597 598 599 600 601 602
	}
	if (asf_st->frag_offset == 0) {
	    /* 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->hdr.preroll;
	    asf_st->pkt.stream_index = asf->stream_index;
603 604
            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
605
//asf->stream_index, asf->packet_key_frame, asf_st->pkt.flags & PKT_FLAG_KEY,
606
//s->streams[asf->stream_index]->codec.codec_type == CODEC_TYPE_AUDIO, asf->packet_obj_size);
607 608
	    if (s->streams[asf->stream_index]->codec.codec_type == CODEC_TYPE_AUDIO) 
		asf->packet_key_frame = 1;
609 610 611 612 613 614 615 616
	    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);
617 618 619
	asf->packet_size_left -= asf->packet_frag_size;
	if (asf->packet_size_left < 0)
            continue;
620 621 622 623 624 625 626
	get_buffer(pb, asf_st->pkt.data + asf->packet_frag_offset,
		   asf->packet_frag_size);
	asf_st->frag_offset += asf->packet_frag_size;
	/* test if whole packet is read */
	if (asf_st->frag_offset == asf_st->pkt.size) {
	    /* return packet */
	    if (asf_st->ds_span > 1) {
627
		/* packet descrambling */
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
		char* newdata = av_malloc(asf_st->pkt.size);
		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);
			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;
		}
	    }
	    asf_st->frag_offset = 0;
	    memcpy(pkt, &asf_st->pkt, sizeof(AVPacket));
	    //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
653 654 655 656 657 658 659 660 661
    }
    return 0;
}

static int asf_read_close(AVFormatContext *s)
{
    int i;

    for(i=0;i<s->nb_streams;i++) {
Zdenek Kabelac's avatar
Zdenek Kabelac committed
662 663 664
	AVStream *st = s->streams[i];
	av_free(st->priv_data);
	av_free(st->codec.extradata);
665
    av_free(st->codec.palctrl);
Fabrice Bellard's avatar
Fabrice Bellard committed
666 667 668 669
    }
    return 0;
}

670 671 672 673 674 675
// 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
676 677
    ASFStream *asf_st;
    int i;
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699

    asf->packet_nb_frames = 0;
    asf->packet_timestamp_start = -1;
    asf->packet_timestamp_end = -1;
    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;
Michael Niedermayer's avatar
Michael Niedermayer committed
700 701 702 703 704 705 706 707
    
    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;
708 709
}

710
static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit)
711 712 713
{
    ASFContext *asf = s->priv_data;
    AVPacket pkt1, *pkt = &pkt1;
Michael Niedermayer's avatar
Michael Niedermayer committed
714
    ASFStream *asf_st;
Michael Niedermayer's avatar
Michael Niedermayer committed
715
    int64_t pts;
Michael Niedermayer's avatar
Michael Niedermayer committed
716
    int64_t pos= *ppos;
717 718 719 720 721 722
    int i;
    int64_t start_pos[s->nb_streams];
    
    for(i=0; i<s->nb_streams; i++){
        start_pos[i]= pos;
    }
723 724 725 726 727
    
    pos= (pos+asf->packet_size-1-s->data_offset)/asf->packet_size*asf->packet_size+ s->data_offset;
    *ppos= pos;
    url_fseek(&s->pb, pos, SEEK_SET);
    
Michael Niedermayer's avatar
Michael Niedermayer committed
728 729
//printf("asf_read_pts\n");
    asf_reset_header(s);
730
    for(;;){
Michael Niedermayer's avatar
Michael Niedermayer committed
731
        if (av_read_frame(s, pkt) < 0){
732
            av_log(s, AV_LOG_INFO, "seek failed\n");
Michael Niedermayer's avatar
Michael Niedermayer committed
733
    	    return AV_NOPTS_VALUE;
Michael Niedermayer's avatar
Michael Niedermayer committed
734
        }
735
        
Michael Niedermayer's avatar
Michael Niedermayer committed
736 737 738
        pts= pkt->pts;

        av_free_packet(pkt);
739 740 741 742 743 744
        if(pkt->flags&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);
745
            pos= asf_st->packet_pos;
746

747
            av_add_index_entry(s->streams[i], pos, pts, pos - start_pos[i] + 1, AVINDEX_KEYFRAME);
748
            start_pos[i]= asf_st->packet_pos + 1;
749 750 751 752 753 754 755
            
            if(pkt->stream_index == stream_index)
               break;
        }
    }

    *ppos= pos;
Michael Niedermayer's avatar
Michael Niedermayer committed
756
//printf("found keyframe at %Ld stream %d stamp:%Ld\n", *ppos, stream_index, pts);
Michael Niedermayer's avatar
Michael Niedermayer committed
757 758

    return pts;
759 760
}

761
static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts)
762
{
763
    ASFContext *asf = s->priv_data;
Michael Niedermayer's avatar
Michael Niedermayer committed
764
    
Michael Niedermayer's avatar
Michael Niedermayer committed
765
    if (asf->packet_size <= 0)
766 767
        return -1;

768 769
    if(av_seek_frame_binary(s, stream_index, pts)<0)
        return -1;
770

771 772
    asf_reset_header(s);
    return 0;
773 774
}

775
static AVInputFormat asf_iformat = {
Fabrice Bellard's avatar
Fabrice Bellard committed
776 777 778 779 780 781 782
    "asf",
    "asf format",
    sizeof(ASFContext),
    asf_probe,
    asf_read_header,
    asf_read_packet,
    asf_read_close,
783
    asf_read_seek,
784
    asf_read_pts,
Fabrice Bellard's avatar
Fabrice Bellard committed
785 786
};

787
#ifdef CONFIG_ENCODERS
788 789
    extern AVOutputFormat asf_oformat;
    extern AVOutputFormat asf_stream_oformat;
790
#endif //CONFIG_ENCODERS
791

Fabrice Bellard's avatar
Fabrice Bellard committed
792 793 794
int asf_init(void)
{
    av_register_input_format(&asf_iformat);
795
#ifdef CONFIG_ENCODERS
Fabrice Bellard's avatar
Fabrice Bellard committed
796
    av_register_output_format(&asf_oformat);
797
    av_register_output_format(&asf_stream_oformat);
798
#endif //CONFIG_ENCODERS
Fabrice Bellard's avatar
Fabrice Bellard committed
799 800
    return 0;
}