Statistics
| Branch: | Revision:

ffmpeg / libav / asf.c @ 390dffc5

History | View | Annotate | Download (30.7 KB)

1
/*
2
 * ASF compatible encoder and decoder.
3
 * Copyright (c) 2000, 2001 Fabrice Bellard.
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 */
19
#include "avformat.h"
20
#include "avi.h"
21
#include "tick.h"
22
#include "mpegaudio.h"
23

    
24
#define PACKET_SIZE 3200
25
#define PACKET_HEADER_SIZE 12
26
#define FRAME_HEADER_SIZE 17
27

    
28
typedef struct {
29
    int num;
30
    int seq;
31
    Ticker pts_ticker;
32
    /* use for reading */
33
    AVPacket pkt;
34
    int frag_offset;
35
    INT64 duration;
36
} ASFStream;
37

    
38
typedef struct {
39
    int seqno;
40
    int packet_size;
41

    
42
    ASFStream streams[2];
43
    /* non streamed additonnal info */
44
    int data_offset;
45
    INT64 nb_packets;
46
    INT64 duration; /* in 100ns units */
47
    /* packet filling */
48
    int packet_size_left;
49
    int packet_timestamp_start;
50
    int packet_timestamp_end;
51
    int packet_nb_frames;
52
    UINT8 packet_buf[PACKET_SIZE];
53
    ByteIOContext pb;
54
    /* only for reading */
55
    int packet_padsize;
56
} ASFContext;
57

    
58
typedef struct {
59
    UINT32 v1;
60
    UINT16 v2;
61
    UINT16 v3;
62
    UINT8 v4[8];
63
} GUID;
64

    
65
static const GUID asf_header = {
66
    0x75B22630, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C },
67
};
68

    
69
static const GUID file_header = {
70
    0x8CABDCA1, 0xA947, 0x11CF, { 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 },
71
};
72

    
73
static const GUID stream_header = {
74
    0xB7DC0791, 0xA9B7, 0x11CF, { 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 },
75
};
76

    
77
static const GUID audio_stream = {
78
    0xF8699E40, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
79
};
80

    
81
static const GUID audio_conceal_none = {
82
    // 0x49f1a440, 0x4ece, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 },
83
    // New value lifted from avifile
84
    0x20fb5700, 0x5b55, 0x11cf, { 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b },
85
};
86

    
87
static const GUID video_stream = {
88
    0xBC19EFC0, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
89
};
90

    
91
static const GUID video_conceal_none = {
92
    0x20FB5700, 0x5B55, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
93
};
94

    
95

    
96
static const GUID comment_header = {
97
    0x75b22633, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c },
98
};
99

    
100
static const GUID codec_comment_header = {
101
    0x86D15240, 0x311D, 0x11D0, { 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 },
102
};
103
static const GUID codec_comment1_header = {
104
    0x86d15241, 0x311d, 0x11d0, { 0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 },
105
};
106

    
107
static const GUID data_header = {
108
    0x75b22636, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c },
109
};
110

    
111
static const GUID index_guid = {
112
    0x33000890, 0xe5b1, 0x11cf, { 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb },
113
};
114

    
115
static const GUID head1_guid = {
116
    0x5fbf03b5, 0xa92e, 0x11cf, { 0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 },
117
};
118

    
119
static const GUID head2_guid = {
120
    0xabd3d211, 0xa9ba, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 },
121
};
122
    
123
/* I am not a number !!! This GUID is the one found on the PC used to
124
   generate the stream */
125
static const GUID my_guid = {
126
    0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 },
127
};
128

    
129
CodecTag codec_asf_bmp_tags[] = {
130
    { CODEC_ID_H263, MKTAG('H', '2', '6', '3') },
131
    { CODEC_ID_H263P, MKTAG('H', '2', '6', '3') },
132
    { CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* intel h263 */
133
    { CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') },
134
    { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X') },
135
    { CODEC_ID_MPEG4, MKTAG('d', 'i', 'v', 'x') },
136
    { CODEC_ID_MPEG4, MKTAG('D', 'X', '5', '0') },
137
    { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') },
138
    { CODEC_ID_MPEG4, MKTAG('x', 'v', 'i', 'd') },
139
    { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 's') },
140
    { CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') },
141
    { CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') },
142
    { CODEC_ID_MPEG4, MKTAG('m', '4', 's', '2') },
143
    { CODEC_ID_MPEG4, MKTAG(0x04, 0, 0, 0) }, /* some broken avi use this */
144
    { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') }, /* default signature when using MSMPEG4 */ 
145
    { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '3') },
146
    { CODEC_ID_MSMPEG4V2, MKTAG('M', 'P', '4', '2') }, 
147
    { CODEC_ID_MSMPEG4V1, MKTAG('M', 'P', 'G', '4') }, 
148
    { CODEC_ID_WMV1, MKTAG('W', 'M', 'V', '1') }, 
149
    { 0, 0 },
150
};
151

    
152

    
153

    
154
static void put_guid(ByteIOContext *s, const GUID *g)
155
{
156
    int i;
157

    
158
    put_le32(s, g->v1);
159
    put_le16(s, g->v2);
160
    put_le16(s, g->v3);
161
    for(i=0;i<8;i++)
162
        put_byte(s, g->v4[i]);
163
}
164

    
165
static void put_str16(ByteIOContext *s, const char *tag)
166
{
167
    int c;
168

    
169
    put_le16(s,strlen(tag) + 1);
170
    for(;;) {
171
        c = (UINT8)*tag++;
172
        put_le16(s, c);
173
        if (c == '\0') 
174
            break;
175
    }
176
}
177

    
178
static void put_str16_nolen(ByteIOContext *s, const char *tag)
179
{
180
    int c;
181

    
182
    for(;;) {
183
        c = (UINT8)*tag++;
184
        put_le16(s, c);
185
        if (c == '\0') 
186
            break;
187
    }
188
}
189

    
190
static INT64 put_header(ByteIOContext *pb, const GUID *g)
191
{
192
    INT64 pos;
193

    
194
    pos = url_ftell(pb);
195
    put_guid(pb, g);
196
    put_le64(pb, 24);
197
    return pos;
198
}
199

    
200
/* update header size */
201
static void end_header(ByteIOContext *pb, INT64 pos)
202
{
203
    INT64 pos1;
204

    
205
    pos1 = url_ftell(pb);
206
    url_fseek(pb, pos + 16, SEEK_SET);
207
    put_le64(pb, pos1 - pos);
208
    url_fseek(pb, pos1, SEEK_SET);
209
}
210

    
211
/* write an asf chunk (only used in streaming case) */
212
static void put_chunk(AVFormatContext *s, int type, int payload_length, int flags)
213
{
214
    ASFContext *asf = s->priv_data;
215
    ByteIOContext *pb = &s->pb;
216
    int length;
217

    
218
    length = payload_length + 8;
219
    put_le16(pb, type); 
220
    put_le16(pb, length); 
221
    put_le32(pb, asf->seqno);
222
    put_le16(pb, flags); /* unknown bytes */
223
    put_le16(pb, length);
224
    asf->seqno++;
225
}
226

    
227
/* convert from unix to windows time */
228
static INT64 unix_to_file_time(int ti)
229
{
230
    INT64 t;
231
    
232
    t = ti * INT64_C(10000000);
233
    t += INT64_C(116444736000000000);
234
    return t;
235
}
236

    
237
/* write the header (used two times if non streamed) */
238
static int asf_write_header1(AVFormatContext *s, INT64 file_size, INT64 data_chunk_size)
239
{
240
    ASFContext *asf = s->priv_data;
241
    ByteIOContext *pb = &s->pb;
242
    int header_size, n, extra_size, extra_size2, wav_extra_size, file_time;
243
    int has_title;
244
    AVCodecContext *enc;
245
    INT64 header_offset, cur_pos, hpos;
246
    int bit_rate;
247

    
248
    has_title = (s->title[0] || s->author[0] || s->copyright[0] || s->comment[0]);
249

    
250
    bit_rate = 0;
251
    for(n=0;n<s->nb_streams;n++) {
252
        enc = &s->streams[n]->codec;
253

    
254
        bit_rate += enc->bit_rate;
255
    }
256

    
257
    if (url_is_streamed(&s->pb)) {
258
        put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */
259
    }
260

    
261
    put_guid(pb, &asf_header);
262
    put_le64(pb, 0); /* header length, will be patched after */
263
    put_le32(pb, 3 + has_title + s->nb_streams); /* number of chunks in header */
264
    put_byte(pb, 1); /* ??? */
265
    put_byte(pb, 2); /* ??? */
266
    
267
    /* file header */
268
    header_offset = url_ftell(pb);
269
    hpos = put_header(pb, &file_header);
270
    put_guid(pb, &my_guid);
271
    put_le64(pb, file_size);
272
    file_time = 0;
273
    put_le64(pb, unix_to_file_time(file_time));
274
    put_le64(pb, asf->nb_packets); /* number of packets */
275
    put_le64(pb, asf->duration); /* end time stamp (in 100ns units) */
276
    put_le64(pb, asf->duration); /* duration (in 100ns units) */
277
    put_le32(pb, 0); /* start time stamp */ 
278
    put_le32(pb, 0); /* ??? */ 
279
    put_le32(pb, url_is_streamed(&s->pb) ? 1 : 0); /* ??? */ 
280
    put_le32(pb, asf->packet_size); /* packet size */
281
    put_le32(pb, asf->packet_size); /* packet size */
282
    put_le32(pb, bit_rate); /* Nominal data rate in bps */
283
    end_header(pb, hpos);
284

    
285
    /* unknown headers */
286
    hpos = put_header(pb, &head1_guid);
287
    put_guid(pb, &head2_guid);
288
    put_le32(pb, 6);
289
    put_le16(pb, 0);
290
    end_header(pb, hpos);
291

    
292
    /* title and other infos */
293
    if (has_title) {
294
        hpos = put_header(pb, &comment_header);
295
        put_le16(pb, 2 * (strlen(s->title) + 1));
296
        put_le16(pb, 2 * (strlen(s->author) + 1));
297
        put_le16(pb, 2 * (strlen(s->copyright) + 1));
298
        put_le16(pb, 2 * (strlen(s->comment) + 1));
299
        put_le16(pb, 0);
300
        put_str16_nolen(pb, s->title);
301
        put_str16_nolen(pb, s->author);
302
        put_str16_nolen(pb, s->copyright);
303
        put_str16_nolen(pb, s->comment);
304
        end_header(pb, hpos);
305
    }
306

    
307
    /* stream headers */
308
    for(n=0;n<s->nb_streams;n++) {
309
        INT64 es_pos;
310
        ASFStream *stream = &asf->streams[n];
311

    
312
        enc = &s->streams[n]->codec;
313
        asf->streams[n].num = n + 1;
314
        asf->streams[n].seq = 0;
315
        
316
        switch(enc->codec_type) {
317
        case CODEC_TYPE_AUDIO:
318
            wav_extra_size = 0;
319
            extra_size = 18 + wav_extra_size;
320
            extra_size2 = 0;
321
            /* Init the ticker */
322
            ticker_init(&stream->pts_ticker,
323
                        enc->sample_rate,
324
                        1000 * enc->frame_size);
325
            break;
326
        default:
327
        case CODEC_TYPE_VIDEO:
328
            wav_extra_size = 0;
329
            extra_size = 0x33;
330
            extra_size2 = 0;
331
            /* Init the ticker */
332
            ticker_init(&stream->pts_ticker,
333
                        enc->frame_rate,
334
                        1000 * FRAME_RATE_BASE);
335
            break;
336
        }
337

    
338
        hpos = put_header(pb, &stream_header);
339
        if (enc->codec_type == CODEC_TYPE_AUDIO) {
340
            put_guid(pb, &audio_stream);
341
            put_guid(pb, &audio_conceal_none);
342
        } else {
343
            put_guid(pb, &video_stream);
344
            put_guid(pb, &video_conceal_none);
345
        }
346
        put_le64(pb, 0); /* ??? */
347
        es_pos = url_ftell(pb);
348
        put_le32(pb, extra_size); /* wav header len */
349
        put_le32(pb, extra_size2); /* additional data len */
350
        put_le16(pb, n + 1); /* stream number */
351
        put_le32(pb, 0); /* ??? */
352
        
353
        if (enc->codec_type == CODEC_TYPE_AUDIO) {
354
            /* WAVEFORMATEX header */
355
            int wavsize = put_wav_header(pb, enc);
356

    
357
            if (wavsize < 0)
358
                return -1;
359
            if (wavsize != extra_size) {
360
                cur_pos = url_ftell(pb);
361
                url_fseek(pb, es_pos, SEEK_SET);
362
                put_le32(pb, wavsize); /* wav header len */
363
                url_fseek(pb, cur_pos, SEEK_SET);
364
            }
365
        } else {
366
            put_le32(pb, enc->width);
367
            put_le32(pb, enc->height);
368
            put_byte(pb, 2); /* ??? */
369
            put_le16(pb, 40); /* size */
370

    
371
            /* BITMAPINFOHEADER header */
372
            put_bmp_header(pb, enc, codec_asf_bmp_tags);
373
        }
374
        end_header(pb, hpos);
375
    }
376

    
377
    /* media comments */
378

    
379
    hpos = put_header(pb, &codec_comment_header);
380
    put_guid(pb, &codec_comment1_header);
381
    put_le32(pb, s->nb_streams);
382
    for(n=0;n<s->nb_streams;n++) {
383
        AVCodec *p;
384

    
385
        enc = &s->streams[n]->codec;
386
        p = avcodec_find_encoder(enc->codec_id);
387

    
388
        put_le16(pb, asf->streams[n].num);
389
        put_str16(pb, p ? p->name : enc->codec_name);
390
        put_le16(pb, 0); /* no parameters */
391
        /* id */
392
        if (enc->codec_type == CODEC_TYPE_AUDIO) {
393
            put_le16(pb, 2);
394
            put_le16(pb, codec_get_tag(codec_wav_tags, enc->codec_id));
395
        } else {
396
            put_le16(pb, 4);
397
            put_le32(pb, codec_get_tag(codec_asf_bmp_tags, enc->codec_id));
398
        }
399
    }
400
    end_header(pb, hpos);
401

    
402
    /* patch the header size fields */
403

    
404
    cur_pos = url_ftell(pb);
405
    header_size = cur_pos - header_offset;
406
    if (url_is_streamed(&s->pb)) {
407
        header_size += 8 + 30 + 50;
408

    
409
        url_fseek(pb, header_offset - 10 - 30, SEEK_SET);
410
        put_le16(pb, header_size);
411
        url_fseek(pb, header_offset - 2 - 30, SEEK_SET);
412
        put_le16(pb, header_size);
413

    
414
        header_size -= 8 + 30 + 50;
415
    }
416
    header_size += 24 + 6;
417
    url_fseek(pb, header_offset - 14, SEEK_SET);
418
    put_le64(pb, header_size);
419
    url_fseek(pb, cur_pos, SEEK_SET);
420

    
421
    /* movie chunk, followed by packets of packet_size */
422
    asf->data_offset = cur_pos;
423
    put_guid(pb, &data_header);
424
    put_le64(pb, data_chunk_size);
425
    put_guid(pb, &my_guid);
426
    put_le64(pb, asf->nb_packets); /* nb packets */
427
    put_byte(pb, 1); /* ??? */
428
    put_byte(pb, 1); /* ??? */
429
    return 0;
430
}
431

    
432
static int asf_write_header(AVFormatContext *s)
433
{
434
    ASFContext *asf = s->priv_data;
435

    
436
    asf->packet_size = PACKET_SIZE;
437
    asf->nb_packets = 0;
438

    
439
    if (asf_write_header1(s, 0, 50) < 0) {
440
        //av_free(asf);
441
        return -1;
442
    }
443

    
444
    put_flush_packet(&s->pb);
445

    
446
    asf->packet_nb_frames = 0;
447
    asf->packet_timestamp_start = -1;
448
    asf->packet_timestamp_end = -1;
449
    asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
450
    init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size, 1,
451
                  NULL, NULL, NULL, NULL);
452

    
453
    return 0;
454
}
455

    
456
/* write a fixed size packet */
457
static int put_packet(AVFormatContext *s, 
458
                       unsigned int timestamp, unsigned int duration, 
459
                       int nb_frames, int padsize)
460
{
461
    ASFContext *asf = s->priv_data;
462
    ByteIOContext *pb = &s->pb;
463
    int flags;
464

    
465
    if (url_is_streamed(&s->pb)) {
466
        put_chunk(s, 0x4424, asf->packet_size, 0);
467
    }
468

    
469
    put_byte(pb, 0x82);
470
    put_le16(pb, 0);
471
    
472
    flags = 0x01; /* nb segments present */
473
    if (padsize > 0) {
474
        if (padsize < 256)
475
            flags |= 0x08;
476
        else
477
            flags |= 0x10;
478
    }
479
    put_byte(pb, flags); /* flags */
480
    put_byte(pb, 0x5d);
481
    if (flags & 0x10)
482
        put_le16(pb, padsize - 2);
483
    if (flags & 0x08)
484
        put_byte(pb, padsize - 1);
485
    put_le32(pb, timestamp);
486
    put_le16(pb, duration);
487
    put_byte(pb, nb_frames | 0x80);
488

    
489
    return PACKET_HEADER_SIZE + ((flags & 0x18) >> 3);
490
}
491

    
492
static void flush_packet(AVFormatContext *s)
493
{
494
    ASFContext *asf = s->priv_data;
495
    int hdr_size, ptr;
496
    
497
    hdr_size = put_packet(s, asf->packet_timestamp_start, 
498
               asf->packet_timestamp_end - asf->packet_timestamp_start, 
499
               asf->packet_nb_frames, asf->packet_size_left);
500
    
501
    /* Clear out the padding bytes */
502
    ptr = asf->packet_size - hdr_size - asf->packet_size_left;
503
    memset(asf->packet_buf + ptr, 0, asf->packet_size_left);
504
    
505
    put_buffer(&s->pb, asf->packet_buf, asf->packet_size - hdr_size);
506
    
507
    put_flush_packet(&s->pb);
508
    asf->nb_packets++;
509
    asf->packet_nb_frames = 0;
510
    asf->packet_timestamp_start = -1;
511
    asf->packet_timestamp_end = -1;
512
    asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
513
    init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size, 1,
514
                  NULL, NULL, NULL, NULL);
515
}
516

    
517
static void put_frame_header(AVFormatContext *s, ASFStream *stream, int timestamp,
518
                             int payload_size, int frag_offset, int frag_len)
519
{
520
    ASFContext *asf = s->priv_data;
521
    ByteIOContext *pb = &asf->pb;
522
    int val;
523

    
524
    val = stream->num;
525
    if (s->streams[val - 1]->codec.key_frame /* && frag_offset == 0 */)
526
        val |= 0x80;
527
    put_byte(pb, val);
528
    put_byte(pb, stream->seq);
529
    put_le32(pb, frag_offset); /* fragment offset */
530
    put_byte(pb, 0x08); /* flags */
531
    put_le32(pb, payload_size);
532
    put_le32(pb, timestamp);
533
    put_le16(pb, frag_len);
534
}
535

    
536

    
537
/* Output a frame. We suppose that payload_size <= PACKET_SIZE.
538

539
   It is there that you understand that the ASF format is really
540
   crap. They have misread the MPEG Systems spec ! 
541
 */
542
static void put_frame(AVFormatContext *s, ASFStream *stream, int timestamp,
543
                      UINT8 *buf, int payload_size)
544
{
545
    ASFContext *asf = s->priv_data;
546
    int frag_pos, frag_len, frag_len1;
547
    
548
    frag_pos = 0;
549
    while (frag_pos < payload_size) {
550
        frag_len = payload_size - frag_pos;
551
        frag_len1 = asf->packet_size_left - FRAME_HEADER_SIZE;
552
        if (frag_len1 > 0) {
553
            if (frag_len > frag_len1)
554
                frag_len = frag_len1;
555
            put_frame_header(s, stream, timestamp, payload_size, frag_pos, frag_len);
556
            put_buffer(&asf->pb, buf, frag_len);
557
            asf->packet_size_left -= (frag_len + FRAME_HEADER_SIZE);
558
            asf->packet_timestamp_end = timestamp;
559
            if (asf->packet_timestamp_start == -1)
560
                asf->packet_timestamp_start = timestamp;
561
            asf->packet_nb_frames++;
562
        } else {
563
            frag_len = 0;
564
        }
565
        frag_pos += frag_len;
566
        buf += frag_len;
567
        /* output the frame if filled */
568
        if (asf->packet_size_left <= FRAME_HEADER_SIZE)
569
            flush_packet(s);
570
    }
571
    stream->seq++;
572
}
573

    
574

    
575
static int asf_write_packet(AVFormatContext *s, int stream_index,
576
                            UINT8 *buf, int size, int force_pts)
577
{
578
    ASFContext *asf = s->priv_data;
579
    ASFStream *stream;
580
    int timestamp;
581
    INT64 duration;
582
    AVCodecContext *codec;
583

    
584
    stream = &asf->streams[stream_index];
585
    codec = &s->streams[stream_index]->codec;
586
    stream = &asf->streams[stream_index];
587
    
588
    if (codec->codec_type == CODEC_TYPE_AUDIO) {
589
        timestamp = (int)ticker_abs(&stream->pts_ticker, codec->frame_number);
590
        duration = (codec->frame_number * codec->frame_size * INT64_C(10000000)) / 
591
            codec->sample_rate;
592
    } else {
593
        timestamp = (int)ticker_abs(&stream->pts_ticker, codec->frame_number);
594
        duration = codec->frame_number * 
595
            ((INT64_C(10000000) * FRAME_RATE_BASE) / codec->frame_rate);
596
    }
597
    if (duration > asf->duration)
598
        asf->duration = duration;
599
    
600
    put_frame(s, stream, timestamp, buf, size);
601
    return 0;
602
}
603
    
604
static int asf_write_trailer(AVFormatContext *s)
605
{
606
    ASFContext *asf = s->priv_data;
607
    INT64 file_size;
608

    
609
    /* flush the current packet */
610
    if (asf->pb.buf_ptr > asf->pb.buffer)
611
        flush_packet(s);
612

    
613
    if (url_is_streamed(&s->pb)) {
614
        put_chunk(s, 0x4524, 0, 0); /* end of stream */
615
    } else {
616
        /* rewrite an updated header */
617
        file_size = url_ftell(&s->pb);
618
        url_fseek(&s->pb, 0, SEEK_SET);
619
        asf_write_header1(s, file_size, file_size - asf->data_offset);
620
    }
621

    
622
    put_flush_packet(&s->pb);
623
    return 0;
624
}
625

    
626
/**********************************/
627
/* decoding */
628

    
629
//#define DEBUG
630

    
631
#ifdef DEBUG
632
static void print_guid(const GUID *g)
633
{
634
    int i;
635
    printf("0x%08x, 0x%04x, 0x%04x, {", g->v1, g->v2, g->v3);
636
    for(i=0;i<8;i++) 
637
        printf(" 0x%02x,", g->v4[i]);
638
    printf("}\n");
639
}
640
#endif
641

    
642
static void get_guid(ByteIOContext *s, GUID *g)
643
{
644
    int i;
645

    
646
    g->v1 = get_le32(s);
647
    g->v2 = get_le16(s);
648
    g->v3 = get_le16(s);
649
    for(i=0;i<8;i++)
650
        g->v4[i] = get_byte(s);
651
}
652

    
653
#if 0
654
static void get_str16(ByteIOContext *pb, char *buf, int buf_size)
655
{
656
    int len, c;
657
    char *q;
658

659
    len = get_le16(pb);
660
    q = buf;
661
    while (len > 0) {
662
        c = get_le16(pb);
663
        if ((q - buf) < buf_size - 1)
664
            *q++ = c;
665
        len--;
666
    }
667
    *q = '\0';
668
}
669
#endif
670

    
671
static void get_str16_nolen(ByteIOContext *pb, int len, char *buf, int buf_size)
672
{
673
    int c;
674
    char *q;
675

    
676
    q = buf;
677
    while (len > 0) {
678
        c = get_le16(pb);
679
        if ((q - buf) < buf_size - 1)
680
            *q++ = c;
681
        len-=2;
682
    }
683
    *q = '\0';
684
}
685

    
686
static int asf_probe(AVProbeData *pd)
687
{
688
    GUID g;
689
    const unsigned char *p;
690
    int i;
691

    
692
    /* check file header */
693
    if (pd->buf_size <= 32)
694
        return 0;
695
    p = pd->buf;
696
    g.v1 = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
697
    p += 4;
698
    g.v2 = p[0] | (p[1] << 8);
699
    p += 2;
700
    g.v3 = p[0] | (p[1] << 8);
701
    p += 2;
702
    for(i=0;i<8;i++)
703
        g.v4[i] = *p++;
704

    
705
    if (!memcmp(&g, &asf_header, sizeof(GUID)))
706
        return AVPROBE_SCORE_MAX;
707
    else
708
        return 0;
709
}
710

    
711
static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap)
712
{
713
    ASFContext *asf = s->priv_data;
714
    GUID g;
715
    ByteIOContext *pb = &s->pb;
716
    AVStream *st;
717
    ASFStream *asf_st;
718
    int size, i, bps;
719
    INT64 gsize;
720

    
721
    get_guid(pb, &g);
722
    if (memcmp(&g, &asf_header, sizeof(GUID)))
723
        goto fail;
724
    get_le64(pb);
725
    get_le32(pb);
726
    get_byte(pb);
727
    get_byte(pb);
728

    
729
    for(;;) {
730
        get_guid(pb, &g);
731
        gsize = get_le64(pb);
732
#ifdef DEBUG
733
        printf("%08Lx: ", url_ftell(pb) - 24);
734
        print_guid(&g);
735
        printf("  size=0x%Lx\n", gsize);
736
#endif
737
        if (gsize < 24)
738
            goto fail;
739
        if (!memcmp(&g, &file_header, sizeof(GUID))) {
740
            get_guid(pb, &g);
741
            get_le64(pb); /* file size */
742
            get_le64(pb); /* file time */
743
            get_le64(pb); /* nb_packets */
744
            get_le64(pb); /* length 0 in us */
745
            get_le64(pb); /* length 1 in us */
746
            get_le32(pb);
747
            get_le32(pb);
748
            get_le32(pb);
749
            asf->packet_size = get_le32(pb);
750
            get_le32(pb);
751
            get_le32(pb);
752
        } else if (!memcmp(&g, &stream_header, sizeof(GUID))) {
753
            int type, id, total_size;
754
            unsigned int tag1;
755
            INT64 pos1, pos2;
756
            
757
            pos1 = url_ftell(pb);
758

    
759
            st = av_mallocz(sizeof(AVStream));
760
            if (!st)
761
                goto fail;
762
            s->streams[s->nb_streams++] = st;
763
            asf_st = av_mallocz(sizeof(ASFStream));
764
            if (!asf_st)
765
                goto fail;
766
            st->priv_data = asf_st;
767

    
768
            get_guid(pb, &g);
769
            if (!memcmp(&g, &audio_stream, sizeof(GUID))) {
770
                type = CODEC_TYPE_AUDIO;
771
            } else if (!memcmp(&g, &video_stream, sizeof(GUID))) {
772
                type = CODEC_TYPE_VIDEO;
773
            } else {
774
                goto fail;
775
            }
776
            get_guid(pb, &g);
777
            total_size = get_le64(pb);
778
            get_le32(pb);
779
            get_le32(pb);
780
            st->id = get_le16(pb); /* stream id */
781
            get_le32(pb);
782
            st->codec.codec_type = type;
783
            if (type == CODEC_TYPE_AUDIO) {
784
                id = get_le16(pb); 
785
                st->codec.codec_tag = id;
786
                st->codec.channels = get_le16(pb);
787
                st->codec.sample_rate = get_le32(pb);
788
                st->codec.bit_rate = get_le32(pb) * 8;
789
                get_le16(pb); /* block align */
790
                bps = get_le16(pb); /* bits per sample */
791
                st->codec.codec_id = wav_codec_get_id(id, bps);
792
                size = get_le16(pb);
793
                url_fskip(pb, size);
794
                /* We have to init the frame size at some point .... */
795
                switch (st->codec.codec_id) {
796
                case CODEC_ID_MP3LAME:
797
                    st->codec.frame_size = MPA_FRAME_SIZE;
798
                    break;
799
                case CODEC_ID_PCM_S16LE:
800
                case CODEC_ID_PCM_S16BE:
801
                case CODEC_ID_PCM_U16LE:
802
                case CODEC_ID_PCM_U16BE:
803
                case CODEC_ID_PCM_S8:
804
                case CODEC_ID_PCM_U8:
805
                case CODEC_ID_PCM_ALAW:
806
                case CODEC_ID_PCM_MULAW:
807
                    st->codec.frame_size = 1;
808
                    break;
809
                default:
810
                    /* This is probably wrong, but it prevents a crash later */
811
                    st->codec.frame_size = 1;
812
                    break;
813
                }
814
            } else {
815
                get_le32(pb);
816
                get_le32(pb);
817
                get_byte(pb);
818
                size = get_le16(pb); /* size */
819
                get_le32(pb); /* size */
820
                st->codec.width = get_le32(pb);
821
                st->codec.height = get_le32(pb);
822
                st->codec.frame_rate = 25 * FRAME_RATE_BASE; /* XXX: find it */
823
                get_le16(pb); /* panes */
824
                get_le16(pb); /* depth */
825
                tag1 = get_le32(pb);
826
                st->codec.codec_tag = tag1;
827
                st->codec.codec_id = codec_get_id(codec_asf_bmp_tags, tag1);
828
                url_fskip(pb, size - 5 * 4);
829
            }
830
            pos2 = url_ftell(pb);
831
            url_fskip(pb, gsize - (pos2 - pos1 + 24));
832
        } else if (!memcmp(&g, &data_header, sizeof(GUID))) {
833
            break;
834
        } else if (!memcmp(&g, &comment_header, sizeof(GUID))) {
835
            int len1, len2, len3, len4, len5;
836

    
837
            len1 = get_le16(pb);
838
            len2 = get_le16(pb);
839
            len3 = get_le16(pb);
840
            len4 = get_le16(pb);
841
            len5 = get_le16(pb);
842
            get_str16_nolen(pb, len1, s->title, sizeof(s->title));
843
            get_str16_nolen(pb, len2, s->author, sizeof(s->author));
844
            get_str16_nolen(pb, len3, s->copyright, sizeof(s->copyright));
845
            get_str16_nolen(pb, len4, s->comment, sizeof(s->comment));
846
            url_fskip(pb, len5);
847
#if 0
848
        } else if (!memcmp(&g, &head1_guid, sizeof(GUID))) {
849
            int v1, v2;
850
            get_guid(pb, &g);
851
            v1 = get_le32(pb);
852
            v2 = get_le16(pb);
853
        } else if (!memcmp(&g, &codec_comment_header, sizeof(GUID))) {
854
            int len, v1, n, num;
855
            char str[256], *q;
856
            char tag[16];
857

858
            get_guid(pb, &g);
859
            print_guid(&g);
860
            
861
            n = get_le32(pb);
862
            for(i=0;i<n;i++) {
863
                num = get_le16(pb); /* stream number */
864
                get_str16(pb, str, sizeof(str));
865
                get_str16(pb, str, sizeof(str));
866
                len = get_le16(pb);
867
                q = tag;
868
                while (len > 0) {
869
                    v1 = get_byte(pb);
870
                    if ((q - tag) < sizeof(tag) - 1)
871
                        *q++ = v1;
872
                    len--;
873
                }
874
                *q = '\0';
875
            }
876
#endif
877
        } else if (url_feof(pb)) {
878
            goto fail;
879
        } else {
880
            url_fseek(pb, gsize - 24, SEEK_CUR);
881
        }
882
    }
883
    get_guid(pb, &g);
884
    get_le64(pb);
885
    get_byte(pb);
886
    get_byte(pb);
887

    
888
    asf->packet_size_left = 0;
889

    
890
    return 0;
891

    
892
 fail:
893
    for(i=0;i<s->nb_streams;i++) {
894
        AVStream *st = s->streams[i];
895
        if (st)
896
            av_free(st->priv_data);
897
        av_free(st);
898
    }
899
    //av_free(asf);
900
    return -1;
901
}
902

    
903
static int asf_get_packet(AVFormatContext *s)
904
{
905
    ASFContext *asf = s->priv_data;
906
    ByteIOContext *pb = &s->pb;
907
    int c, flags, timestamp, hdr_size;
908

    
909
    hdr_size = 12;
910
    c = get_byte(pb);
911
    if (c != 0x82)
912
        return -EIO;
913
    get_le16(pb);
914
    flags = get_byte(pb);
915
    get_byte(pb);
916
    asf->packet_padsize = 0;
917
    if (flags & 0x10) {
918
        asf->packet_padsize = get_le16(pb);
919
        hdr_size += 2;
920
    } else if (flags & 0x08) {
921
        asf->packet_padsize = get_byte(pb);
922
        hdr_size++;
923
    }
924
    timestamp = get_le32(pb);
925
    get_le16(pb); /* duration */
926
    get_byte(pb); /* nb_frames */
927
#ifdef DEBUG
928
    printf("packet: size=%d padsize=%d\n", asf->packet_size, asf->packet_padsize);
929
#endif
930
    asf->packet_size_left = asf->packet_size - hdr_size;
931
    return 0;
932
}
933

    
934
static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
935
{
936
    ASFContext *asf = s->priv_data;
937
    AVStream *st;
938
    ASFStream *asf_st;
939
    ByteIOContext *pb = &s->pb;
940
    int ret, num, seq, frag_offset, payload_size, frag_len;
941
    int key_frame;
942
    int timestamp, i;
943

    
944
    for(;;) {
945
        if (asf->packet_size_left < FRAME_HEADER_SIZE ||
946
            asf->packet_size_left <= asf->packet_padsize) {
947
            /* fail safe */
948
            if (asf->packet_size_left)
949
                url_fskip(pb, asf->packet_size_left);
950
            ret = asf_get_packet(s);
951
            if (ret < 0)
952
                return -EIO;
953
        }
954
        /* read frame header */
955
        num = get_byte(pb);
956
        if (num & 0x80)
957
            key_frame = 1;
958
        else    
959
            key_frame = 0;
960

    
961
        num &= 0x7f;    
962
        seq = get_byte(pb);
963
        frag_offset = get_le32(pb);
964
        get_byte(pb); /* flags */
965
        payload_size = get_le32(pb);
966
        timestamp = get_le32(pb);
967
        frag_len = get_le16(pb);
968
#ifdef DEBUG
969
        printf("num=%d seq=%d totsize=%d frag_off=%d frag_size=%d\n",
970
               num, seq, payload_size, frag_offset, frag_len);
971
#endif
972
        st = NULL;
973
        for(i=0;i<s->nb_streams;i++) {
974
            st = s->streams[i];
975
            if (st->id == num)
976
                break;
977
        }
978
        asf->packet_size_left -= FRAME_HEADER_SIZE + frag_len;
979
        if (i == s->nb_streams) {
980
            /* unhandled packet (should not happen) */
981
            url_fskip(pb, frag_len);
982
        } else {
983
            asf_st = st->priv_data;
984
            if (asf_st->frag_offset == 0) {
985
                /* new packet */
986
                av_new_packet(&asf_st->pkt, payload_size);
987
                asf_st->seq = seq;
988
                if (key_frame)
989
                    asf_st->pkt.flags |= PKT_FLAG_KEY;
990

    
991
                asf_st->pkt.pts = timestamp;    
992
            } else {
993
                if (seq == asf_st->seq && 
994
                    frag_offset == asf_st->frag_offset) {
995
                    /* continuing packet */
996
                } else {
997
                    /* cannot continue current packet: free it */
998
                    av_free_packet(&asf_st->pkt);
999
                    asf_st->frag_offset = 0;
1000
                    if (frag_offset != 0) {
1001
                        /* cannot create new packet */
1002
                        url_fskip(pb, frag_len);
1003
                        goto next_frame;
1004
                    } else {
1005
                        /* create new packet */
1006
                        av_new_packet(&asf_st->pkt, payload_size);
1007
                        asf_st->seq = seq;
1008
                    }
1009
                }
1010
            }
1011
            /* read data */
1012
            get_buffer(pb, asf_st->pkt.data + frag_offset, frag_len);
1013
            asf_st->frag_offset += frag_len;
1014
            /* test if whole packet read */
1015
            if (asf_st->frag_offset == asf_st->pkt.size) {
1016
                /* return packet */
1017
                asf_st->pkt.stream_index = i;
1018
                asf_st->frag_offset = 0;
1019
                memcpy(pkt, &asf_st->pkt, sizeof(AVPacket)); 
1020
                break;
1021
            }
1022
        }
1023
    next_frame:;
1024
    }
1025

    
1026
    return 0;
1027
}
1028

    
1029
static int asf_read_close(AVFormatContext *s)
1030
{
1031
    //ASFContext *asf = s->priv_data;
1032
    int i;
1033

    
1034
    for(i=0;i<s->nb_streams;i++) {
1035
        AVStream *st = s->streams[i];
1036
        av_free(st->priv_data);
1037
    }
1038
    //av_free(asf);
1039
    return 0;
1040
}
1041

    
1042
AVInputFormat asf_iformat = {
1043
    "asf",
1044
    "asf format",
1045
    sizeof(ASFContext),
1046
    asf_probe,
1047
    asf_read_header,
1048
    asf_read_packet,
1049
    asf_read_close,
1050
};
1051

    
1052
AVOutputFormat asf_oformat = {
1053
    "asf",
1054
    "asf format",
1055
    "application/octet-stream",
1056
    "asf,wmv",
1057
    sizeof(ASFContext),
1058
#ifdef CONFIG_MP3LAME
1059
    CODEC_ID_MP3LAME,
1060
#else
1061
    CODEC_ID_MP2,
1062
#endif
1063
    CODEC_ID_MSMPEG4,
1064
    asf_write_header,
1065
    asf_write_packet,
1066
    asf_write_trailer,
1067
};
1068

    
1069
int asf_init(void)
1070
{
1071
    av_register_input_format(&asf_iformat);
1072
    av_register_output_format(&asf_oformat);
1073
    return 0;
1074
}