]> git.sesse.net Git - ffmpeg/blob - libav/asf.c
Restore the main Makefile to have debug flags.
[ffmpeg] / libav / asf.c
1 /*
2  * ASF compatible encoder and decoder.
3  * Copyright (c) 2000, 2001 Gerard Lantau.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program 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
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 #include "avformat.h"
20 #include "avi.h"
21
22 #define PACKET_SIZE 3200
23 #define PACKET_HEADER_SIZE 12
24 #define FRAME_HEADER_SIZE 17
25
26 typedef struct {
27     int num;
28     int seq;
29     /* use for reading */
30     AVPacket pkt;
31     int frag_offset;
32 } ASFStream;
33
34 typedef struct {
35     int seqno;
36     int packet_size;
37
38     ASFStream streams[2];
39     /* non streamed additonnal info */
40     int data_offset;
41     INT64 nb_packets;
42     INT64 duration; /* in 100ns units */
43     /* packet filling */
44     int packet_size_left;
45     int packet_timestamp_start;
46     int packet_timestamp_end;
47     int packet_nb_frames;
48     UINT8 packet_buf[PACKET_SIZE];
49     ByteIOContext pb;
50     /* only for reading */
51     int packet_padsize;
52 } ASFContext;
53
54 typedef struct {
55     UINT32 v1;
56     UINT16 v2;
57     UINT16 v3;
58     UINT8 v4[8];
59 } GUID;
60
61 static const GUID asf_header = {
62     0x75B22630, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C },
63 };
64
65 static const GUID file_header = {
66     0x8CABDCA1, 0xA947, 0x11CF, { 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 },
67 };
68
69 static const GUID stream_header = {
70     0xB7DC0791, 0xA9B7, 0x11CF, { 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 },
71 };
72
73 static const GUID audio_stream = {
74     0xF8699E40, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
75 };
76
77 static const GUID audio_conceal_none = {
78     0x49f1a440, 0x4ece, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 },
79 };
80
81 static const GUID video_stream = {
82     0xBC19EFC0, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
83 };
84
85 static const GUID video_conceal_none = {
86     0x20FB5700, 0x5B55, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
87 };
88
89
90 static const GUID comment_header = {
91     0x75b22633, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c },
92 };
93
94 static const GUID codec_comment_header = {
95     0x86D15240, 0x311D, 0x11D0, { 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 },
96 };
97 static const GUID codec_comment1_header = {
98     0x86d15241, 0x311d, 0x11d0, { 0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 },
99 };
100
101 static const GUID data_header = {
102     0x75b22636, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c },
103 };
104
105 static const GUID index_guid = {
106     0x33000890, 0xe5b1, 0x11cf, { 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb },
107 };
108
109 static const GUID head1_guid = {
110     0x5fbf03b5, 0xa92e, 0x11cf, { 0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 },
111 };
112
113 static const GUID head2_guid = {
114     0xabd3d211, 0xa9ba, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 },
115 };
116     
117 /* I am not a number !!! This GUID is the one found on the PC used to
118    generate the stream */
119 static const GUID my_guid = {
120     0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 },
121 };
122
123 static void put_guid(ByteIOContext *s, const GUID *g)
124 {
125     int i;
126
127     put_le32(s, g->v1);
128     put_le16(s, g->v2);
129     put_le16(s, g->v3);
130     for(i=0;i<8;i++)
131         put_byte(s, g->v4[i]);
132 }
133
134 static void put_str16(ByteIOContext *s, const char *tag)
135 {
136     int c;
137
138     put_le16(s,strlen(tag) + 1);
139     for(;;) {
140         c = (UINT8)*tag++;
141         put_le16(s, c);
142         if (c == '\0') 
143             break;
144     }
145 }
146
147 static void put_str16_nolen(ByteIOContext *s, const char *tag)
148 {
149     int c;
150
151     for(;;) {
152         c = (UINT8)*tag++;
153         put_le16(s, c);
154         if (c == '\0') 
155             break;
156     }
157 }
158
159 static INT64 put_header(ByteIOContext *pb, const GUID *g)
160 {
161     INT64 pos;
162
163     pos = url_ftell(pb);
164     put_guid(pb, g);
165     put_le64(pb, 24);
166     return pos;
167 }
168
169 /* update header size */
170 static void end_header(ByteIOContext *pb, INT64 pos)
171 {
172     INT64 pos1;
173
174     pos1 = url_ftell(pb);
175     url_fseek(pb, pos + 16, SEEK_SET);
176     put_le64(pb, pos1 - pos);
177     url_fseek(pb, pos1, SEEK_SET);
178 }
179
180 /* write an asf chunk (only used in streaming case) */
181 static void put_chunk(AVFormatContext *s, int type, int payload_length)
182 {
183     ASFContext *asf = s->priv_data;
184     ByteIOContext *pb = &s->pb;
185     int length;
186
187     length = payload_length + 8;
188     put_le16(pb, type); 
189     put_le16(pb, length); 
190     put_le32(pb, asf->seqno);
191     put_le16(pb, 0); /* unknown bytes */
192     put_le16(pb, length);
193     asf->seqno++;
194 }
195
196 /* convert from unix to windows time */
197 static INT64 unix_to_file_time(int ti)
198 {
199     INT64 t;
200     
201     t = ti * INT64_C(10000000);
202     t += INT64_C(116444736000000000);
203     return t;
204 }
205
206 /* write the header (used two times if non streamed) */
207 static int asf_write_header1(AVFormatContext *s, INT64 file_size, INT64 data_chunk_size)
208 {
209     ASFContext *asf = s->priv_data;
210     ByteIOContext *pb = &s->pb;
211     int header_size, n, extra_size, extra_size2, wav_extra_size, file_time;
212     int has_title;
213     AVCodecContext *enc;
214     INT64 header_offset, cur_pos, hpos;
215
216     has_title = (s->title[0] != '\0');
217
218     if (!url_is_streamed(&s->pb)) {
219         put_guid(pb, &asf_header);
220         put_le64(pb, 0); /* header length, will be patched after */
221         put_le32(pb, 3 + has_title + s->nb_streams); /* number of chunks in header */
222         put_byte(pb, 1); /* ??? */
223         put_byte(pb, 2); /* ??? */
224     } else {
225         put_chunk(s, 0x4824, 0); /* start of stream (length will be patched later) */
226     }
227     
228     /* file header */
229     header_offset = url_ftell(pb);
230     hpos = put_header(pb, &file_header);
231     put_guid(pb, &my_guid);
232     put_le64(pb, file_size);
233     file_time = 0;
234     put_le64(pb, unix_to_file_time(file_time));
235     put_le64(pb, asf->nb_packets); /* number of packets */
236     put_le64(pb, asf->duration); /* end time stamp (in 100ns units) */
237     put_le64(pb, asf->duration); /* duration (in 100ns units) */
238     put_le32(pb, 0); /* start time stamp */ 
239     put_le32(pb, 0); /* ??? */ 
240     put_le32(pb, 0); /* ??? */ 
241     put_le32(pb, asf->packet_size); /* packet size */
242     put_le32(pb, asf->packet_size); /* packet size */
243     put_le32(pb, 80 * asf->packet_size); /* frame_size ??? */
244     end_header(pb, hpos);
245
246     /* unknown headers */
247     hpos = put_header(pb, &head1_guid);
248     put_guid(pb, &head2_guid);
249     put_le32(pb, 6);
250     put_le16(pb, 0);
251     end_header(pb, hpos);
252
253     /* title and other infos */
254     if (has_title) {
255         hpos = put_header(pb, &comment_header);
256         put_le16(pb, 2 * (strlen(s->title) + 1));
257         put_le16(pb, 2 * (strlen(s->author) + 1));
258         put_le16(pb, 2 * (strlen(s->copyright) + 1));
259         put_le16(pb, 2 * (strlen(s->comment) + 1));
260         put_le16(pb, 0);
261         put_str16_nolen(pb, s->title);
262         put_str16_nolen(pb, s->author);
263         put_str16_nolen(pb, s->copyright);
264         put_str16_nolen(pb, s->comment);
265         end_header(pb, hpos);
266     }
267
268     /* stream headers */
269     for(n=0;n<s->nb_streams;n++) {
270         enc = &s->streams[n]->codec;
271         asf->streams[n].num = n + 1;
272         asf->streams[n].seq = 0;
273         
274         switch(enc->codec_type) {
275         case CODEC_TYPE_AUDIO:
276             wav_extra_size = 0;
277             extra_size = 18 + wav_extra_size;
278             extra_size2 = 0;
279             break;
280         default:
281         case CODEC_TYPE_VIDEO:
282             wav_extra_size = 0;
283             extra_size = 0x33;
284             extra_size2 = 0;
285             break;
286         }
287
288         hpos = put_header(pb, &stream_header);
289         if (enc->codec_type == CODEC_TYPE_AUDIO) {
290             put_guid(pb, &audio_stream);
291             put_guid(pb, &audio_conceal_none);
292         } else {
293             put_guid(pb, &video_stream);
294             put_guid(pb, &video_conceal_none);
295         }
296         put_le64(pb, 0); /* ??? */
297         put_le32(pb, extra_size); /* wav header len */
298         put_le32(pb, extra_size2); /* additional data len */
299         put_le16(pb, n + 1); /* stream number */
300         put_le32(pb, 0); /* ??? */
301         
302         if (enc->codec_type == CODEC_TYPE_AUDIO) {
303             /* WAVEFORMATEX header */
304             if (put_wav_header(pb, enc) < 0)
305                 return -1;
306         } else {
307             put_le32(pb, enc->width);
308             put_le32(pb, enc->height);
309             put_byte(pb, 2); /* ??? */
310             put_le16(pb, 40); /* size */
311
312             /* BITMAPINFOHEADER header */
313             put_bmp_header(pb, enc);
314         }
315         end_header(pb, hpos);
316     }
317
318     /* media comments */
319
320     hpos = put_header(pb, &codec_comment_header);
321     put_guid(pb, &codec_comment1_header);
322     put_le32(pb, s->nb_streams);
323     for(n=0;n<s->nb_streams;n++) {
324         enc = &s->streams[n]->codec;
325
326         put_le16(pb, asf->streams[n].num);
327         put_str16(pb, enc->codec_name);
328         put_le16(pb, 0); /* no parameters */
329         /* id */
330         if (enc->codec_type == CODEC_TYPE_AUDIO) {
331             put_le16(pb, 2);
332             put_le16(pb, codec_get_tag(codec_wav_tags, enc->codec_id));
333         } else {
334             put_le16(pb, 4);
335             put_le32(pb, codec_get_tag(codec_bmp_tags, enc->codec_id));
336         }
337     }
338     end_header(pb, hpos);
339
340     /* patch the header size fields */
341
342     cur_pos = url_ftell(pb);
343     header_size = cur_pos - header_offset;
344     if (!url_is_streamed(&s->pb)) {
345         header_size += 24 + 6;
346         url_fseek(pb, header_offset - 14, SEEK_SET);
347         put_le64(pb, header_size);
348     } else {
349         header_size += 8 + 50;
350         url_fseek(pb, header_offset - 10, SEEK_SET);
351         put_le16(pb, header_size);
352         url_fseek(pb, header_offset - 2, SEEK_SET);
353         put_le16(pb, header_size);
354     }
355     url_fseek(pb, cur_pos, SEEK_SET);
356
357     /* movie chunk, followed by packets of packet_size */
358     asf->data_offset = cur_pos;
359     put_guid(pb, &data_header);
360     put_le64(pb, data_chunk_size);
361     put_guid(pb, &my_guid);
362     put_le64(pb, asf->nb_packets); /* nb packets */
363     put_byte(pb, 1); /* ??? */
364     put_byte(pb, 1); /* ??? */
365     return 0;
366 }
367
368 static int asf_write_header(AVFormatContext *s)
369 {
370     ASFContext *asf;
371
372     asf = av_mallocz(sizeof(ASFContext));
373     if (!asf)
374         return -1;
375     s->priv_data = asf;
376
377     asf->packet_size = PACKET_SIZE;
378     asf->nb_packets = 0;
379
380     if (asf_write_header1(s, 0, 24) < 0) {
381         free(asf);
382         return -1;
383     }
384
385     put_flush_packet(&s->pb);
386
387     asf->packet_nb_frames = 0;
388     asf->packet_timestamp_start = -1;
389     asf->packet_timestamp_end = -1;
390     asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
391     init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size, 1,
392                   NULL, NULL, NULL, NULL);
393
394     return 0;
395 }
396
397 /* write a fixed size packet */
398 static void put_packet(AVFormatContext *s, 
399                        unsigned int timestamp, unsigned int duration, 
400                        int nb_frames, int padsize)
401 {
402     ASFContext *asf = s->priv_data;
403     ByteIOContext *pb = &s->pb;
404     int flags;
405
406     if (url_is_streamed(&s->pb)) {
407         put_chunk(s, 0x4424, asf->packet_size);
408     }
409
410     put_byte(pb, 0x82);
411     put_le16(pb, 0);
412     
413     flags = 0x01; /* nb segments present */
414     if (padsize > 0) {
415         if (padsize < 256)
416             flags |= 0x08;
417         else
418             flags |= 0x10;
419     }
420     put_byte(pb, flags); /* flags */
421     put_byte(pb, 0x5d);
422     if (flags & 0x10)
423         put_le16(pb, padsize);
424     if (flags & 0x08)
425         put_byte(pb, padsize);
426     put_le32(pb, timestamp);
427     put_le16(pb, duration);
428     put_byte(pb, nb_frames | 0x80);
429 }
430
431 static void flush_packet(AVFormatContext *s)
432 {
433     ASFContext *asf = s->priv_data;
434     int hdr_size, ptr;
435     
436     put_packet(s, asf->packet_timestamp_start, 
437                asf->packet_timestamp_end - asf->packet_timestamp_start, 
438                asf->packet_nb_frames, asf->packet_size_left);
439     
440     /* compute padding */
441     hdr_size = PACKET_HEADER_SIZE;
442     if (asf->packet_size_left > 0) {
443         /* if padding needed, don't forget to count the
444            padding byte in the header size */
445         hdr_size++;
446         asf->packet_size_left--;
447         /* XXX: I do not test again exact limit to avoid boundary problems */
448         if (asf->packet_size_left > 200) {
449             hdr_size++;
450             asf->packet_size_left--;
451         }
452     }
453     ptr = asf->packet_size - PACKET_HEADER_SIZE - asf->packet_size_left;
454     memset(asf->packet_buf + ptr, 0, asf->packet_size_left);
455     
456     put_buffer(&s->pb, asf->packet_buf, asf->packet_size - hdr_size);
457     
458     put_flush_packet(&s->pb);
459     asf->nb_packets++;
460     asf->packet_nb_frames = 0;
461     asf->packet_timestamp_start = -1;
462     asf->packet_timestamp_end = -1;
463     asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
464     init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size, 1,
465                   NULL, NULL, NULL, NULL);
466 }
467
468 static void put_frame_header(AVFormatContext *s, ASFStream *stream, int timestamp,
469                              int payload_size, int frag_offset, int frag_len)
470 {
471     ASFContext *asf = s->priv_data;
472     ByteIOContext *pb = &asf->pb;
473     int val;
474
475     val = stream->num;
476     if (s->streams[val - 1]->codec.key_frame)
477         val |= 0x80;
478     put_byte(pb, val);
479     put_byte(pb, stream->seq);
480     put_le32(pb, frag_offset); /* fragment offset */
481     put_byte(pb, 0x08); /* flags */
482     put_le32(pb, payload_size);
483     put_le32(pb, timestamp);
484     put_le16(pb, frag_len);
485 }
486
487
488 /* Output a frame. We suppose that payload_size <= PACKET_SIZE.
489
490    It is there that you understand that the ASF format is really
491    crap. They have misread the MPEG Systems spec ! 
492  */
493 static void put_frame(AVFormatContext *s, ASFStream *stream, int timestamp,
494                       UINT8 *buf, int payload_size)
495 {
496     ASFContext *asf = s->priv_data;
497     int frag_pos, frag_len, frag_len1;
498     
499     frag_pos = 0;
500     while (frag_pos < payload_size) {
501         frag_len = payload_size - frag_pos;
502         frag_len1 = asf->packet_size_left - FRAME_HEADER_SIZE;
503         if (frag_len1 > 0) {
504             if (frag_len > frag_len1)
505                 frag_len = frag_len1;
506             put_frame_header(s, stream, timestamp, payload_size, frag_pos, frag_len);
507             put_buffer(&asf->pb, buf, frag_len);
508             asf->packet_size_left -= (frag_len + FRAME_HEADER_SIZE);
509             asf->packet_timestamp_end = timestamp;
510             if (asf->packet_timestamp_start == -1)
511                 asf->packet_timestamp_start = timestamp;
512             asf->packet_nb_frames++;
513         } else {
514             frag_len = 0;
515         }
516         frag_pos += frag_len;
517         buf += frag_len;
518         /* output the frame if filled */
519         if (asf->packet_size_left <= FRAME_HEADER_SIZE)
520             flush_packet(s);
521     }
522     stream->seq++;
523 }
524
525
526 static int asf_write_packet(AVFormatContext *s, int stream_index,
527                             UINT8 *buf, int size)
528 {
529     ASFContext *asf = s->priv_data;
530     int timestamp;
531     INT64 duration;
532     AVCodecContext *codec;
533
534     codec = &s->streams[stream_index]->codec;
535     if (codec->codec_type == CODEC_TYPE_AUDIO) {
536         timestamp = (int)((float)codec->frame_number * codec->frame_size * 1000.0 / 
537                           codec->sample_rate);
538         duration = (codec->frame_number * codec->frame_size * INT64_C(10000000)) / 
539             codec->sample_rate;
540     } else {
541         timestamp = (int)((float)codec->frame_number * 1000.0 * FRAME_RATE_BASE / 
542                           codec->frame_rate);
543         duration = codec->frame_number * 
544             ((INT64_C(10000000) * FRAME_RATE_BASE) / codec->frame_rate);
545     }
546     if (duration > asf->duration)
547         asf->duration = duration;
548     
549     put_frame(s, &asf->streams[stream_index], (int)timestamp, buf, size);
550     return 0;
551 }
552     
553 static int asf_write_trailer(AVFormatContext *s)
554 {
555     ASFContext *asf = s->priv_data;
556     INT64 file_size;
557
558     /* flush the current packet */
559     if (asf->pb.buf_ptr > asf->pb.buffer)
560         flush_packet(s);
561
562     if (url_is_streamed(&s->pb)) {
563         put_chunk(s, 0x4524, 0); /* end of stream */
564     } else {
565         /* rewrite an updated header */
566         file_size = url_ftell(&s->pb);
567         url_fseek(&s->pb, 0, SEEK_SET);
568         asf_write_header1(s, file_size, file_size - asf->data_offset);
569     }
570
571     put_flush_packet(&s->pb);
572
573     free(asf);
574     return 0;
575 }
576
577 /**********************************/
578 /* decoding */
579
580 //#define DEBUG
581
582 #ifdef DEBUG
583 static void print_guid(const GUID *g)
584 {
585     int i;
586     printf("0x%08x, 0x%04x, 0x%04x, {", g->v1, g->v2, g->v3);
587     for(i=0;i<8;i++) 
588         printf(" 0x%02x,", g->v4[i]);
589     printf("}\n");
590 }
591 #endif
592
593 static void get_guid(ByteIOContext *s, GUID *g)
594 {
595     int i;
596
597     g->v1 = get_le32(s);
598     g->v2 = get_le16(s);
599     g->v3 = get_le16(s);
600     for(i=0;i<8;i++)
601         g->v4[i] = get_byte(s);
602 }
603
604 #if 0
605 static void get_str16(ByteIOContext *pb, char *buf, int buf_size)
606 {
607     int len, c;
608     char *q;
609
610     len = get_le16(pb);
611     q = buf;
612     while (len > 0) {
613         c = get_le16(pb);
614         if ((q - buf) < buf_size - 1)
615             *q++ = c;
616         len--;
617     }
618     *q = '\0';
619 }
620 #endif
621
622 static void get_str16_nolen(ByteIOContext *pb, int len, char *buf, int buf_size)
623 {
624     int c;
625     char *q;
626
627     q = buf;
628     while (len > 0) {
629         c = get_le16(pb);
630         if ((q - buf) < buf_size - 1)
631             *q++ = c;
632         len-=2;
633     }
634     *q = '\0';
635 }
636
637 static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap)
638 {
639     ASFContext *asf;
640     GUID g;
641     ByteIOContext *pb = &s->pb;
642     AVStream *st;
643     ASFStream *asf_st;
644     int size, i, bps;
645     INT64 gsize;
646
647     asf = av_mallocz(sizeof(ASFContext));
648     if (!asf)
649         return -1;
650     s->priv_data = asf;
651
652     get_guid(pb, &g);
653     if (memcmp(&g, &asf_header, sizeof(GUID)))
654         goto fail;
655     get_le64(pb);
656     get_le32(pb);
657     get_byte(pb);
658     get_byte(pb);
659
660     for(;;) {
661         get_guid(pb, &g);
662         gsize = get_le64(pb);
663 #ifdef DEBUG
664         printf("%08Lx: ", url_ftell(pb) - 24);
665         print_guid(&g);
666         printf("  size=0x%Lx\n", gsize);
667 #endif
668         if (gsize < 24)
669             goto fail;
670         if (!memcmp(&g, &file_header, sizeof(GUID))) {
671             get_guid(pb, &g);
672             get_le64(pb); /* file size */
673             get_le64(pb); /* file time */
674             get_le64(pb); /* nb_packets */
675             get_le64(pb); /* length 0 in us */
676             get_le64(pb); /* length 1 in us */
677             get_le32(pb);
678             get_le32(pb);
679             get_le32(pb);
680             asf->packet_size = get_le32(pb);
681             get_le32(pb);
682             get_le32(pb);
683         } else if (!memcmp(&g, &stream_header, sizeof(GUID))) {
684             int type, id, total_size;
685             unsigned int tag1;
686             INT64 pos1, pos2;
687             
688             pos1 = url_ftell(pb);
689
690             st = av_mallocz(sizeof(AVStream));
691             if (!st)
692                 goto fail;
693             s->streams[s->nb_streams++] = st;
694             asf_st = av_mallocz(sizeof(ASFStream));
695             if (!asf_st)
696                 goto fail;
697             st->priv_data = asf_st;
698
699             get_guid(pb, &g);
700             if (!memcmp(&g, &audio_stream, sizeof(GUID))) {
701                 type = CODEC_TYPE_AUDIO;
702             } else if (!memcmp(&g, &video_stream, sizeof(GUID))) {
703                 type = CODEC_TYPE_VIDEO;
704             } else {
705                 goto fail;
706             }
707             get_guid(pb, &g);
708             total_size = get_le64(pb);
709             get_le32(pb);
710             get_le32(pb);
711             st->id = get_le16(pb); /* stream id */
712             get_le32(pb);
713             st->codec.codec_type = type;
714             if (type == CODEC_TYPE_AUDIO) {
715                 id = get_le16(pb); 
716                 st->codec.codec_tag = id;
717                 st->codec.channels = get_le16(pb);
718                 st->codec.sample_rate = get_le32(pb);
719                 st->codec.bit_rate = get_le32(pb) * 8;
720                 get_le16(pb); /* block align */
721                 bps = get_le16(pb); /* bits per sample */
722                 st->codec.codec_id = wav_codec_get_id(id, bps);
723                 size = get_le16(pb);
724                 url_fskip(pb, size);
725             } else {
726                 get_le32(pb);
727                 get_le32(pb);
728                 get_byte(pb);
729                 size = get_le16(pb); /* size */
730                 get_le32(pb); /* size */
731                 st->codec.width = get_le32(pb);
732                 st->codec.height = get_le32(pb);
733                 st->codec.frame_rate = 25 * FRAME_RATE_BASE; /* XXX: find it */
734                 get_le16(pb); /* panes */
735                 get_le16(pb); /* depth */
736                 tag1 = get_le32(pb);
737                 st->codec.codec_tag = tag1;
738                 st->codec.codec_id = codec_get_id(codec_bmp_tags, tag1);
739                 url_fskip(pb, size - 5 * 4);
740             }
741             pos2 = url_ftell(pb);
742             url_fskip(pb, gsize - (pos2 - pos1 + 24));
743         } else if (!memcmp(&g, &data_header, sizeof(GUID))) {
744             break;
745         } else if (!memcmp(&g, &comment_header, sizeof(GUID))) {
746             int len1, len2, len3, len4, len5;
747
748             len1 = get_le16(pb);
749             len2 = get_le16(pb);
750             len3 = get_le16(pb);
751             len4 = get_le16(pb);
752             len5 = get_le16(pb);
753             get_str16_nolen(pb, len1, s->title, sizeof(s->title));
754             get_str16_nolen(pb, len2, s->author, sizeof(s->author));
755             get_str16_nolen(pb, len3, s->copyright, sizeof(s->copyright));
756             get_str16_nolen(pb, len4, s->comment, sizeof(s->comment));
757             url_fskip(pb, len5);
758 #if 0
759         } else if (!memcmp(&g, &head1_guid, sizeof(GUID))) {
760             int v1, v2;
761             get_guid(pb, &g);
762             v1 = get_le32(pb);
763             v2 = get_le16(pb);
764         } else if (!memcmp(&g, &codec_comment_header, sizeof(GUID))) {
765             int len, v1, n, num;
766             char str[256], *q;
767             char tag[16];
768
769             get_guid(pb, &g);
770             print_guid(&g);
771             
772             n = get_le32(pb);
773             for(i=0;i<n;i++) {
774                 num = get_le16(pb); /* stream number */
775                 get_str16(pb, str, sizeof(str));
776                 get_str16(pb, str, sizeof(str));
777                 len = get_le16(pb);
778                 q = tag;
779                 while (len > 0) {
780                     v1 = get_byte(pb);
781                     if ((q - tag) < sizeof(tag) - 1)
782                         *q++ = v1;
783                     len--;
784                 }
785                 *q = '\0';
786             }
787 #endif
788         } else if (url_feof(pb)) {
789             goto fail;
790         } else {
791             url_fseek(pb, gsize - 24, SEEK_CUR);
792         }
793     }
794     get_guid(pb, &g);
795     get_le64(pb);
796     get_byte(pb);
797     get_byte(pb);
798
799     asf->packet_size_left = 0;
800
801     return 0;
802
803  fail:
804     for(i=0;i<s->nb_streams;i++) {
805         AVStream *st = s->streams[i];
806         if (st)
807             free(st->priv_data);
808         free(st);
809     }
810     free(asf);
811     return -1;
812 }
813
814 static int asf_get_packet(AVFormatContext *s)
815 {
816     ASFContext *asf = s->priv_data;
817     ByteIOContext *pb = &s->pb;
818     int c, flags, timestamp, hdr_size;
819
820     hdr_size = 12;
821     c = get_byte(pb);
822     if (c != 0x82)
823         return -EIO;
824     get_le16(pb);
825     flags = get_byte(pb);
826     get_byte(pb);
827     asf->packet_padsize = 0;
828     if (flags & 0x10) {
829         asf->packet_padsize = get_le16(pb);
830         hdr_size += 2;
831     } else if (flags & 0x08) {
832         asf->packet_padsize = get_byte(pb);
833         hdr_size++;
834     }
835     timestamp = get_le32(pb);
836     get_le16(pb); /* duration */
837     get_byte(pb); /* nb_frames */
838 #ifdef DEBUG
839     printf("packet: size=%d padsize=%d\n", asf->packet_size, asf->packet_padsize);
840 #endif
841     asf->packet_size_left = asf->packet_size - hdr_size;
842     return 0;
843 }
844
845 static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
846 {
847     ASFContext *asf = s->priv_data;
848     AVStream *st;
849     ASFStream *asf_st;
850     ByteIOContext *pb = &s->pb;
851     int ret, num, seq, frag_offset, payload_size, frag_len;
852     int timestamp, i;
853
854     for(;;) {
855         if (asf->packet_size_left < FRAME_HEADER_SIZE ||
856             asf->packet_size_left <= asf->packet_padsize) {
857             /* fail safe */
858             if (asf->packet_size_left)
859                 url_fskip(pb, asf->packet_size_left);
860             ret = asf_get_packet(s);
861             if (ret < 0)
862                 return -EIO;
863         }
864         /* read frame header */
865         num = get_byte(pb) & 0x7f;
866         seq = get_byte(pb);
867         frag_offset = get_le32(pb);
868         get_byte(pb); /* flags */
869         payload_size = get_le32(pb);
870         timestamp = get_le32(pb);
871         frag_len = get_le16(pb);
872 #ifdef DEBUG
873         printf("num=%d seq=%d totsize=%d frag_off=%d frag_size=%d\n",
874                num, seq, payload_size, frag_offset, frag_len);
875 #endif
876         st = NULL;
877         for(i=0;i<s->nb_streams;i++) {
878             st = s->streams[i];
879             if (st->id == num)
880                 break;
881         }
882         asf->packet_size_left -= FRAME_HEADER_SIZE + frag_len;
883         if (i == s->nb_streams) {
884             /* unhandled packet (should not happen) */
885             url_fskip(pb, frag_len);
886         } else {
887             asf_st = st->priv_data;
888             if (asf_st->frag_offset == 0) {
889                 /* new packet */
890                 av_new_packet(&asf_st->pkt, payload_size);
891                 asf_st->seq = seq;
892             } else {
893                 if (seq == asf_st->seq && 
894                     frag_offset == asf_st->frag_offset) {
895                     /* continuing packet */
896                 } else {
897                     /* cannot continue current packet: free it */
898                     av_free_packet(&asf_st->pkt);
899                     asf_st->frag_offset = 0;
900                     if (frag_offset != 0) {
901                         /* cannot create new packet */
902                         url_fskip(pb, frag_len);
903                         goto next_frame;
904                     } else {
905                         /* create new packet */
906                         av_new_packet(&asf_st->pkt, payload_size);
907                         asf_st->seq = seq;
908                     }
909                 }
910             }
911             /* read data */
912             get_buffer(pb, asf_st->pkt.data + frag_offset, frag_len);
913             asf_st->frag_offset += frag_len;
914             /* test if whole packet read */
915             if (asf_st->frag_offset == asf_st->pkt.size) {
916                 /* return packet */
917                 asf_st->pkt.stream_index = i;
918                 asf_st->frag_offset = 0;
919                 memcpy(pkt, &asf_st->pkt, sizeof(AVPacket)); 
920                 break;
921             }
922         }
923     next_frame:;
924     }
925
926     return 0;
927 }
928
929 static int asf_read_close(AVFormatContext *s)
930 {
931     ASFContext *asf = s->priv_data;
932     int i;
933
934     for(i=0;i<s->nb_streams;i++) {
935         AVStream *st = s->streams[i];
936             free(st->priv_data);
937     }
938     free(asf);
939     return 0;
940 }
941
942 AVFormat asf_format = {
943     "asf",
944     "asf format",
945     "application/octet-stream",
946     "asf,wmv",
947     CODEC_ID_MP2,
948     CODEC_ID_MSMPEG4,
949     asf_write_header,
950     asf_write_packet,
951     asf_write_trailer,
952
953     asf_read_header,
954     asf_read_packet,
955     asf_read_close,
956 };