Initial revision
[libav.git] / asfenc.c
1 /*
2 * ASF compatible encoder
3 * Copyright (c) 2000 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 <stdlib.h>
20 #include <stdio.h>
21 #include <netinet/in.h>
22 #include <string.h>
23 #include "mpegenc.h"
24
25 #define PACKET_SIZE 3200
26 #define PACKET_HEADER_SIZE 12
27 #define FRAME_HEADER_SIZE 17
28
29 typedef struct {
30 AVEncodeContext *enc;
31 int num;
32 int seq;
33 } ASFStream;
34
35 typedef struct {
36 int is_streamed; /* true if streamed */
37 int seqno;
38 int packet_size;
39
40 ASFStream streams[2];
41 ASFStream *audio_stream, *video_stream;
42 int nb_streams;
43 /* non streamed additonnal info */
44 int file_size_offset;
45 int data_offset;
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 PutByteContext pb;
53 } ASFContext;
54
55 typedef struct {
56 UINT32 v1;
57 UINT16 v2;
58 UINT16 v3;
59 UINT8 v4[8];
60 } GUID;
61
62 static const GUID asf_header = {
63 0x75B22630, 0x668E, 0x11CF, { 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C },
64 };
65
66 static const GUID file_header = {
67 0x8CABDCA1, 0xA947, 0x11CF, { 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 },
68 };
69
70 static const GUID stream_header = {
71 0xB7DC0791, 0xA9B7, 0x11CF, { 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 },
72 };
73
74 static const GUID audio_stream = {
75 0xF8699E40, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
76 };
77
78 static const GUID audio_conceal_none = {
79 0x49f1a440, 0x4ece, 0x11d0, { 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6 },
80 };
81
82 static const GUID video_stream = {
83 0xBC19EFC0, 0x5B4D, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
84 };
85
86 static const GUID video_conceal_none = {
87 0x20FB5700, 0x5B55, 0x11CF, { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B },
88 };
89
90 static const GUID comment_header = {
91 0x86D15240, 0x311D, 0x11D0, { 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6 },
92 };
93
94 static const GUID data_header = {
95 0x75b22636, 0x668e, 0x11cf, { 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c },
96 };
97
98 static const GUID packet_guid = {
99 0xF656CCE1, 0x03B3, 0x11D4, { 0xBE, 0xA2, 0x00, 0xA0, 0xCC, 0x3D, 0x72, 0x74 },
100 };
101
102 /* I am not a number !!! This GUID is the one found on the PC used to
103 generate the stream */
104 static const GUID my_guid = {
105 0x12345678, 0xA947, 0x11CF, { 0x31, 0x41, 0x59, 0x26, 0x20, 0x20, 0x20, 0x20 },
106 };
107
108 static void put_guid(PutByteContext *s, const GUID *g)
109 {
110 int i;
111
112 put_le32(s, g->v1);
113 put_le16(s, g->v2);
114 put_le16(s, g->v3);
115 for(i=0;i<8;i++)
116 put_byte(s, g->v4[i]);
117 }
118
119 #if 0
120 static void put_str16(PutByteContext *s, const char *tag)
121 {
122 put_le16(s,strlen(tag));
123 while (*tag) {
124 put_le16(s, *tag++);
125 }
126 }
127 #endif
128
129 /* write an asf chunk (only used in streaming case) */
130 static void put_chunk(AVFormatContext *s, int type, int payload_length)
131 {
132 ASFContext *asf = s->priv_data;
133 PutByteContext *pb = &s->pb;
134 int length;
135
136 length = payload_length + 8;
137 put_le16(pb, type);
138 put_le16(pb, length);
139 put_le32(pb, asf->seqno);
140 put_le16(pb, 0); /* unknown bytes */
141 put_le16(pb, length);
142 asf->seqno++;
143 }
144
145
146 static int asf_write_header(AVFormatContext *s)
147 {
148 PutByteContext *pb = &s->pb;
149 ASFContext *asf;
150 int header_size, n, extra_size, extra_size2, i, wav_extra_size;
151 AVEncodeContext *enc;
152 long long header_offset, cur_pos;
153
154 asf = malloc(sizeof(ASFContext));
155 if (!asf)
156 return -1;
157 memset(asf, 0, sizeof(ASFContext));
158 s->priv_data = asf;
159
160 asf->packet_size = PACKET_SIZE;
161
162 if (!s->is_streamed) {
163 put_guid(pb, &asf_header);
164 put_le64(pb, 0); /* header length, will be patched after */
165 put_le32(pb, 6); /* ??? */
166 put_byte(pb, 1); /* ??? */
167 put_byte(pb, 2); /* ??? */
168 } else {
169 put_chunk(s, 0x4824, 0); /* start of stream (length will be patched later) */
170 }
171
172 /* file header */
173 header_offset = put_pos(pb);
174 put_guid(pb, &file_header);
175 put_le64(pb, 24 + 80);
176 put_guid(pb, &my_guid);
177 asf->file_size_offset = put_pos(pb);
178 put_le64(pb, 0); /* file size (patched after if not streamed) */
179 put_le64(pb, 0); /* file time : 1601 :-) */
180 put_le64(pb, 0x283); /* ??? */
181 put_le64(pb, 0); /* stream 0 length in us */
182 put_le64(pb, 0); /* stream 1 length in us */
183 put_le32(pb, 0x0c1c); /* ??? */
184 put_le32(pb, 0); /* ??? */
185 put_le32(pb, 2); /* ??? */
186 put_le32(pb, asf->packet_size); /* packet size */
187 put_le32(pb, asf->packet_size); /* ??? */
188 put_le32(pb, 0x03e800); /* ??? */
189
190 /* stream headers */
191 n = 0;
192 for(i=0;i<2;i++) {
193 if (i == 0)
194 enc = s->audio_enc;
195 else
196 enc = s->video_enc;
197
198 if (!enc)
199 continue;
200 asf->streams[n].num = i;
201 asf->streams[n].seq = 0;
202 asf->streams[n].enc = enc;
203
204 switch(enc->codec->type) {
205 case CODEC_TYPE_AUDIO:
206 asf->audio_stream = &asf->streams[n];
207 wav_extra_size = 0;
208 extra_size = 18 + wav_extra_size;
209 extra_size2 = 0;
210 break;
211 default:
212 case CODEC_TYPE_VIDEO:
213 asf->video_stream = &asf->streams[n];
214 wav_extra_size = 0;
215 extra_size = 0x33;
216 extra_size2 = 0;
217 break;
218 }
219
220 put_guid(pb, &stream_header);
221 put_le64(pb, 24 + 16 * 2 + 22 + extra_size + extra_size2);
222 if (enc->codec->type == CODEC_TYPE_AUDIO) {
223 put_guid(pb, &audio_stream);
224 put_guid(pb, &audio_conceal_none);
225 } else {
226 put_guid(pb, &video_stream);
227 put_guid(pb, &video_conceal_none);
228 }
229 put_le64(pb, 0); /* ??? */
230 put_le32(pb, extra_size); /* wav header len */
231 put_le32(pb, extra_size2); /* additional data len */
232 put_le16(pb, n + 1); /* stream number */
233 put_le32(pb, 0); /* ??? */
234
235 if (enc->codec->type == CODEC_TYPE_AUDIO) {
236 /* WAVEFORMATEX header */
237
238 put_le16(pb, 0x55); /* MP3 format */
239 put_le16(pb, s->audio_enc->channels);
240 put_le32(pb, s->audio_enc->rate);
241 put_le32(pb, s->audio_enc->bit_rate / 8);
242 put_le16(pb, 1); /* block align */
243 put_le16(pb, 16); /* bits per sample */
244 put_le16(pb, wav_extra_size);
245
246 /* no addtionnal adata */
247 } else {
248 put_le32(pb, enc->width);
249 put_le32(pb, enc->height);
250 put_byte(pb, 2); /* ??? */
251 put_le16(pb, 40); /* size */
252
253 /* BITMAPINFOHEADER header */
254 put_le32(pb, 40); /* size */
255 put_le32(pb, enc->width);
256 put_le32(pb, enc->height);
257 put_le16(pb, 1); /* planes */
258 put_le16(pb, 24); /* depth */
259 /* compression type */
260 switch(enc->codec->id) {
261 case CODEC_ID_H263:
262 put_tag(pb, "I263");
263 break;
264 case CODEC_ID_MJPEG:
265 put_tag(pb, "MJPG");
266 break;
267 default:
268 put_tag(pb, "XXXX");
269 break;
270 }
271 put_le32(pb, enc->width * enc->height * 3);
272 put_le32(pb, 0);
273 put_le32(pb, 0);
274 put_le32(pb, 0);
275 put_le32(pb, 0);
276 }
277 n++;
278 }
279 asf->nb_streams = n;
280
281 /* XXX: should media comments */
282 #if 0
283 put_guid(pb, &comment_header);
284 put_le64(pb, 0);
285 #endif
286 /* patch the header size fields */
287 cur_pos = put_pos(pb);
288 header_size = cur_pos - header_offset;
289 if (!s->is_streamed) {
290 header_size += 24 + 6;
291 put_seek(pb, header_offset - 14, SEEK_SET);
292 put_le64(pb, header_size);
293 } else {
294 header_size += 8 + 50;
295 put_seek(pb, header_offset - 10, SEEK_SET);
296 put_le16(pb, header_size);
297 put_seek(pb, header_offset - 2, SEEK_SET);
298 put_le16(pb, header_size);
299 }
300 put_seek(pb, cur_pos, SEEK_SET);
301
302 /* movie chunk, followed by packets of packet_size */
303 asf->data_offset = cur_pos;
304 put_guid(pb, &data_header);
305 put_le64(pb, 24); /* will be patched after */
306 put_guid(pb, &packet_guid);
307 put_le64(pb, 0x283); /* ??? */
308 put_byte(pb, 1); /* ??? */
309 put_byte(pb, 1); /* ??? */
310
311 put_flush_packet(&s->pb);
312
313 asf->packet_nb_frames = 0;
314 asf->packet_timestamp_start = -1;
315 asf->packet_timestamp_end = -1;
316 asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
317 init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size,
318 NULL, NULL, NULL);
319
320 return 0;
321 }
322
323 /* write a fixed size packet */
324 static void put_packet(AVFormatContext *s,
325 unsigned int timestamp, unsigned int duration,
326 int nb_frames, int padsize)
327 {
328 ASFContext *asf = s->priv_data;
329 PutByteContext *pb = &s->pb;
330 int flags;
331
332 if (s->is_streamed) {
333 put_chunk(s, 0x4424, asf->packet_size);
334 }
335
336 put_byte(pb, 0x82);
337 put_le16(pb, 0);
338
339 flags = 0x01; /* nb segments present */
340 if (padsize > 0) {
341 if (padsize < 256)
342 flags |= 0x08;
343 else
344 flags |= 0x10;
345 }
346 put_byte(pb, flags); /* flags */
347 put_byte(pb, 0x5d);
348 if (flags & 0x10)
349 put_le16(pb, padsize);
350 if (flags & 0x08)
351 put_byte(pb, padsize);
352 put_le32(pb, timestamp);
353 put_le16(pb, duration);
354 put_byte(pb, nb_frames | 0x80);
355 }
356
357 static void flush_packet(AVFormatContext *s)
358 {
359 ASFContext *asf = s->priv_data;
360 int hdr_size, ptr;
361
362 put_packet(s, asf->packet_timestamp_start,
363 asf->packet_timestamp_end - asf->packet_timestamp_start,
364 asf->packet_nb_frames, asf->packet_size_left);
365
366 /* compute padding */
367 hdr_size = PACKET_HEADER_SIZE;
368 if (asf->packet_size_left > 0) {
369 /* if padding needed, don't forget to count the
370 padding byte in the header size */
371 hdr_size++;
372 asf->packet_size_left--;
373 /* XXX: I do not test again exact limit to avoid boundary problems */
374 if (asf->packet_size_left > 200) {
375 hdr_size++;
376 asf->packet_size_left--;
377 }
378 }
379 ptr = asf->packet_size - PACKET_HEADER_SIZE - asf->packet_size_left;
380 memset(asf->packet_buf + ptr, 0, asf->packet_size_left);
381
382 put_buffer(&s->pb, asf->packet_buf, asf->packet_size - hdr_size);
383
384 put_flush_packet(&s->pb);
385 asf->packet_nb_frames = 0;
386 asf->packet_timestamp_start = -1;
387 asf->packet_timestamp_end = -1;
388 asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
389 init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size,
390 NULL, NULL, NULL);
391 }
392
393 static void put_frame_header(AVFormatContext *s, ASFStream *stream, int timestamp,
394 int payload_size, int frag_offset, int frag_len)
395 {
396 ASFContext *asf = s->priv_data;
397 PutByteContext *pb = &asf->pb;
398 int val;
399
400 val = stream->num;
401 if (stream->enc->key_frame)
402 val |= 0x80;
403 put_byte(pb, val);
404 put_byte(pb, stream->seq);
405 put_le32(pb, frag_offset); /* fragment offset */
406 put_byte(pb, 0x08); /* flags */
407 put_le32(pb, payload_size);
408 put_le32(pb, timestamp);
409 put_le16(pb, frag_len);
410 }
411
412
413 /* Output a frame. We suppose that payload_size <= PACKET_SIZE.
414
415 It is there that you understand that the ASF format is really
416 crap. They have misread the MPEG Systems spec !
417 */
418 static void put_frame(AVFormatContext *s, ASFStream *stream, int timestamp,
419 UINT8 *buf, int payload_size)
420 {
421 ASFContext *asf = s->priv_data;
422 int frag_pos, frag_len, frag_len1;
423
424 frag_pos = 0;
425 while (frag_pos < payload_size) {
426 frag_len = payload_size - frag_pos;
427 frag_len1 = asf->packet_size_left - FRAME_HEADER_SIZE;
428 if (frag_len1 > 0) {
429 if (frag_len > frag_len1)
430 frag_len = frag_len1;
431 put_frame_header(s, stream, timestamp, payload_size, frag_pos, frag_len);
432 put_buffer(&asf->pb, buf, frag_len);
433 asf->packet_size_left -= (frag_len + FRAME_HEADER_SIZE);
434 asf->packet_timestamp_end = timestamp;
435 if (asf->packet_timestamp_start == -1)
436 asf->packet_timestamp_start = timestamp;
437 asf->packet_nb_frames++;
438 } else {
439 frag_len = 0;
440 }
441 frag_pos += frag_len;
442 buf += frag_len;
443 /* output the frame if filled */
444 if (asf->packet_size_left <= FRAME_HEADER_SIZE)
445 flush_packet(s);
446 }
447 stream->seq++;
448 }
449
450
451 static int asf_write_audio(AVFormatContext *s, UINT8 *buf, int size)
452 {
453 ASFContext *asf = s->priv_data;
454 int timestamp;
455
456 timestamp = (int)((float)s->audio_enc->frame_number * s->audio_enc->frame_size * 1000.0 /
457 s->audio_enc->rate);
458 put_frame(s, asf->audio_stream, timestamp, buf, size);
459 return 0;
460 }
461
462 static int asf_write_video(AVFormatContext *s, UINT8 *buf, int size)
463 {
464 ASFContext *asf = s->priv_data;
465 int timestamp;
466
467 timestamp = (int)((float)s->video_enc->frame_number * 1000.0 /
468 s->video_enc->rate);
469 put_frame(s, asf->audio_stream, timestamp, buf, size);
470 return 0;
471 }
472
473 static int asf_write_trailer(AVFormatContext *s)
474 {
475 ASFContext *asf = s->priv_data;
476 long long file_size;
477
478 /* flush the current packet */
479 if (asf->pb.buf_ptr > asf->pb.buffer)
480 flush_packet(s);
481
482 if (s->is_streamed) {
483 put_chunk(s, 0x4524, 0); /* end of stream */
484 } else {
485 /* patch the various place which depends on the file size */
486 file_size = put_pos(&s->pb);
487 put_seek(&s->pb, asf->file_size_offset, SEEK_SET);
488 put_le64(&s->pb, file_size);
489 put_seek(&s->pb, asf->data_offset + 16, SEEK_SET);
490 put_le64(&s->pb, file_size - asf->data_offset);
491 }
492
493 put_flush_packet(&s->pb);
494
495 free(asf);
496 return 0;
497 }
498
499 AVFormat asf_format = {
500 "asf",
501 "asf format",
502 "application/octet-stream",
503 "asf",
504 CODEC_ID_MP2,
505 CODEC_ID_MJPEG,
506 asf_write_header,
507 asf_write_audio,
508 asf_write_video,
509 asf_write_trailer,
510 };