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