Statistics
| Branch: | Revision:

ffmpeg / libav / asf.c @ 9b030d9d

History | View | Annotate | Download (30.4 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(0x04, 0, 0, 0) }, /* some broken avi use this */
137
    { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') }, /* default signature when using MSMPEG4 */ 
138
    { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '3') },
139
    { CODEC_ID_MSMPEG4V2, MKTAG('M', 'P', '4', '2') }, 
140
    { CODEC_ID_MSMPEG4V1, MKTAG('M', 'P', 'G', '4') }, 
141
    { CODEC_ID_WMV1, MKTAG('W', 'M', 'V', '1') }, 
142
    { 0, 0 },
143
};
144

    
145

    
146

    
147
static void put_guid(ByteIOContext *s, const GUID *g)
148
{
149
    int i;
150

    
151
    put_le32(s, g->v1);
152
    put_le16(s, g->v2);
153
    put_le16(s, g->v3);
154
    for(i=0;i<8;i++)
155
        put_byte(s, g->v4[i]);
156
}
157

    
158
static void put_str16(ByteIOContext *s, const char *tag)
159
{
160
    int c;
161

    
162
    put_le16(s,strlen(tag) + 1);
163
    for(;;) {
164
        c = (UINT8)*tag++;
165
        put_le16(s, c);
166
        if (c == '\0') 
167
            break;
168
    }
169
}
170

    
171
static void put_str16_nolen(ByteIOContext *s, const char *tag)
172
{
173
    int c;
174

    
175
    for(;;) {
176
        c = (UINT8)*tag++;
177
        put_le16(s, c);
178
        if (c == '\0') 
179
            break;
180
    }
181
}
182

    
183
static INT64 put_header(ByteIOContext *pb, const GUID *g)
184
{
185
    INT64 pos;
186

    
187
    pos = url_ftell(pb);
188
    put_guid(pb, g);
189
    put_le64(pb, 24);
190
    return pos;
191
}
192

    
193
/* update header size */
194
static void end_header(ByteIOContext *pb, INT64 pos)
195
{
196
    INT64 pos1;
197

    
198
    pos1 = url_ftell(pb);
199
    url_fseek(pb, pos + 16, SEEK_SET);
200
    put_le64(pb, pos1 - pos);
201
    url_fseek(pb, pos1, SEEK_SET);
202
}
203

    
204
/* write an asf chunk (only used in streaming case) */
205
static void put_chunk(AVFormatContext *s, int type, int payload_length, int flags)
206
{
207
    ASFContext *asf = s->priv_data;
208
    ByteIOContext *pb = &s->pb;
209
    int length;
210

    
211
    length = payload_length + 8;
212
    put_le16(pb, type); 
213
    put_le16(pb, length); 
214
    put_le32(pb, asf->seqno);
215
    put_le16(pb, flags); /* unknown bytes */
216
    put_le16(pb, length);
217
    asf->seqno++;
218
}
219

    
220
/* convert from unix to windows time */
221
static INT64 unix_to_file_time(int ti)
222
{
223
    INT64 t;
224
    
225
    t = ti * INT64_C(10000000);
226
    t += INT64_C(116444736000000000);
227
    return t;
228
}
229

    
230
/* write the header (used two times if non streamed) */
231
static int asf_write_header1(AVFormatContext *s, INT64 file_size, INT64 data_chunk_size)
232
{
233
    ASFContext *asf = s->priv_data;
234
    ByteIOContext *pb = &s->pb;
235
    int header_size, n, extra_size, extra_size2, wav_extra_size, file_time;
236
    int has_title;
237
    AVCodecContext *enc;
238
    INT64 header_offset, cur_pos, hpos;
239
    int bit_rate;
240

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

    
243
    bit_rate = 0;
244
    for(n=0;n<s->nb_streams;n++) {
245
        enc = &s->streams[n]->codec;
246

    
247
        bit_rate += enc->bit_rate;
248
    }
249

    
250
    if (url_is_streamed(&s->pb)) {
251
        put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */
252
    }
253

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

    
278
    /* unknown headers */
279
    hpos = put_header(pb, &head1_guid);
280
    put_guid(pb, &head2_guid);
281
    put_le32(pb, 6);
282
    put_le16(pb, 0);
283
    end_header(pb, hpos);
284

    
285
    /* title and other infos */
286
    if (has_title) {
287
        hpos = put_header(pb, &comment_header);
288
        put_le16(pb, 2 * (strlen(s->title) + 1));
289
        put_le16(pb, 2 * (strlen(s->author) + 1));
290
        put_le16(pb, 2 * (strlen(s->copyright) + 1));
291
        put_le16(pb, 2 * (strlen(s->comment) + 1));
292
        put_le16(pb, 0);
293
        put_str16_nolen(pb, s->title);
294
        put_str16_nolen(pb, s->author);
295
        put_str16_nolen(pb, s->copyright);
296
        put_str16_nolen(pb, s->comment);
297
        end_header(pb, hpos);
298
    }
299

    
300
    /* stream headers */
301
    for(n=0;n<s->nb_streams;n++) {
302
        INT64 es_pos;
303
        ASFStream *stream = &asf->streams[n];
304

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

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

    
350
            if (wavsize < 0)
351
                return -1;
352
            if (wavsize != extra_size) {
353
                cur_pos = url_ftell(pb);
354
                url_fseek(pb, es_pos, SEEK_SET);
355
                put_le32(pb, wavsize); /* wav header len */
356
                url_fseek(pb, cur_pos, SEEK_SET);
357
            }
358
        } else {
359
            put_le32(pb, enc->width);
360
            put_le32(pb, enc->height);
361
            put_byte(pb, 2); /* ??? */
362
            put_le16(pb, 40); /* size */
363

    
364
            /* BITMAPINFOHEADER header */
365
            put_bmp_header(pb, enc, codec_asf_bmp_tags);
366
        }
367
        end_header(pb, hpos);
368
    }
369

    
370
    /* media comments */
371

    
372
    hpos = put_header(pb, &codec_comment_header);
373
    put_guid(pb, &codec_comment1_header);
374
    put_le32(pb, s->nb_streams);
375
    for(n=0;n<s->nb_streams;n++) {
376
        AVCodec *p;
377

    
378
        enc = &s->streams[n]->codec;
379
        p = avcodec_find_encoder(enc->codec_id);
380

    
381
        put_le16(pb, asf->streams[n].num);
382
        put_str16(pb, p ? p->name : enc->codec_name);
383
        put_le16(pb, 0); /* no parameters */
384
        /* id */
385
        if (enc->codec_type == CODEC_TYPE_AUDIO) {
386
            put_le16(pb, 2);
387
            put_le16(pb, codec_get_tag(codec_wav_tags, enc->codec_id));
388
        } else {
389
            put_le16(pb, 4);
390
            put_le32(pb, codec_get_tag(codec_asf_bmp_tags, enc->codec_id));
391
        }
392
    }
393
    end_header(pb, hpos);
394

    
395
    /* patch the header size fields */
396

    
397
    cur_pos = url_ftell(pb);
398
    header_size = cur_pos - header_offset;
399
    if (url_is_streamed(&s->pb)) {
400
        header_size += 8 + 30 + 50;
401

    
402
        url_fseek(pb, header_offset - 10 - 30, SEEK_SET);
403
        put_le16(pb, header_size);
404
        url_fseek(pb, header_offset - 2 - 30, SEEK_SET);
405
        put_le16(pb, header_size);
406

    
407
        header_size -= 8 + 30 + 50;
408
    }
409
    header_size += 24 + 6;
410
    url_fseek(pb, header_offset - 14, SEEK_SET);
411
    put_le64(pb, header_size);
412
    url_fseek(pb, cur_pos, SEEK_SET);
413

    
414
    /* movie chunk, followed by packets of packet_size */
415
    asf->data_offset = cur_pos;
416
    put_guid(pb, &data_header);
417
    put_le64(pb, data_chunk_size);
418
    put_guid(pb, &my_guid);
419
    put_le64(pb, asf->nb_packets); /* nb packets */
420
    put_byte(pb, 1); /* ??? */
421
    put_byte(pb, 1); /* ??? */
422
    return 0;
423
}
424

    
425
static int asf_write_header(AVFormatContext *s)
426
{
427
    ASFContext *asf = s->priv_data;
428

    
429
    asf->packet_size = PACKET_SIZE;
430
    asf->nb_packets = 0;
431

    
432
    if (asf_write_header1(s, 0, 50) < 0) {
433
        //av_free(asf);
434
        return -1;
435
    }
436

    
437
    put_flush_packet(&s->pb);
438

    
439
    asf->packet_nb_frames = 0;
440
    asf->packet_timestamp_start = -1;
441
    asf->packet_timestamp_end = -1;
442
    asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
443
    init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size, 1,
444
                  NULL, NULL, NULL, NULL);
445

    
446
    return 0;
447
}
448

    
449
/* write a fixed size packet */
450
static int put_packet(AVFormatContext *s, 
451
                       unsigned int timestamp, unsigned int duration, 
452
                       int nb_frames, int padsize)
453
{
454
    ASFContext *asf = s->priv_data;
455
    ByteIOContext *pb = &s->pb;
456
    int flags;
457

    
458
    if (url_is_streamed(&s->pb)) {
459
        put_chunk(s, 0x4424, asf->packet_size, 0);
460
    }
461

    
462
    put_byte(pb, 0x82);
463
    put_le16(pb, 0);
464
    
465
    flags = 0x01; /* nb segments present */
466
    if (padsize > 0) {
467
        if (padsize < 256)
468
            flags |= 0x08;
469
        else
470
            flags |= 0x10;
471
    }
472
    put_byte(pb, flags); /* flags */
473
    put_byte(pb, 0x5d);
474
    if (flags & 0x10)
475
        put_le16(pb, padsize - 2);
476
    if (flags & 0x08)
477
        put_byte(pb, padsize - 1);
478
    put_le32(pb, timestamp);
479
    put_le16(pb, duration);
480
    put_byte(pb, nb_frames | 0x80);
481

    
482
    return PACKET_HEADER_SIZE + ((flags & 0x18) >> 3);
483
}
484

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

    
510
static void put_frame_header(AVFormatContext *s, ASFStream *stream, int timestamp,
511
                             int payload_size, int frag_offset, int frag_len)
512
{
513
    ASFContext *asf = s->priv_data;
514
    ByteIOContext *pb = &asf->pb;
515
    int val;
516

    
517
    val = stream->num;
518
    if (s->streams[val - 1]->codec.key_frame /* && frag_offset == 0 */)
519
        val |= 0x80;
520
    put_byte(pb, val);
521
    put_byte(pb, stream->seq);
522
    put_le32(pb, frag_offset); /* fragment offset */
523
    put_byte(pb, 0x08); /* flags */
524
    put_le32(pb, payload_size);
525
    put_le32(pb, timestamp);
526
    put_le16(pb, frag_len);
527
}
528

    
529

    
530
/* Output a frame. We suppose that payload_size <= PACKET_SIZE.
531

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

    
567

    
568
static int asf_write_packet(AVFormatContext *s, int stream_index,
569
                            UINT8 *buf, int size, int force_pts)
570
{
571
    ASFContext *asf = s->priv_data;
572
    ASFStream *stream;
573
    int timestamp;
574
    INT64 duration;
575
    AVCodecContext *codec;
576

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

    
602
    /* flush the current packet */
603
    if (asf->pb.buf_ptr > asf->pb.buffer)
604
        flush_packet(s);
605

    
606
    if (url_is_streamed(&s->pb)) {
607
        put_chunk(s, 0x4524, 0, 0); /* end of stream */
608
    } else {
609
        /* rewrite an updated header */
610
        file_size = url_ftell(&s->pb);
611
        url_fseek(&s->pb, 0, SEEK_SET);
612
        asf_write_header1(s, file_size, file_size - asf->data_offset);
613
    }
614

    
615
    put_flush_packet(&s->pb);
616
    return 0;
617
}
618

    
619
/**********************************/
620
/* decoding */
621

    
622
//#define DEBUG
623

    
624
#ifdef DEBUG
625
static void print_guid(const GUID *g)
626
{
627
    int i;
628
    printf("0x%08x, 0x%04x, 0x%04x, {", g->v1, g->v2, g->v3);
629
    for(i=0;i<8;i++) 
630
        printf(" 0x%02x,", g->v4[i]);
631
    printf("}\n");
632
}
633
#endif
634

    
635
static void get_guid(ByteIOContext *s, GUID *g)
636
{
637
    int i;
638

    
639
    g->v1 = get_le32(s);
640
    g->v2 = get_le16(s);
641
    g->v3 = get_le16(s);
642
    for(i=0;i<8;i++)
643
        g->v4[i] = get_byte(s);
644
}
645

    
646
#if 0
647
static void get_str16(ByteIOContext *pb, char *buf, int buf_size)
648
{
649
    int len, c;
650
    char *q;
651

652
    len = get_le16(pb);
653
    q = buf;
654
    while (len > 0) {
655
        c = get_le16(pb);
656
        if ((q - buf) < buf_size - 1)
657
            *q++ = c;
658
        len--;
659
    }
660
    *q = '\0';
661
}
662
#endif
663

    
664
static void get_str16_nolen(ByteIOContext *pb, int len, char *buf, int buf_size)
665
{
666
    int c;
667
    char *q;
668

    
669
    q = buf;
670
    while (len > 0) {
671
        c = get_le16(pb);
672
        if ((q - buf) < buf_size - 1)
673
            *q++ = c;
674
        len-=2;
675
    }
676
    *q = '\0';
677
}
678

    
679
static int asf_probe(AVProbeData *pd)
680
{
681
    GUID g;
682
    const unsigned char *p;
683
    int i;
684

    
685
    /* check file header */
686
    if (pd->buf_size <= 32)
687
        return 0;
688
    p = pd->buf;
689
    g.v1 = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
690
    p += 4;
691
    g.v2 = p[0] | (p[1] << 8);
692
    p += 2;
693
    g.v3 = p[0] | (p[1] << 8);
694
    p += 2;
695
    for(i=0;i<8;i++)
696
        g.v4[i] = *p++;
697

    
698
    if (!memcmp(&g, &asf_header, sizeof(GUID)))
699
        return AVPROBE_SCORE_MAX;
700
    else
701
        return 0;
702
}
703

    
704
static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap)
705
{
706
    ASFContext *asf = s->priv_data;
707
    GUID g;
708
    ByteIOContext *pb = &s->pb;
709
    AVStream *st;
710
    ASFStream *asf_st;
711
    int size, i, bps;
712
    INT64 gsize;
713

    
714
    get_guid(pb, &g);
715
    if (memcmp(&g, &asf_header, sizeof(GUID)))
716
        goto fail;
717
    get_le64(pb);
718
    get_le32(pb);
719
    get_byte(pb);
720
    get_byte(pb);
721

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

    
752
            st = av_mallocz(sizeof(AVStream));
753
            if (!st)
754
                goto fail;
755
            s->streams[s->nb_streams++] = st;
756
            asf_st = av_mallocz(sizeof(ASFStream));
757
            if (!asf_st)
758
                goto fail;
759
            st->priv_data = asf_st;
760

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

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

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

    
881
    asf->packet_size_left = 0;
882

    
883
    return 0;
884

    
885
 fail:
886
    for(i=0;i<s->nb_streams;i++) {
887
        AVStream *st = s->streams[i];
888
        if (st)
889
            av_free(st->priv_data);
890
        av_free(st);
891
    }
892
    //av_free(asf);
893
    return -1;
894
}
895

    
896
static int asf_get_packet(AVFormatContext *s)
897
{
898
    ASFContext *asf = s->priv_data;
899
    ByteIOContext *pb = &s->pb;
900
    int c, flags, timestamp, hdr_size;
901

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

    
927
static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
928
{
929
    ASFContext *asf = s->priv_data;
930
    AVStream *st;
931
    ASFStream *asf_st;
932
    ByteIOContext *pb = &s->pb;
933
    int ret, num, seq, frag_offset, payload_size, frag_len;
934
    int key_frame;
935
    int timestamp, i;
936

    
937
    for(;;) {
938
        if (asf->packet_size_left < FRAME_HEADER_SIZE ||
939
            asf->packet_size_left <= asf->packet_padsize) {
940
            /* fail safe */
941
            if (asf->packet_size_left)
942
                url_fskip(pb, asf->packet_size_left);
943
            ret = asf_get_packet(s);
944
            if (ret < 0)
945
                return -EIO;
946
        }
947
        /* read frame header */
948
        num = get_byte(pb);
949
        if (num & 0x80)
950
            key_frame = 1;
951
        else    
952
            key_frame = 0;
953

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

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

    
1019
    return 0;
1020
}
1021

    
1022
static int asf_read_close(AVFormatContext *s)
1023
{
1024
    //ASFContext *asf = s->priv_data;
1025
    int i;
1026

    
1027
    for(i=0;i<s->nb_streams;i++) {
1028
        AVStream *st = s->streams[i];
1029
        av_free(st->priv_data);
1030
    }
1031
    //av_free(asf);
1032
    return 0;
1033
}
1034

    
1035
AVInputFormat asf_iformat = {
1036
    "asf",
1037
    "asf format",
1038
    sizeof(ASFContext),
1039
    asf_probe,
1040
    asf_read_header,
1041
    asf_read_packet,
1042
    asf_read_close,
1043
};
1044

    
1045
AVOutputFormat asf_oformat = {
1046
    "asf",
1047
    "asf format",
1048
    "application/octet-stream",
1049
    "asf,wmv",
1050
    sizeof(ASFContext),
1051
#ifdef CONFIG_MP3LAME
1052
    CODEC_ID_MP3LAME,
1053
#else
1054
    CODEC_ID_MP2,
1055
#endif
1056
    CODEC_ID_MSMPEG4,
1057
    asf_write_header,
1058
    asf_write_packet,
1059
    asf_write_trailer,
1060
};
1061

    
1062
int asf_init(void)
1063
{
1064
    av_register_input_format(&asf_iformat);
1065
    av_register_output_format(&asf_oformat);
1066
    return 0;
1067
}