suppressed mpeg demux mess - use now dynamic stream creation api
[libav.git] / libav / avienc.c
CommitLineData
de6d9b64
FB
1/*
2 * AVI 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 */
de6d9b64
FB
19#include "avformat.h"
20#include "avi.h"
21
22/*
23 * TODO:
24 * - fill all fields if non streamed (nb_frames for example)
25 */
26
27typedef struct AVIIndex {
28 unsigned char tag[4];
29 unsigned int flags, pos, len;
30 struct AVIIndex *next;
31} AVIIndex;
32
33typedef struct {
86bec9a1
J
34 offset_t movi_list, frames_hdr_all, frames_hdr_strm[MAX_STREAMS];
35 int audio_strm_length[MAX_STREAMS];
de6d9b64
FB
36 AVIIndex *first, *last;
37} AVIContext;
38
39offset_t start_tag(ByteIOContext *pb, char *tag)
40{
41 put_tag(pb, tag);
42 put_le32(pb, 0);
43 return url_ftell(pb);
44}
45
46void end_tag(ByteIOContext *pb, offset_t start)
47{
48 offset_t pos;
49
50 pos = url_ftell(pb);
51 url_fseek(pb, start - 4, SEEK_SET);
8be1c656 52 put_le32(pb, (UINT32)(pos - start));
de6d9b64
FB
53 url_fseek(pb, pos, SEEK_SET);
54}
55
56/* Note: when encoding, the first matching tag is used, so order is
57 important if multiple tags possible for a given codec. */
58CodecTag codec_bmp_tags[] = {
95c79a24
J
59 { CODEC_ID_H263, MKTAG('H', '2', '6', '3') },
60 { CODEC_ID_H263P, MKTAG('H', '2', '6', '3') },
de6d9b64
FB
61 { CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* intel h263 */
62 { CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') },
58f26ba9
FB
63 { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X') },
64 { CODEC_ID_MPEG4, MKTAG('d', 'i', 'v', 'x') },
65 { CODEC_ID_MPEG4, MKTAG(0x04, 0, 0, 0) }, /* some broken avi use this */
bb3debab
GV
66 { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '3') }, /* default signature when using MSMPEG4 */
67 { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') },
68 { CODEC_ID_MSMPEG4V2, MKTAG('M', 'P', '4', '2') },
69 { CODEC_ID_MSMPEG4V1, MKTAG('M', 'P', '4', '1') },
de6d9b64
FB
70 { 0, 0 },
71};
72
a266644f 73unsigned int codec_get_tag(const CodecTag *tags, int id)
de6d9b64
FB
74{
75 while (tags->id != 0) {
76 if (tags->id == id)
77 return tags->tag;
78 tags++;
79 }
80 return 0;
81}
82
a266644f 83int codec_get_id(const CodecTag *tags, unsigned int tag)
de6d9b64
FB
84{
85 while (tags->id != 0) {
86 if (tags->tag == tag)
87 return tags->id;
88 tags++;
89 }
90 return 0;
91}
92
93unsigned int codec_get_bmp_tag(int id)
94{
95 return codec_get_tag(codec_bmp_tags, id);
96}
97
98/* BITMAPINFOHEADER header */
502d105f 99void put_bmp_header(ByteIOContext *pb, AVCodecContext *enc, CodecTag *tags)
de6d9b64
FB
100{
101 put_le32(pb, 40); /* size */
102 put_le32(pb, enc->width);
103 put_le32(pb, enc->height);
104 put_le16(pb, 1); /* planes */
105 put_le16(pb, 24); /* depth */
106 /* compression type */
502d105f 107 put_le32(pb, codec_get_tag(tags, enc->codec_id));
de6d9b64
FB
108 put_le32(pb, enc->width * enc->height * 3);
109 put_le32(pb, 0);
110 put_le32(pb, 0);
111 put_le32(pb, 0);
112 put_le32(pb, 0);
113}
114
86bec9a1
J
115void parse_specific_params(AVCodecContext *stream, int *au_byterate, int *au_ssize, int *au_scale)
116{
117 switch(stream->codec_id) {
118 case CODEC_ID_PCM_S16LE:
119 *au_scale = *au_ssize = 2*stream->channels;
120 *au_byterate = *au_ssize * stream->sample_rate;
121 break;
122 case CODEC_ID_PCM_U8:
123 case CODEC_ID_PCM_ALAW:
124 case CODEC_ID_PCM_MULAW:
125 *au_scale = *au_ssize = stream->channels;
126 *au_byterate = *au_ssize * stream->sample_rate;
127 break;
128 case CODEC_ID_MP2:
129 *au_ssize = 1;
130 *au_scale = 1;
131 *au_byterate = stream->bit_rate / 8;
5798368b
J
132 case CODEC_ID_MP3LAME:
133 *au_ssize = 1;
134 *au_scale = 1;
135 *au_byterate = stream->bit_rate / 8;
86bec9a1
J
136 default:
137 *au_ssize = 1;
138 *au_scale = 1;
139 *au_byterate = stream->bit_rate / 8;
140 break;
141 }
142}
143
de6d9b64
FB
144static int avi_write_header(AVFormatContext *s)
145{
146 AVIContext *avi;
147 ByteIOContext *pb = &s->pb;
86bec9a1 148 int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale;
de6d9b64
FB
149 AVCodecContext *stream, *video_enc;
150 offset_t list1, list2, strh, strf;
151
1ea4f593 152 avi = av_malloc(sizeof(AVIContext));
de6d9b64
FB
153 if (!avi)
154 return -1;
155 memset(avi, 0, sizeof(AVIContext));
156 s->priv_data = avi;
157
158 put_tag(pb, "RIFF");
159 put_le32(pb, 0); /* file length */
160 put_tag(pb, "AVI ");
161
162 /* header list */
163 list1 = start_tag(pb, "LIST");
164 put_tag(pb, "hdrl");
165
166 /* avi header */
167 put_tag(pb, "avih");
168 put_le32(pb, 14 * 4);
169 bitrate = 0;
170
171 video_enc = NULL;
172 for(n=0;n<s->nb_streams;n++) {
173 stream = &s->streams[n]->codec;
174 bitrate += stream->bit_rate;
175 if (stream->codec_type == CODEC_TYPE_VIDEO)
176 video_enc = stream;
177 }
178
179 if (!video_enc) {
1ea4f593 180 av_free(avi);
de6d9b64
FB
181 return -1;
182 }
183 nb_frames = 0;
184
8be1c656 185 put_le32(pb, (UINT32)(INT64_C(1000000) * FRAME_RATE_BASE / video_enc->frame_rate));
de6d9b64
FB
186 put_le32(pb, bitrate / 8); /* XXX: not quite exact */
187 put_le32(pb, 0); /* padding */
188 put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */
86bec9a1 189 avi->frames_hdr_all = url_ftell(pb); /* remember this offset to fill later */
de6d9b64
FB
190 put_le32(pb, nb_frames); /* nb frames, filled later */
191 put_le32(pb, 0); /* initial frame */
192 put_le32(pb, s->nb_streams); /* nb streams */
193 put_le32(pb, 1024 * 1024); /* suggested buffer size */
194 put_le32(pb, video_enc->width);
195 put_le32(pb, video_enc->height);
196 put_le32(pb, 0); /* reserved */
197 put_le32(pb, 0); /* reserved */
198 put_le32(pb, 0); /* reserved */
199 put_le32(pb, 0); /* reserved */
200
201 /* stream list */
202 for(i=0;i<n;i++) {
203 list2 = start_tag(pb, "LIST");
204 put_tag(pb, "strl");
205
206 stream = &s->streams[i]->codec;
207
208 /* stream generic header */
209 strh = start_tag(pb, "strh");
210 switch(stream->codec_type) {
211 case CODEC_TYPE_VIDEO:
212 put_tag(pb, "vids");
213 put_le32(pb, codec_get_bmp_tag(stream->codec_id));
214 put_le32(pb, 0); /* flags */
215 put_le16(pb, 0); /* priority */
216 put_le16(pb, 0); /* language */
217 put_le32(pb, 0); /* initial frame */
218 put_le32(pb, 1000); /* scale */
219 put_le32(pb, (1000 * stream->frame_rate) / FRAME_RATE_BASE); /* rate */
220 put_le32(pb, 0); /* start */
86bec9a1 221 avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */
de6d9b64
FB
222 put_le32(pb, nb_frames); /* length, XXX: fill later */
223 put_le32(pb, 1024 * 1024); /* suggested buffer size */
86bec9a1 224 put_le32(pb, -1); /* quality */
de6d9b64
FB
225 put_le32(pb, stream->width * stream->height * 3); /* sample size */
226 put_le16(pb, 0);
227 put_le16(pb, 0);
228 put_le16(pb, stream->width);
229 put_le16(pb, stream->height);
230 break;
231 case CODEC_TYPE_AUDIO:
232 put_tag(pb, "auds");
86bec9a1 233 put_le32(pb, 1); /* tag */
de6d9b64
FB
234 put_le32(pb, 0); /* flags */
235 put_le16(pb, 0); /* priority */
236 put_le16(pb, 0); /* language */
237 put_le32(pb, 0); /* initial frame */
86bec9a1
J
238 parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
239 put_le32(pb, au_scale); /* scale */
240 put_le32(pb, au_byterate); /* rate */
de6d9b64 241 put_le32(pb, 0); /* start */
86bec9a1 242 avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */
de6d9b64
FB
243 put_le32(pb, 0); /* length, XXX: filled later */
244 put_le32(pb, 12 * 1024); /* suggested buffer size */
245 put_le32(pb, -1); /* quality */
86bec9a1 246 put_le32(pb, au_ssize); /* sample size */
de6d9b64
FB
247 put_le32(pb, 0);
248 put_le32(pb, 0);
249 break;
53cafac0
PG
250 default:
251 abort();
de6d9b64
FB
252 }
253 end_tag(pb, strh);
254
255 strf = start_tag(pb, "strf");
256 switch(stream->codec_type) {
257 case CODEC_TYPE_VIDEO:
502d105f 258 put_bmp_header(pb, stream, codec_bmp_tags);
de6d9b64
FB
259 break;
260 case CODEC_TYPE_AUDIO:
46a3d068 261 if (put_wav_header(pb, stream) < 0) {
1ea4f593 262 av_free(avi);
46a3d068
FB
263 return -1;
264 }
de6d9b64 265 break;
53cafac0
PG
266 default:
267 abort();
de6d9b64
FB
268 }
269 end_tag(pb, strf);
270 end_tag(pb, list2);
271 }
272
273 end_tag(pb, list1);
274
275 avi->movi_list = start_tag(pb, "LIST");
276 avi->first = NULL;
277 avi->last = NULL;
278 put_tag(pb, "movi");
279
280 put_flush_packet(pb);
281
282 return 0;
283}
284
285static int avi_write_packet(AVFormatContext *s, int stream_index,
10bb7023 286 UINT8 *buf, int size, int force_pts)
de6d9b64
FB
287{
288 AVIContext *avi = s->priv_data;
289 ByteIOContext *pb = &s->pb;
290 AVIIndex *idx;
291 unsigned char tag[5];
292 unsigned int flags;
293 AVCodecContext *enc;
294
295 enc = &s->streams[stream_index]->codec;
296
297 tag[0] = '0';
298 tag[1] = '0' + stream_index;
299 if (enc->codec_type == CODEC_TYPE_VIDEO) {
300 tag[2] = 'd';
301 tag[3] = 'c';
302 flags = enc->key_frame ? 0x10 : 0x00;
303 } else {
304 tag[2] = 'w';
305 tag[3] = 'b';
306 flags = 0x10;
307 }
86bec9a1
J
308 if (enc->codec_type == CODEC_TYPE_AUDIO)
309 avi->audio_strm_length[stream_index] += size;
de6d9b64
FB
310
311 if (!url_is_streamed(&s->pb)) {
1ea4f593 312 idx = av_malloc(sizeof(AVIIndex));
de6d9b64
FB
313 memcpy(idx->tag, tag, 4);
314 idx->flags = flags;
315 idx->pos = url_ftell(pb) - avi->movi_list;
316 idx->len = size;
317 idx->next = NULL;
318 if (!avi->last)
319 avi->first = idx;
320 else
321 avi->last->next = idx;
322 avi->last = idx;
323 }
324
325 put_buffer(pb, tag, 4);
326 put_le32(pb, size);
327 put_buffer(pb, buf, size);
328 if (size & 1)
329 put_byte(pb, 0);
330
331 put_flush_packet(pb);
332 return 0;
333}
334
335static int avi_write_trailer(AVFormatContext *s)
336{
337 ByteIOContext *pb = &s->pb;
338 AVIContext *avi = s->priv_data;
339 offset_t file_size, idx_chunk;
86bec9a1
J
340 int n, nb_frames, au_byterate, au_ssize, au_scale;
341 AVCodecContext *stream;
de6d9b64
FB
342 AVIIndex *idx;
343
344 if (!url_is_streamed(&s->pb)) {
345 end_tag(pb, avi->movi_list);
346
347 idx_chunk = start_tag(pb, "idx1");
348 idx = avi->first;
349 while (idx != NULL) {
350 put_buffer(pb, idx->tag, 4);
351 put_le32(pb, idx->flags);
352 put_le32(pb, idx->pos);
353 put_le32(pb, idx->len);
354 idx = idx->next;
355 }
356 end_tag(pb, idx_chunk);
357
358 /* update file size */
359 file_size = url_ftell(pb);
360 url_fseek(pb, 4, SEEK_SET);
8be1c656 361 put_le32(pb, (UINT32)(file_size - 8));
86bec9a1
J
362
363 /* Fill in frame/sample counters */
364 nb_frames = 0;
365 for(n=0;n<s->nb_streams;n++) {
366 if (avi->frames_hdr_strm[n] != 0) {
367 stream = &s->streams[n]->codec;
368 url_fseek(pb, avi->frames_hdr_strm[n], SEEK_SET);
369 if (stream->codec_type == CODEC_TYPE_VIDEO) {
370 put_le32(pb, stream->frame_number);
371 if (nb_frames < stream->frame_number)
372 nb_frames = stream->frame_number;
373 } else {
5798368b 374 if (stream->codec_id == CODEC_ID_MP2 || stream->codec_id == CODEC_ID_MP3LAME) {
86bec9a1
J
375 put_le32(pb, stream->frame_number);
376 nb_frames += stream->frame_number;
377 } else {
378 parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
379 put_le32(pb, avi->audio_strm_length[n] / au_ssize);
380 }
381 }
382 }
383 }
384 if (avi->frames_hdr_all != 0) {
385 url_fseek(pb, avi->frames_hdr_all, SEEK_SET);
386 put_le32(pb, nb_frames);
387 }
de6d9b64
FB
388 url_fseek(pb, file_size, SEEK_SET);
389 }
390 put_flush_packet(pb);
391
1ea4f593 392 av_free(avi);
de6d9b64
FB
393 return 0;
394}
395
396AVFormat avi_format = {
397 "avi",
398 "avi format",
399 "video/x-msvideo",
400 "avi",
401 CODEC_ID_MP2,
402 CODEC_ID_MSMPEG4,
403 avi_write_header,
404 avi_write_packet,
405 avi_write_trailer,
406
407 avi_read_header,
408 avi_read_packet,
409 avi_read_close,
410};