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