comparison asf-enc.c @ 372:2e12cd1b68ed libavformat

split asf patch by (Konstantin Andreyev <kandreyev at bcsii dot com>)
author michael
date Fri, 05 Mar 2004 21:34:30 +0000
parents asf.c@845f9de2c883
children e47d9c8e2054
comparison
equal deleted inserted replaced
371:b0e50e10472c 372:2e12cd1b68ed
1 /*
2 * Adaptive stream format encoder
3 * Copyright (c) 2000, 2001 Fabrice Bellard.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 #include "avformat.h"
20 #include "avi.h"
21 #include "asf.h"
22
23 #undef NDEBUG
24 #include <assert.h>
25
26 #ifdef CONFIG_ENCODERS
27 static void put_guid(ByteIOContext *s, const GUID *g)
28 {
29 int i;
30
31 put_le32(s, g->v1);
32 put_le16(s, g->v2);
33 put_le16(s, g->v3);
34 for(i=0;i<8;i++)
35 put_byte(s, g->v4[i]);
36 }
37
38 static void put_str16(ByteIOContext *s, const char *tag)
39 {
40 int c;
41
42 put_le16(s,strlen(tag) + 1);
43 for(;;) {
44 c = (uint8_t)*tag++;
45 put_le16(s, c);
46 if (c == '\0')
47 break;
48 }
49 }
50
51 static void put_str16_nolen(ByteIOContext *s, const char *tag)
52 {
53 int c;
54
55 for(;;) {
56 c = (uint8_t)*tag++;
57 put_le16(s, c);
58 if (c == '\0')
59 break;
60 }
61 }
62
63 static int64_t put_header(ByteIOContext *pb, const GUID *g)
64 {
65 int64_t pos;
66
67 pos = url_ftell(pb);
68 put_guid(pb, g);
69 put_le64(pb, 24);
70 return pos;
71 }
72
73 /* update header size */
74 static void end_header(ByteIOContext *pb, int64_t pos)
75 {
76 int64_t pos1;
77
78 pos1 = url_ftell(pb);
79 url_fseek(pb, pos + 16, SEEK_SET);
80 put_le64(pb, pos1 - pos);
81 url_fseek(pb, pos1, SEEK_SET);
82 }
83
84 /* write an asf chunk (only used in streaming case) */
85 static void put_chunk(AVFormatContext *s, int type, int payload_length, int flags)
86 {
87 ASFContext *asf = s->priv_data;
88 ByteIOContext *pb = &s->pb;
89 int length;
90
91 length = payload_length + 8;
92 put_le16(pb, type);
93 put_le16(pb, length);
94 put_le32(pb, asf->seqno);
95 put_le16(pb, flags); /* unknown bytes */
96 put_le16(pb, length);
97 asf->seqno++;
98 }
99
100 /* convert from unix to windows time */
101 static int64_t unix_to_file_time(int ti)
102 {
103 int64_t t;
104
105 t = ti * int64_t_C(10000000);
106 t += int64_t_C(116444736000000000);
107 return t;
108 }
109
110 /* write the header (used two times if non streamed) */
111 static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data_chunk_size)
112 {
113 ASFContext *asf = s->priv_data;
114 ByteIOContext *pb = &s->pb;
115 int header_size, n, extra_size, extra_size2, wav_extra_size, file_time;
116 int has_title;
117 AVCodecContext *enc;
118 int64_t header_offset, cur_pos, hpos;
119 int bit_rate;
120
121 has_title = (s->title[0] || s->author[0] || s->copyright[0] || s->comment[0]);
122
123 bit_rate = 0;
124 for(n=0;n<s->nb_streams;n++) {
125 enc = &s->streams[n]->codec;
126
127 bit_rate += enc->bit_rate;
128 }
129
130 if (asf->is_streamed) {
131 put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */
132 }
133
134 put_guid(pb, &asf_header);
135 put_le64(pb, -1); /* header length, will be patched after */
136 put_le32(pb, 3 + has_title + s->nb_streams); /* number of chunks in header */
137 put_byte(pb, 1); /* ??? */
138 put_byte(pb, 2); /* ??? */
139
140 /* file header */
141 header_offset = url_ftell(pb);
142 hpos = put_header(pb, &file_header);
143 put_guid(pb, &my_guid);
144 put_le64(pb, file_size);
145 file_time = 0;
146 put_le64(pb, unix_to_file_time(file_time));
147 put_le64(pb, asf->nb_packets); /* number of packets */
148 put_le64(pb, asf->duration); /* end time stamp (in 100ns units) */
149 put_le64(pb, asf->duration); /* duration (in 100ns units) */
150 put_le32(pb, 0); /* start time stamp */
151 put_le32(pb, 0); /* ??? */
152 put_le32(pb, asf->is_streamed ? 1 : 0); /* ??? */
153 put_le32(pb, asf->packet_size); /* packet size */
154 put_le32(pb, asf->packet_size); /* packet size */
155 put_le32(pb, bit_rate); /* Nominal data rate in bps */
156 end_header(pb, hpos);
157
158 /* unknown headers */
159 hpos = put_header(pb, &head1_guid);
160 put_guid(pb, &head2_guid);
161 put_le32(pb, 6);
162 put_le16(pb, 0);
163 end_header(pb, hpos);
164
165 /* title and other infos */
166 if (has_title) {
167 hpos = put_header(pb, &comment_header);
168 put_le16(pb, 2 * (strlen(s->title) + 1));
169 put_le16(pb, 2 * (strlen(s->author) + 1));
170 put_le16(pb, 2 * (strlen(s->copyright) + 1));
171 put_le16(pb, 2 * (strlen(s->comment) + 1));
172 put_le16(pb, 0);
173 put_str16_nolen(pb, s->title);
174 put_str16_nolen(pb, s->author);
175 put_str16_nolen(pb, s->copyright);
176 put_str16_nolen(pb, s->comment);
177 end_header(pb, hpos);
178 }
179
180 /* stream headers */
181 for(n=0;n<s->nb_streams;n++) {
182 int64_t es_pos;
183 // ASFStream *stream = &asf->streams[n];
184
185 enc = &s->streams[n]->codec;
186 asf->streams[n].num = n + 1;
187 asf->streams[n].seq = 0;
188
189 switch(enc->codec_type) {
190 case CODEC_TYPE_AUDIO:
191 wav_extra_size = 0;
192 extra_size = 18 + wav_extra_size;
193 extra_size2 = 0;
194 break;
195 default:
196 case CODEC_TYPE_VIDEO:
197 wav_extra_size = 0;
198 extra_size = 0x33;
199 extra_size2 = 0;
200 break;
201 }
202
203 hpos = put_header(pb, &stream_header);
204 if (enc->codec_type == CODEC_TYPE_AUDIO) {
205 put_guid(pb, &audio_stream);
206 put_guid(pb, &audio_conceal_none);
207 } else {
208 put_guid(pb, &video_stream);
209 put_guid(pb, &video_conceal_none);
210 }
211 put_le64(pb, 0); /* ??? */
212 es_pos = url_ftell(pb);
213 put_le32(pb, extra_size); /* wav header len */
214 put_le32(pb, extra_size2); /* additional data len */
215 put_le16(pb, n + 1); /* stream number */
216 put_le32(pb, 0); /* ??? */
217
218 if (enc->codec_type == CODEC_TYPE_AUDIO) {
219 /* WAVEFORMATEX header */
220 int wavsize = put_wav_header(pb, enc);
221
222 if (wavsize < 0)
223 return -1;
224 if (wavsize != extra_size) {
225 cur_pos = url_ftell(pb);
226 url_fseek(pb, es_pos, SEEK_SET);
227 put_le32(pb, wavsize); /* wav header len */
228 url_fseek(pb, cur_pos, SEEK_SET);
229 }
230 } else {
231 put_le32(pb, enc->width);
232 put_le32(pb, enc->height);
233 put_byte(pb, 2); /* ??? */
234 put_le16(pb, 40); /* size */
235
236 /* BITMAPINFOHEADER header */
237 put_bmp_header(pb, enc, codec_bmp_tags, 1);
238 }
239 end_header(pb, hpos);
240 }
241
242 /* media comments */
243
244 hpos = put_header(pb, &codec_comment_header);
245 put_guid(pb, &codec_comment1_header);
246 put_le32(pb, s->nb_streams);
247 for(n=0;n<s->nb_streams;n++) {
248 AVCodec *p;
249
250 enc = &s->streams[n]->codec;
251 p = avcodec_find_encoder(enc->codec_id);
252
253 put_le16(pb, asf->streams[n].num);
254 put_str16(pb, p ? p->name : enc->codec_name);
255 put_le16(pb, 0); /* no parameters */
256
257
258 /* id */
259 if (enc->codec_type == CODEC_TYPE_AUDIO) {
260 put_le16(pb, 2);
261 if(!enc->codec_tag)
262 enc->codec_tag = codec_get_tag(codec_wav_tags, enc->codec_id);
263 if(!enc->codec_tag)
264 return -1;
265 put_le16(pb, enc->codec_tag);
266 } else {
267 put_le16(pb, 4);
268 if(!enc->codec_tag)
269 enc->codec_tag = codec_get_tag(codec_bmp_tags, enc->codec_id);
270 if(!enc->codec_tag)
271 return -1;
272 put_le32(pb, enc->codec_tag);
273 }
274 }
275 end_header(pb, hpos);
276
277 /* patch the header size fields */
278
279 cur_pos = url_ftell(pb);
280 header_size = cur_pos - header_offset;
281 if (asf->is_streamed) {
282 header_size += 8 + 30 + 50;
283
284 url_fseek(pb, header_offset - 10 - 30, SEEK_SET);
285 put_le16(pb, header_size);
286 url_fseek(pb, header_offset - 2 - 30, SEEK_SET);
287 put_le16(pb, header_size);
288
289 header_size -= 8 + 30 + 50;
290 }
291 header_size += 24 + 6;
292 url_fseek(pb, header_offset - 14, SEEK_SET);
293 put_le64(pb, header_size);
294 url_fseek(pb, cur_pos, SEEK_SET);
295
296 /* movie chunk, followed by packets of packet_size */
297 asf->data_offset = cur_pos;
298 put_guid(pb, &data_header);
299 put_le64(pb, data_chunk_size);
300 put_guid(pb, &my_guid);
301 put_le64(pb, asf->nb_packets); /* nb packets */
302 put_byte(pb, 1); /* ??? */
303 put_byte(pb, 1); /* ??? */
304 return 0;
305 }
306
307 static int asf_write_header(AVFormatContext *s)
308 {
309 ASFContext *asf = s->priv_data;
310
311 av_set_pts_info(s, 32, 1, 1000); /* 32 bit pts in ms */
312
313 asf->packet_size = PACKET_SIZE;
314 asf->nb_packets = 0;
315
316 if (asf_write_header1(s, 0, 50) < 0) {
317 //av_free(asf);
318 return -1;
319 }
320
321 put_flush_packet(&s->pb);
322
323 asf->packet_nb_frames = 0;
324 asf->packet_timestamp_start = -1;
325 asf->packet_timestamp_end = -1;
326 asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
327 init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size, 1,
328 NULL, NULL, NULL, NULL);
329
330 return 0;
331 }
332
333 static int asf_write_stream_header(AVFormatContext *s)
334 {
335 ASFContext *asf = s->priv_data;
336
337 asf->is_streamed = 1;
338
339 return asf_write_header(s);
340 }
341
342 /* write a fixed size packet */
343 static int put_packet(AVFormatContext *s,
344 unsigned int timestamp, unsigned int duration,
345 int nb_frames, int padsize)
346 {
347 ASFContext *asf = s->priv_data;
348 ByteIOContext *pb = &s->pb;
349 int flags;
350
351 if (asf->is_streamed) {
352 put_chunk(s, 0x4424, asf->packet_size, 0);
353 }
354
355 put_byte(pb, 0x82);
356 put_le16(pb, 0);
357
358 flags = 0x01; /* nb segments present */
359 if (padsize > 0) {
360 if (padsize < 256)
361 flags |= 0x08;
362 else
363 flags |= 0x10;
364 }
365 put_byte(pb, flags); /* flags */
366 put_byte(pb, 0x5d);
367 if (flags & 0x10)
368 put_le16(pb, padsize - 2);
369 if (flags & 0x08)
370 put_byte(pb, padsize - 1);
371 put_le32(pb, timestamp);
372 put_le16(pb, duration);
373 put_byte(pb, nb_frames | 0x80);
374
375 return PACKET_HEADER_SIZE + ((flags & 0x18) >> 3);
376 }
377
378 static void flush_packet(AVFormatContext *s)
379 {
380 ASFContext *asf = s->priv_data;
381 int hdr_size, ptr;
382
383 hdr_size = put_packet(s, asf->packet_timestamp_start,
384 asf->packet_timestamp_end - asf->packet_timestamp_start,
385 asf->packet_nb_frames, asf->packet_size_left);
386
387 /* Clear out the padding bytes */
388 ptr = asf->packet_size - hdr_size - asf->packet_size_left;
389 memset(asf->packet_buf + ptr, 0, asf->packet_size_left);
390
391 put_buffer(&s->pb, asf->packet_buf, asf->packet_size - hdr_size);
392
393 put_flush_packet(&s->pb);
394 asf->nb_packets++;
395 asf->packet_nb_frames = 0;
396 asf->packet_timestamp_start = -1;
397 asf->packet_timestamp_end = -1;
398 asf->packet_size_left = asf->packet_size - PACKET_HEADER_SIZE;
399 init_put_byte(&asf->pb, asf->packet_buf, asf->packet_size, 1,
400 NULL, NULL, NULL, NULL);
401 }
402
403 static void put_frame_header(AVFormatContext *s, ASFStream *stream, int timestamp,
404 int payload_size, int frag_offset, int frag_len)
405 {
406 ASFContext *asf = s->priv_data;
407 ByteIOContext *pb = &asf->pb;
408 int val;
409
410 val = stream->num;
411 if (s->streams[val - 1]->codec.coded_frame->key_frame /* && frag_offset == 0 */)
412 val |= 0x80;
413 put_byte(pb, val);
414 put_byte(pb, stream->seq);
415 put_le32(pb, frag_offset); /* fragment offset */
416 put_byte(pb, 0x08); /* flags */
417 put_le32(pb, payload_size);
418 put_le32(pb, timestamp);
419 put_le16(pb, frag_len);
420 }
421
422
423 /* Output a frame. We suppose that payload_size <= PACKET_SIZE.
424
425 It is there that you understand that the ASF format is really
426 crap. They have misread the MPEG Systems spec !
427 */
428 static void put_frame(AVFormatContext *s, ASFStream *stream, int timestamp,
429 const uint8_t *buf, int payload_size)
430 {
431 ASFContext *asf = s->priv_data;
432 int frag_pos, frag_len, frag_len1;
433
434 frag_pos = 0;
435 while (frag_pos < payload_size) {
436 frag_len = payload_size - frag_pos;
437 frag_len1 = asf->packet_size_left - FRAME_HEADER_SIZE;
438 if (frag_len1 > 0) {
439 if (frag_len > frag_len1)
440 frag_len = frag_len1;
441 put_frame_header(s, stream, timestamp+1, payload_size, frag_pos, frag_len);
442 put_buffer(&asf->pb, buf, frag_len);
443 asf->packet_size_left -= (frag_len + FRAME_HEADER_SIZE);
444 asf->packet_timestamp_end = timestamp;
445 if (asf->packet_timestamp_start == -1)
446 asf->packet_timestamp_start = timestamp;
447 asf->packet_nb_frames++;
448 } else {
449 frag_len = 0;
450 }
451 frag_pos += frag_len;
452 buf += frag_len;
453 /* output the frame if filled */
454 if (asf->packet_size_left <= FRAME_HEADER_SIZE)
455 flush_packet(s);
456 }
457 stream->seq++;
458 }
459
460
461 static int asf_write_packet(AVFormatContext *s, int stream_index,
462 const uint8_t *buf, int size, int64_t timestamp)
463 {
464 ASFContext *asf = s->priv_data;
465 ASFStream *stream;
466 int64_t duration;
467 AVCodecContext *codec;
468
469 codec = &s->streams[stream_index]->codec;
470 stream = &asf->streams[stream_index];
471
472 if (codec->codec_type == CODEC_TYPE_AUDIO) {
473 duration = (codec->frame_number * codec->frame_size * int64_t_C(10000000)) /
474 codec->sample_rate;
475 } else {
476 duration = av_rescale(codec->frame_number * codec->frame_rate_base, 10000000, codec->frame_rate);
477 }
478 if (duration > asf->duration)
479 asf->duration = duration;
480
481 put_frame(s, stream, timestamp, buf, size);
482 return 0;
483 }
484
485 static int asf_write_trailer(AVFormatContext *s)
486 {
487 ASFContext *asf = s->priv_data;
488 int64_t file_size;
489
490 /* flush the current packet */
491 if (asf->pb.buf_ptr > asf->pb.buffer)
492 flush_packet(s);
493
494 if (asf->is_streamed) {
495 put_chunk(s, 0x4524, 0, 0); /* end of stream */
496 } else {
497 /* rewrite an updated header */
498 file_size = url_ftell(&s->pb);
499 url_fseek(&s->pb, 0, SEEK_SET);
500 asf_write_header1(s, file_size, file_size - asf->data_offset);
501 }
502
503 put_flush_packet(&s->pb);
504 return 0;
505 }
506
507 AVOutputFormat asf_oformat = {
508 "asf",
509 "asf format",
510 "video/x-ms-asf",
511 "asf,wmv",
512 sizeof(ASFContext),
513 #ifdef CONFIG_MP3LAME
514 CODEC_ID_MP3,
515 #else
516 CODEC_ID_MP2,
517 #endif
518 CODEC_ID_MSMPEG4V3,
519 asf_write_header,
520 asf_write_packet,
521 asf_write_trailer,
522 };
523
524 AVOutputFormat asf_stream_oformat = {
525 "asf_stream",
526 "asf format",
527 "video/x-ms-asf",
528 "asf,wmv",
529 sizeof(ASFContext),
530 #ifdef CONFIG_MP3LAME
531 CODEC_ID_MP3,
532 #else
533 CODEC_ID_MP2,
534 #endif
535 CODEC_ID_MSMPEG4V3,
536 asf_write_stream_header,
537 asf_write_packet,
538 asf_write_trailer,
539 };
540 #endif //CONFIG_ENCODERS