10l (bytes_left() -> url_feof())
[libav.git] / libavformat / movenc.c
CommitLineData
1cb5f7fd
MN
1/*
2 * MOV, 3GP, MP4 encoder.
3 * Copyright (c) 2003 Thomas Raivio.
69dde1ad 4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>.
1cb5f7fd
MN
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include "avformat.h"
f578f938 21#include "avi.h"
1cb5f7fd 22#include "avio.h"
1cb5f7fd 23
6e6d6dc0
MN
24#undef NDEBUG
25#include <assert.h>
26
1cb5f7fd
MN
27#define MOV_INDEX_CLUSTER_SIZE 16384
28#define globalTimescale 1000
29
69dde1ad
GB
30#define MODE_MP4 0
31#define MODE_MOV 1
32#define MODE_3GP 2
33
1cb5f7fd 34typedef struct MOVIentry {
e45ccf79
GB
35 unsigned int flags, pos, size;
36 unsigned int samplesInChunk;
f578f938 37 char key_frame;
1cb5f7fd
MN
38 unsigned int entries;
39} MOVIentry;
40
41typedef struct MOVIndex {
69dde1ad 42 int mode;
1cb5f7fd 43 int entry;
1cb5f7fd 44 int mdat_size;
1cb5f7fd
MN
45 int ents_allocated;
46 long timescale;
47 long time;
f578f938 48 long trackDuration;
e45ccf79
GB
49 long sampleCount;
50 long sampleDuration;
f578f938 51 int hasKeyframes;
1cb5f7fd
MN
52 int trackID;
53 AVCodecContext *enc;
54
55 int vosLen;
6e6d6dc0 56 uint8_t *vosData;
1cb5f7fd
MN
57 MOVIentry** cluster;
58} MOVTrack;
59
60typedef struct {
69dde1ad 61 int mode;
1cb5f7fd
MN
62 long time;
63 int nb_streams;
f578f938
TR
64 int mdat_written;
65 offset_t mdat_pos;
1cb5f7fd
MN
66 long timescale;
67 MOVTrack tracks[MAX_STREAMS];
68} MOVContext;
69
e45ccf79
GB
70static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track);
71
6e6d6dc0
MN
72//FIXME supprt 64bit varaint with wide placeholders
73static int updateSize (ByteIOContext *pb, int pos)
1cb5f7fd
MN
74{
75 long curpos = url_ftell(pb);
76 url_fseek(pb, pos, SEEK_SET);
6e6d6dc0 77 put_be32(pb, curpos - pos); /* rewrite size */
1cb5f7fd 78 url_fseek(pb, curpos, SEEK_SET);
6e6d6dc0
MN
79
80 return curpos - pos;
1cb5f7fd
MN
81}
82
e45ccf79 83/* Chunk offset atom */
6e6d6dc0 84static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
85{
86 int i;
f578f938
TR
87 int pos = url_ftell(pb);
88 put_be32(pb, 0); /* size */
1cb5f7fd
MN
89 put_tag(pb, "stco");
90 put_be32(pb, 0); /* version & flags */
91 put_be32(pb, track->entry); /* entry count */
92 for (i=0; i<track->entry; i++) {
93 int cl = i / MOV_INDEX_CLUSTER_SIZE;
94 int id = i % MOV_INDEX_CLUSTER_SIZE;
95 put_be32(pb, track->cluster[cl][id].pos);
96 }
f578f938 97 return updateSize (pb, pos);
1cb5f7fd
MN
98}
99
e45ccf79 100/* Sample size atom */
6e6d6dc0 101static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 102{
f578f938 103 int equalChunks = 1;
e45ccf79 104 int i, j, entries = 0, tst = -1, oldtst = -1;
1cb5f7fd 105
f578f938
TR
106 int pos = url_ftell(pb);
107 put_be32(pb, 0); /* size */
1cb5f7fd
MN
108 put_tag(pb, "stsz");
109 put_be32(pb, 0); /* version & flags */
110
f578f938
TR
111 for (i=0; i<track->entry; i++) {
112 int cl = i / MOV_INDEX_CLUSTER_SIZE;
113 int id = i % MOV_INDEX_CLUSTER_SIZE;
e45ccf79
GB
114 tst = track->cluster[cl][id].size/track->cluster[cl][id].entries;
115 if(oldtst != -1 && tst != oldtst) {
116 equalChunks = 0;
f578f938
TR
117 }
118 oldtst = tst;
e45ccf79 119 entries += track->cluster[cl][id].entries;
f578f938 120 }
e45ccf79
GB
121 if (equalChunks) {
122 int sSize = track->cluster[0][0].size/track->cluster[0][0].entries;
f578f938 123 put_be32(pb, sSize); // sample size
e45ccf79 124 put_be32(pb, entries); // sample count
1cb5f7fd 125 }
f578f938
TR
126 else {
127 put_be32(pb, 0); // sample size
e45ccf79 128 put_be32(pb, entries); // sample count
f578f938 129 for (i=0; i<track->entry; i++) {
1cb5f7fd
MN
130 int cl = i / MOV_INDEX_CLUSTER_SIZE;
131 int id = i % MOV_INDEX_CLUSTER_SIZE;
e45ccf79
GB
132 for ( j=0; j<track->cluster[cl][id].entries; j++) {
133 put_be32(pb, track->cluster[cl][id].size /
134 track->cluster[cl][id].entries);
135 }
1cb5f7fd
MN
136 }
137 }
f578f938 138 return updateSize (pb, pos);
1cb5f7fd
MN
139}
140
e45ccf79 141/* Sample to chunk atom */
6e6d6dc0 142static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 143{
f578f938
TR
144 int index = 0, oldval = -1, i, entryPos, curpos;
145
146 int pos = url_ftell(pb);
147 put_be32(pb, 0); /* size */
1cb5f7fd
MN
148 put_tag(pb, "stsc");
149 put_be32(pb, 0); // version & flags
f578f938
TR
150 entryPos = url_ftell(pb);
151 put_be32(pb, track->entry); // entry count
152 for (i=0; i<track->entry; i++) {
153 int cl = i / MOV_INDEX_CLUSTER_SIZE;
154 int id = i % MOV_INDEX_CLUSTER_SIZE;
e45ccf79 155 if(oldval != track->cluster[cl][id].samplesInChunk)
f578f938 156 {
1cb5f7fd 157 put_be32(pb, i+1); // first chunk
e45ccf79 158 put_be32(pb, track->cluster[cl][id].samplesInChunk); // samples per chunk
1cb5f7fd 159 put_be32(pb, 0x1); // sample description index
e45ccf79 160 oldval = track->cluster[cl][id].samplesInChunk;
f578f938 161 index++;
1cb5f7fd
MN
162 }
163 }
f578f938
TR
164 curpos = url_ftell(pb);
165 url_fseek(pb, entryPos, SEEK_SET);
166 put_be32(pb, index); // rewrite size
167 url_fseek(pb, curpos, SEEK_SET);
1cb5f7fd 168
f578f938 169 return updateSize (pb, pos);
1cb5f7fd
MN
170}
171
e45ccf79 172/* Sync sample atom */
f578f938 173static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 174{
f578f938
TR
175 long curpos;
176 int i, index = 0, entryPos;
177 int pos = url_ftell(pb);
178 put_be32(pb, 0); // size
1cb5f7fd 179 put_tag(pb, "stss");
f578f938
TR
180 put_be32(pb, 0); // version & flags
181 entryPos = url_ftell(pb);
182 put_be32(pb, track->entry); // entry count
183 for (i=0; i<track->entry; i++) {
184 int cl = i / MOV_INDEX_CLUSTER_SIZE;
185 int id = i % MOV_INDEX_CLUSTER_SIZE;
186 if(track->cluster[cl][id].key_frame == 1) {
187 put_be32(pb, i+1);
188 index++;
189 }
190 }
191 curpos = url_ftell(pb);
192 url_fseek(pb, entryPos, SEEK_SET);
193 put_be32(pb, index); // rewrite size
194 url_fseek(pb, curpos, SEEK_SET);
195 return updateSize (pb, pos);
1cb5f7fd
MN
196}
197
6e6d6dc0 198static int mov_write_damr_tag(ByteIOContext *pb)
1cb5f7fd
MN
199{
200 put_be32(pb, 0x11); /* size */
201 put_tag(pb, "damr");
202 put_tag(pb, "FFMP");
203 put_byte(pb, 0);
f578f938
TR
204
205 put_be16(pb, 0x80); /* Mode set (all modes for AMR_NB) */
206 put_be16(pb, 0xa); /* Mode change period (no restriction) */
207 //put_be16(pb, 0x81ff); /* Mode set (all modes for AMR_NB) */
208 //put_be16(pb, 1); /* Mode change period (no restriction) */
1cb5f7fd
MN
209 return 0x11;
210}
211
69dde1ad
GB
212static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack* track)
213{
214 int pos = url_ftell(pb);
215
216 put_be32(pb, 0); /* size */
217 put_tag(pb, "wave");
218
219 put_be32(pb, 12); /* size */
220 put_tag(pb, "frma");
221 put_tag(pb, "mp4a");
222
223 put_be32(pb, 12); /* size */
224 put_tag(pb, "mp4a");
225 put_be32(pb, 0);
226
227 mov_write_esds_tag(pb, track);
228
229 put_be32(pb, 12); /* size */
230 put_tag(pb, "srcq");
231 put_be32(pb, 0x40);
232
233 put_be32(pb, 8); /* size */
234 put_be32(pb, 0); /* null tag */
235
236 return updateSize (pb, pos);
237}
238
f578f938 239static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 240{
6e6d6dc0 241 int pos = url_ftell(pb);
1cb5f7fd 242 put_be32(pb, 0); /* size */
f578f938
TR
243
244 if(track->enc->codec_id == CODEC_ID_PCM_MULAW)
245 put_tag(pb, "ulaw");
246 else if(track->enc->codec_id == CODEC_ID_PCM_ALAW)
247 put_tag(pb, "alaw");
248 else if(track->enc->codec_id == CODEC_ID_ADPCM_IMA_QT)
249 put_tag(pb, "ima4");
250 else if(track->enc->codec_id == CODEC_ID_MACE3)
251 put_tag(pb, "MAC3");
252 else if(track->enc->codec_id == CODEC_ID_MACE6)
253 put_tag(pb, "MAC6");
254 else if(track->enc->codec_id == CODEC_ID_AAC)
255 put_tag(pb, "mp4a");
256 else if(track->enc->codec_id == CODEC_ID_AMR_NB)
257 put_tag(pb, "samr");
ca20f118
RS
258 else if(track->enc->codec_id == CODEC_ID_PCM_S16BE)
259 put_tag(pb, "twos");
260 else if(track->enc->codec_id == CODEC_ID_PCM_S16LE)
261 put_tag(pb, "sowt");
f578f938
TR
262 else
263 put_tag(pb, " ");
264
1cb5f7fd
MN
265 put_be32(pb, 0); /* Reserved */
266 put_be16(pb, 0); /* Reserved */
267 put_be16(pb, 1); /* Data-reference index, XXX == 1 */
69dde1ad 268
e45ccf79 269 /* SoundDescription */
69dde1ad
GB
270 if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC)
271 put_be16(pb, 1); /* Version 1 */
272 else
273 put_be16(pb, 0); /* Version 0 */
e45ccf79 274 put_be16(pb, 0); /* Revision level */
1cb5f7fd
MN
275 put_be32(pb, 0); /* Reserved */
276
f578f938
TR
277 put_be16(pb, track->enc->channels); /* Number of channels */
278 /* TODO: Currently hard-coded to 16-bit, there doesn't seem
e45ccf79 279 to be a good way to get number of bits of audio */
1cb5f7fd 280 put_be16(pb, 0x10); /* Reserved */
9a4d9388
RS
281 put_be16(pb, 0); /* compression ID (= 0) */
282 put_be16(pb, 0); /* packet size (= 0) */
1cb5f7fd
MN
283 put_be16(pb, track->timescale); /* Time scale */
284 put_be16(pb, 0); /* Reserved */
285
69dde1ad
GB
286 if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC)
287 {
288 /* SoundDescription V1 extended info */
289 put_be32(pb, track->enc->frame_size); /* Samples per packet */
290 put_be32(pb, 1536); /* Bytes per packet */
291 put_be32(pb, 2); /* Bytes per frame */
292 put_be32(pb, 2); /* Bytes per sample */
293 }
294
295 if(track->enc->codec_id == CODEC_ID_AAC) {
296 if( track->mode == MODE_MOV ) mov_write_wave_tag(pb, track);
297 else mov_write_esds_tag(pb, track);
298 }
f578f938
TR
299 if(track->enc->codec_id == CODEC_ID_AMR_NB)
300 mov_write_damr_tag(pb);
6e6d6dc0 301 return updateSize (pb, pos);
1cb5f7fd
MN
302}
303
6e6d6dc0 304static int mov_write_d263_tag(ByteIOContext *pb)
1cb5f7fd
MN
305{
306 put_be32(pb, 0xf); /* size */
307 put_tag(pb, "d263");
308 put_tag(pb, "FFMP");
309 put_be16(pb, 0x0a);
310 put_byte(pb, 0);
311 return 0xf;
312}
313
f578f938
TR
314/* TODO: No idea about these values */
315static int mov_write_svq3_tag(ByteIOContext *pb)
1cb5f7fd 316{
f578f938
TR
317 put_be32(pb, 0x15);
318 put_tag(pb, "SMI ");
319 put_tag(pb, "SEQH");
320 put_be32(pb, 0x5);
321 put_be32(pb, 0xe2c0211d);
322 put_be32(pb, 0xc0000000);
323 put_byte(pb, 0);
324 return 0x15;
1cb5f7fd
MN
325}
326
e45ccf79
GB
327static unsigned int descrLength(unsigned int len)
328{
329 if (len < 0x00000080)
330 return 2 + len;
331 else if (len < 0x00004000)
332 return 3 + len;
333 else if(len < 0x00200000)
334 return 4 + len;
335 else
336 return 5 + len;
337}
338
339static void putDescr(ByteIOContext *pb, int tag, int size)
1cb5f7fd 340{
e45ccf79
GB
341 uint32_t len;
342 uint8_t vals[4];
343
344 len = size;
345 vals[3] = (uint8_t)(len & 0x7f);
346 len >>= 7;
347 vals[2] = (uint8_t)((len & 0x7f) | 0x80);
348 len >>= 7;
349 vals[1] = (uint8_t)((len & 0x7f) | 0x80);
350 len >>= 7;
351 vals[0] = (uint8_t)((len & 0x7f) | 0x80);
352
353 put_byte(pb, tag); // DescriptorTag
354
355 if (size < 0x00000080)
356 {
357 put_byte(pb, vals[3]);
358 }
359 else if (size < 0x00004000)
360 {
361 put_byte(pb, vals[2]);
362 put_byte(pb, vals[3]);
363 }
364 else if (size < 0x00200000)
365 {
366 put_byte(pb, vals[1]);
367 put_byte(pb, vals[2]);
368 put_byte(pb, vals[3]);
369 }
370 else if (size < 0x10000000)
371 {
372 put_byte(pb, vals[0]);
373 put_byte(pb, vals[1]);
374 put_byte(pb, vals[2]);
375 put_byte(pb, vals[3]);
376 }
1cb5f7fd
MN
377}
378
6e6d6dc0 379static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
1cb5f7fd 380{
e45ccf79
GB
381 int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;
382 int pos = url_ftell(pb);
383
384 put_be32(pb, 0); // size
1cb5f7fd 385 put_tag(pb, "esds");
e45ccf79 386 put_be32(pb, 0); // Version
1cb5f7fd 387
e45ccf79
GB
388 // ES descriptor
389 putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) +
390 descrLength(1));
391 put_be16(pb, 0x0001); // ID (= 1)
1cb5f7fd
MN
392 put_byte(pb, 0x00); // flags (= no flags)
393
e45ccf79
GB
394 // DecoderConfig descriptor
395 putDescr(pb, 0x04, 13 + decoderSpecificInfoLen);
396
397 if(track->enc->codec_id == CODEC_ID_AAC)
398 put_byte(pb, 0x40); // Object type indication
399 else if(track->enc->codec_id == CODEC_ID_MPEG4)
400 put_byte(pb, 0x20); // Object type indication (Visual 14496-2)
401
402 if(track->enc->codec_type == CODEC_TYPE_AUDIO)
403 put_byte(pb, 0x15); // flags (= Audiostream)
404 else
405 put_byte(pb, 0x11); // flags (= Visualstream)
406
1cb5f7fd
MN
407 put_byte(pb, 0x0); // Buffersize DB (24 bits)
408 put_be16(pb, 0x0dd2); // Buffersize DB
409
410 // TODO: find real values for these
411 put_be32(pb, 0x0002e918); // maxbitrate
412 put_be32(pb, 0x00017e6b); // avg bitrate
413
e45ccf79
GB
414 if (track->vosLen)
415 {
416 // DecoderSpecific info descriptor
417 putDescr(pb, 0x05, track->vosLen);
418 put_buffer(pb, track->vosData, track->vosLen);
419 }
420
421 // SL descriptor
4bfc029f 422 putDescr(pb, 0x06, 1);
1cb5f7fd 423 put_byte(pb, 0x02);
e45ccf79 424 return updateSize (pb, pos);
1cb5f7fd
MN
425}
426
f578f938 427static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 428{
6e6d6dc0 429 int pos = url_ftell(pb);
f578f938
TR
430 put_be32(pb, 0); /* size */
431 if(track->enc->codec_id == CODEC_ID_SVQ1)
432 put_tag(pb, "SVQ1");
433 else if(track->enc->codec_id == CODEC_ID_SVQ3)
434 put_tag(pb, "SVQ3");
435 else if(track->enc->codec_id == CODEC_ID_MPEG4)
436 put_tag(pb, "mp4v");
437 else if(track->enc->codec_id == CODEC_ID_H263)
438 put_tag(pb, "s263");
ca20f118
RS
439 else if(track->enc->codec_id == CODEC_ID_DVVIDEO)
440 put_tag(pb, "dvc ");
f578f938
TR
441 else
442 put_tag(pb, " "); /* Unknown tag */
6e6d6dc0 443
f578f938
TR
444 put_be32(pb, 0); /* Reserved */
445 put_be16(pb, 0); /* Reserved */
446 put_be16(pb, 1); /* Data-reference index */
447
448 put_be32(pb, 0); /* Reserved (= 02000c) */
449 put_be32(pb, 0); /* Reserved ("SVis")*/
450 put_be32(pb, 0); /* Reserved */
451 put_be32(pb, 0); /* Reserved (400)*/
452 put_be16(pb, track->enc->width); /* Video width */
453 put_be16(pb, track->enc->height); /* Video height */
454 put_be32(pb, 0x00480000); /* Reserved */
455 put_be32(pb, 0x00480000); /* Reserved */
9a4d9388
RS
456 put_be32(pb, 0); /* Data size (= 0) */
457 put_be16(pb, 1); /* Frame count (= 1) */
458
f578f938
TR
459 put_be32(pb, 0); /* Reserved */
460 put_be32(pb, 0); /* Reserved */
461 put_be32(pb, 0); /* Reserved */
462 put_be32(pb, 0); /* Reserved */
463 put_be32(pb, 0); /* Reserved */
464 put_be32(pb, 0); /* Reserved */
f578f938
TR
465 put_be32(pb, 0); /* Reserved */
466 put_be32(pb, 0); /* Reserved */
9a4d9388 467
f578f938
TR
468 put_be16(pb, 0x18); /* Reserved */
469 put_be16(pb, 0xffff); /* Reserved */
470 if(track->enc->codec_id == CODEC_ID_MPEG4)
471 mov_write_esds_tag(pb, track);
472 else if(track->enc->codec_id == CODEC_ID_H263)
473 mov_write_d263_tag(pb);
474 else if(track->enc->codec_id == CODEC_ID_SVQ3)
475 mov_write_svq3_tag(pb);
476
477 return updateSize (pb, pos);
1cb5f7fd
MN
478}
479
6e6d6dc0 480static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 481{
6e6d6dc0 482 int pos = url_ftell(pb);
1cb5f7fd
MN
483 put_be32(pb, 0); /* size */
484 put_tag(pb, "stsd");
485 put_be32(pb, 0); /* version & flags */
486 put_be32(pb, 1); /* entry count */
f578f938
TR
487 if (track->enc->codec_type == CODEC_TYPE_VIDEO)
488 mov_write_video_tag(pb, track);
489 else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
490 mov_write_audio_tag(pb, track);
6e6d6dc0 491 return updateSize(pb, pos);
1cb5f7fd
MN
492}
493
f578f938 494/* TODO?: Currently all samples/frames seem to have same duration */
e45ccf79 495/* Time to sample atom */
6e6d6dc0 496static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
497{
498 put_be32(pb, 0x18); /* size */
499 put_tag(pb, "stts");
500 put_be32(pb, 0); /* version & flags */
501 put_be32(pb, 1); /* entry count */
502
e45ccf79
GB
503 put_be32(pb, track->sampleCount); /* sample count */
504 put_be32(pb, track->sampleDuration); /* sample duration */
1cb5f7fd
MN
505 return 0x18;
506}
507
6e6d6dc0 508static int mov_write_dref_tag(ByteIOContext *pb)
1cb5f7fd
MN
509{
510 put_be32(pb, 28); /* size */
511 put_tag(pb, "dref");
512 put_be32(pb, 0); /* version & flags */
513 put_be32(pb, 1); /* entry count */
514
515 put_be32(pb, 0xc); /* size */
516 put_tag(pb, "url ");
517 put_be32(pb, 1); /* version & flags */
518
519 return 28;
520}
521
6e6d6dc0 522static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 523{
6e6d6dc0 524 int pos = url_ftell(pb);
1cb5f7fd
MN
525 put_be32(pb, 0); /* size */
526 put_tag(pb, "stbl");
6e6d6dc0
MN
527 mov_write_stsd_tag(pb, track);
528 mov_write_stts_tag(pb, track);
f578f938
TR
529 if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
530 track->hasKeyframes)
531 mov_write_stss_tag(pb, track);
6e6d6dc0
MN
532 mov_write_stsc_tag(pb, track);
533 mov_write_stsz_tag(pb, track);
534 mov_write_stco_tag(pb, track);
535 return updateSize(pb, pos);
1cb5f7fd
MN
536}
537
6e6d6dc0 538static int mov_write_dinf_tag(ByteIOContext *pb)
1cb5f7fd 539{
6e6d6dc0 540 int pos = url_ftell(pb);
1cb5f7fd
MN
541 put_be32(pb, 0); /* size */
542 put_tag(pb, "dinf");
6e6d6dc0
MN
543 mov_write_dref_tag(pb);
544 return updateSize(pb, pos);
1cb5f7fd
MN
545}
546
6e6d6dc0 547static int mov_write_smhd_tag(ByteIOContext *pb)
1cb5f7fd
MN
548{
549 put_be32(pb, 16); /* size */
550 put_tag(pb, "smhd");
551 put_be32(pb, 0); /* version & flags */
552 put_be16(pb, 0); /* reserved (balance, normally = 0) */
553 put_be16(pb, 0); /* reserved */
554 return 16;
555}
556
6e6d6dc0 557static int mov_write_vmhd_tag(ByteIOContext *pb)
1cb5f7fd
MN
558{
559 put_be32(pb, 0x14); /* size (always 0x14) */
560 put_tag(pb, "vmhd");
561 put_be32(pb, 0x01); /* version & flags */
562 put_be64(pb, 0); /* reserved (graphics mode = copy) */
563 return 0x14;
564}
565
6e6d6dc0 566static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 567{
9a4d9388 568 char *descr, *hdlr, *hdlr_type;
f578f938 569 int pos = url_ftell(pb);
9a4d9388
RS
570
571 if (!track) { /* no media --> data handler */
572 hdlr = "dhlr";
573 hdlr_type = "url ";
574 descr = "DataHandler";
575 } else {
576 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
577 if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
578 hdlr_type = "vide";
579 descr = "VideoHandler";
580 } else {
581 hdlr_type = "soun";
582 descr = "SoundHandler";
583 }
584 }
585
f578f938 586 put_be32(pb, 0); /* size */
1cb5f7fd
MN
587 put_tag(pb, "hdlr");
588 put_be32(pb, 0); /* Version & flags */
906b578f 589 put_buffer(pb, hdlr, 4); /* handler */
9a4d9388 590 put_tag(pb, hdlr_type); /* handler type */
f578f938
TR
591 put_be32(pb ,0); /* reserved */
592 put_be32(pb ,0); /* reserved */
593 put_be32(pb ,0); /* reserved */
9a4d9388
RS
594 put_byte(pb, strlen(descr)); /* string counter */
595 put_buffer(pb, descr, strlen(descr)); /* handler description */
596 return updateSize(pb, pos);
597}
598
599static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track)
600{
601 int pos = url_ftell(pb);
602 put_be32(pb, 0); /* size */
603 put_tag(pb, "minf");
1cb5f7fd 604 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
9a4d9388 605 mov_write_vmhd_tag(pb);
1cb5f7fd 606 else
9a4d9388
RS
607 mov_write_smhd_tag(pb);
608 if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */
609 mov_write_hdlr_tag(pb, NULL);
610 mov_write_dinf_tag(pb);
611 mov_write_stbl_tag(pb, track);
f578f938 612 return updateSize(pb, pos);
1cb5f7fd
MN
613}
614
6e6d6dc0 615static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
616{
617 put_be32(pb, 32); /* size */
618 put_tag(pb, "mdhd");
619 put_be32(pb, 0); /* Version & flags */
620 put_be32(pb, track->time); /* creation time */
621 put_be32(pb, track->time); /* modification time */
e45ccf79
GB
622 put_be32(pb, track->timescale); /* time scale (sample rate for audio) */
623 put_be32(pb, track->trackDuration); /* duration */
1cb5f7fd
MN
624 put_be16(pb, 0); /* language, 0 = english */
625 put_be16(pb, 0); /* reserved (quality) */
626 return 32;
627}
628
6e6d6dc0 629static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 630{
6e6d6dc0 631 int pos = url_ftell(pb);
1cb5f7fd
MN
632 put_be32(pb, 0); /* size */
633 put_tag(pb, "mdia");
6e6d6dc0
MN
634 mov_write_mdhd_tag(pb, track);
635 mov_write_hdlr_tag(pb, track);
636 mov_write_minf_tag(pb, track);
637 return updateSize(pb, pos);
1cb5f7fd
MN
638}
639
6e6d6dc0 640static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 641{
f578f938 642 int64_t maxTrackLenTemp;
1cb5f7fd
MN
643 put_be32(pb, 0x5c); /* size (always 0x5c) */
644 put_tag(pb, "tkhd");
f578f938 645 put_be32(pb, 0xf); /* version & flags (track enabled) */
1cb5f7fd
MN
646 put_be32(pb, track->time); /* creation time */
647 put_be32(pb, track->time); /* modification time */
648 put_be32(pb, track->trackID); /* track-id */
649 put_be32(pb, 0); /* reserved */
f578f938
TR
650 maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)track->trackDuration)/(int64_t)track->timescale;
651 put_be32(pb, (long)maxTrackLenTemp); /* duration */
1cb5f7fd
MN
652
653 put_be32(pb, 0); /* reserved */
654 put_be32(pb, 0); /* reserved */
655 put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
656 /* Volume, only for audio */
657 if(track->enc->codec_type == CODEC_TYPE_AUDIO)
658 put_be16(pb, 0x0100);
659 else
660 put_be16(pb, 0);
661 put_be16(pb, 0); /* reserved */
662
663 /* Matrix structure */
664 put_be32(pb, 0x00010000); /* reserved */
665 put_be32(pb, 0x0); /* reserved */
666 put_be32(pb, 0x0); /* reserved */
667 put_be32(pb, 0x0); /* reserved */
668 put_be32(pb, 0x00010000); /* reserved */
669 put_be32(pb, 0x0); /* reserved */
670 put_be32(pb, 0x0); /* reserved */
671 put_be32(pb, 0x0); /* reserved */
672 put_be32(pb, 0x40000000); /* reserved */
673
674 /* Track width and height, for visual only */
675 if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
69dde1ad
GB
676 double sample_aspect_ratio = av_q2d(track->enc->sample_aspect_ratio);
677 if( !sample_aspect_ratio ) sample_aspect_ratio = 1;
678 put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000);
f578f938 679 put_be32(pb, track->enc->height*0x10000);
1cb5f7fd
MN
680 }
681 else {
682 put_be32(pb, 0);
683 put_be32(pb, 0);
684 }
685 return 0x5c;
686}
687
6e6d6dc0 688static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 689{
6e6d6dc0 690 int pos = url_ftell(pb);
1cb5f7fd
MN
691 put_be32(pb, 0); /* size */
692 put_tag(pb, "trak");
6e6d6dc0
MN
693 mov_write_tkhd_tag(pb, track);
694 mov_write_mdia_tag(pb, track);
695 return updateSize(pb, pos);
1cb5f7fd
MN
696}
697
698/* TODO: Not sorted out, but not necessary either */
6e6d6dc0 699static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd
MN
700{
701 put_be32(pb, 0x15); /* size */
702 put_tag(pb, "iods");
703 put_be32(pb, 0); /* version & flags */
704 put_be16(pb, 0x1007);
705 put_byte(pb, 0);
706 put_be16(pb, 0x4fff);
707 put_be16(pb, 0xfffe);
708 put_be16(pb, 0x01ff);
709 return 0x15;
710}
711
6e6d6dc0 712static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd
MN
713{
714 int maxTrackID = 1, maxTrackLen = 0, i;
f578f938 715 int64_t maxTrackLenTemp;
1cb5f7fd
MN
716
717 put_be32(pb, 0x6c); /* size (always 0x6c) */
718 put_tag(pb, "mvhd");
719 put_be32(pb, 0); /* version & flags */
720 put_be32(pb, mov->time); /* creation time */
721 put_be32(pb, mov->time); /* modification time */
722 put_be32(pb, mov->timescale); /* timescale */
723 for (i=0; i<MAX_STREAMS; i++) {
724 if(mov->tracks[i].entry > 0) {
f578f938
TR
725 maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)mov->tracks[i].trackDuration)/(int64_t)mov->tracks[i].timescale;
726 if(maxTrackLen < maxTrackLenTemp)
727 maxTrackLen = maxTrackLenTemp;
1cb5f7fd
MN
728 if(maxTrackID < mov->tracks[i].trackID)
729 maxTrackID = mov->tracks[i].trackID;
730 }
731 }
732 put_be32(pb, maxTrackLen); /* duration of longest track */
733
734 put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
735 put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
736 put_be16(pb, 0); /* reserved */
737 put_be32(pb, 0); /* reserved */
738 put_be32(pb, 0); /* reserved */
739
740 /* Matrix structure */
741 put_be32(pb, 0x00010000); /* reserved */
742 put_be32(pb, 0x0); /* reserved */
743 put_be32(pb, 0x0); /* reserved */
744 put_be32(pb, 0x0); /* reserved */
745 put_be32(pb, 0x00010000); /* reserved */
746 put_be32(pb, 0x0); /* reserved */
747 put_be32(pb, 0x0); /* reserved */
748 put_be32(pb, 0x0); /* reserved */
749 put_be32(pb, 0x40000000); /* reserved */
750
751 put_be32(pb, 0); /* reserved (preview time) */
752 put_be32(pb, 0); /* reserved (preview duration) */
753 put_be32(pb, 0); /* reserved (poster time) */
754 put_be32(pb, 0); /* reserved (selection time) */
755 put_be32(pb, 0); /* reserved (selection duration) */
756 put_be32(pb, 0); /* reserved (current time) */
757 put_be32(pb, maxTrackID+1); /* Next track id */
758 return 0x6c;
759}
760
69dde1ad
GB
761static int mov_write_udta_tag(ByteIOContext *pb, MOVContext* mov,
762 AVFormatContext *s)
763{
764 int pos = url_ftell(pb);
765 int i;
766
767 put_be32(pb, 0); /* size */
768 put_tag(pb, "udta");
769
770 /* Requirements */
771 for (i=0; i<MAX_STREAMS; i++) {
772 if(mov->tracks[i].entry <= 0) continue;
773 if (mov->tracks[i].enc->codec_id == CODEC_ID_AAC ||
774 mov->tracks[i].enc->codec_id == CODEC_ID_MPEG4) {
775 int pos = url_ftell(pb);
776 put_be32(pb, 0); /* size */
777 put_tag(pb, "\251req");
778 put_be16(pb, sizeof("QuickTime 6.0 or greater") - 1);
779 put_be16(pb, 0);
780 put_buffer(pb, "QuickTime 6.0 or greater",
781 sizeof("QuickTime 6.0 or greater") - 1);
782 updateSize(pb, pos);
783 break;
784 }
785 }
786
787 /* Encoder */
788 {
789 int pos = url_ftell(pb);
790 put_be32(pb, 0); /* size */
791 put_tag(pb, "\251enc");
792 put_be16(pb, sizeof(LIBAVFORMAT_IDENT) - 1); /* string length */
793 put_be16(pb, 0);
794 put_buffer(pb, LIBAVFORMAT_IDENT, sizeof(LIBAVFORMAT_IDENT) - 1);
795 updateSize(pb, pos);
796 }
797
798 if( s->title[0] )
799 {
800 int pos = url_ftell(pb);
801 put_be32(pb, 0); /* size */
802 put_tag(pb, "\251nam");
803 put_be16(pb, strlen(s->title)); /* string length */
804 put_be16(pb, 0);
805 put_buffer(pb, s->title, strlen(s->title));
806 updateSize(pb, pos);
807 }
808
809 if( s->author[0] )
810 {
811 int pos = url_ftell(pb);
812 put_be32(pb, 0); /* size */
813 put_tag(pb, /*"\251aut"*/ "\251day" );
814 put_be16(pb, strlen(s->author)); /* string length */
815 put_be16(pb, 0);
816 put_buffer(pb, s->author, strlen(s->author));
817 updateSize(pb, pos);
818 }
819
820 if( s->comment[0] )
821 {
822 int pos = url_ftell(pb);
823 put_be32(pb, 0); /* size */
824 put_tag(pb, "\251des");
825 put_be16(pb, strlen(s->comment)); /* string length */
826 put_be16(pb, 0);
827 put_buffer(pb, s->comment, strlen(s->comment));
828 updateSize(pb, pos);
829 }
830
831 return updateSize(pb, pos);
832}
833
834static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov,
835 AVFormatContext *s)
1cb5f7fd 836{
6e6d6dc0 837 int pos, i;
1cb5f7fd
MN
838 pos = url_ftell(pb);
839 put_be32(pb, 0); /* size placeholder*/
840 put_tag(pb, "moov");
841 mov->timescale = globalTimescale;
842
843 for (i=0; i<MAX_STREAMS; i++) {
e45ccf79
GB
844 if(mov->tracks[i].entry <= 0) continue;
845
846 if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) {
847 mov->tracks[i].timescale = mov->tracks[i].enc->frame_rate;
848 mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_rate_base;
849 }
850 else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) {
851 /* If AMR, track timescale = 8000, AMR_WB = 16000 */
852 if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) {
853 mov->tracks[i].sampleDuration = 160; // Bytes per chunk
854 mov->tracks[i].timescale = 8000;
1cb5f7fd 855 }
e45ccf79
GB
856 else {
857 mov->tracks[i].timescale = mov->tracks[i].enc->sample_rate;
858 mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_size;
1cb5f7fd 859 }
1cb5f7fd 860 }
e45ccf79
GB
861
862 mov->tracks[i].trackDuration =
863 mov->tracks[i].sampleCount * mov->tracks[i].sampleDuration;
864 mov->tracks[i].time = mov->time;
865 mov->tracks[i].trackID = i+1;
1cb5f7fd
MN
866 }
867
6e6d6dc0
MN
868 mov_write_mvhd_tag(pb, mov);
869 //mov_write_iods_tag(pb, mov);
1cb5f7fd
MN
870 for (i=0; i<MAX_STREAMS; i++) {
871 if(mov->tracks[i].entry > 0) {
6e6d6dc0 872 mov_write_trak_tag(pb, &(mov->tracks[i]));
1cb5f7fd
MN
873 }
874 }
875
69dde1ad
GB
876 mov_write_udta_tag(pb, mov, s);
877
6e6d6dc0 878 return updateSize(pb, pos);
1cb5f7fd
MN
879}
880
f578f938 881int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov)
1cb5f7fd 882{
f578f938 883 mov->mdat_pos = url_ftell(pb);
1cb5f7fd
MN
884 put_be32(pb, 0); /* size placeholder*/
885 put_tag(pb, "mdat");
886 return 0;
887}
888
889/* TODO: This needs to be more general */
e45ccf79 890int mov_write_ftyp_tag(ByteIOContext *pb, AVFormatContext *s)
1cb5f7fd 891{
69dde1ad
GB
892 MOVContext *mov = s->priv_data;
893
1cb5f7fd
MN
894 put_be32(pb, 0x14 ); /* size */
895 put_tag(pb, "ftyp");
e45ccf79 896
69dde1ad 897 if ( mov->mode == MODE_3GP )
e45ccf79
GB
898 put_tag(pb, "3gp4");
899 else
900 put_tag(pb, "isom");
901
1cb5f7fd 902 put_be32(pb, 0x200 );
e45ccf79 903
69dde1ad 904 if ( mov->mode == MODE_3GP )
e45ccf79
GB
905 put_tag(pb, "3gp4");
906 else
907 put_tag(pb, "mp41");
908
1cb5f7fd
MN
909 return 0x14;
910}
911
912static int mov_write_header(AVFormatContext *s)
913{
914 ByteIOContext *pb = &s->pb;
69dde1ad
GB
915 MOVContext *mov = s->priv_data;
916 int i;
1cb5f7fd 917
69dde1ad
GB
918 /* Default mode == MP4 */
919 mov->mode = MODE_MP4;
920
921 if (s->oformat != NULL) {
922 if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP;
923 else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV;
924
925 if ( mov->mode == MODE_3GP || mov->mode == MODE_MP4 )
926 mov_write_ftyp_tag(pb,s);
927 }
928
929 for (i=0; i<MAX_STREAMS; i++) {
930 mov->tracks[i].mode = mov->mode;
f578f938
TR
931 }
932
1cb5f7fd
MN
933 put_flush_packet(pb);
934
935 return 0;
936}
937
7906085f 938static int Timestamp(void) {
dd0003fa 939 return 1067949799U+(24107*86400); //its the modification time of this line :)
1cb5f7fd
MN
940}
941
942static int mov_write_packet(AVFormatContext *s, int stream_index,
49057904 943 const uint8_t *buf, int size, int64_t pts)
1cb5f7fd
MN
944{
945 MOVContext *mov = s->priv_data;
946 ByteIOContext *pb = &s->pb;
e45ccf79
GB
947 AVCodecContext *enc = &s->streams[stream_index]->codec;
948 MOVTrack* trk = &mov->tracks[stream_index];
1a31840c 949 int cl, id;
e45ccf79 950 unsigned int samplesInChunk = 0;
1cb5f7fd 951
e45ccf79
GB
952 if (url_is_streamed(&s->pb)) return 0; /* Can't handle that */
953 if (!size) return 0; /* Discard 0 sized packets */
1cb5f7fd 954
e45ccf79
GB
955 if (enc->codec_type == CODEC_TYPE_VIDEO ) {
956 samplesInChunk = 1;
957 }
958 else if (enc->codec_type == CODEC_TYPE_AUDIO ) {
959 if( enc->codec_id == CODEC_ID_AMR_NB) {
f578f938 960 /* We must find out how many AMR blocks there are in one packet */
e45ccf79
GB
961 static uint16_t packed_size[16] =
962 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0};
963 int len = 0;
964
965 while (len < size && samplesInChunk < 100) {
966 len += packed_size[(buf[len] >> 3) & 0x0F];
967 samplesInChunk++;
f578f938 968 }
1cb5f7fd 969 }
e45ccf79
GB
970 else if(enc->codec_id == CODEC_ID_PCM_ALAW) {
971 samplesInChunk = size/enc->channels;
1cb5f7fd 972 }
9a4d9388
RS
973 else if(enc->codec_id == CODEC_ID_PCM_S16BE || enc->codec_id == CODEC_ID_PCM_S16LE) {
974 samplesInChunk = size/(2*enc->channels);
975 }
e45ccf79
GB
976 else {
977 samplesInChunk = 1;
1cb5f7fd 978 }
e45ccf79
GB
979 }
980
981 if ((enc->codec_id == CODEC_ID_MPEG4 || enc->codec_id == CODEC_ID_AAC)
982 && trk->vosLen == 0) {
983 assert(enc->extradata_size);
984
985 trk->vosLen = enc->extradata_size;
986 trk->vosData = av_malloc(trk->vosLen);
987 memcpy(trk->vosData, enc->extradata, trk->vosLen);
988 }
989
990 cl = trk->entry / MOV_INDEX_CLUSTER_SIZE;
991 id = trk->entry % MOV_INDEX_CLUSTER_SIZE;
992
993 if (trk->ents_allocated <= trk->entry) {
994 trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*));
995 if (!trk->cluster)
996 return -1;
997 trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry));
998 if (!trk->cluster[cl])
999 return -1;
1000 trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE;
1001 }
1002 if (mov->mdat_written == 0) {
1003 mov_write_mdat_tag(pb, mov);
1004 mov->mdat_written = 1;
1005 mov->time = Timestamp();
1006 }
1007
69dde1ad 1008 trk->cluster[cl][id].pos = url_ftell(pb);
e45ccf79
GB
1009 trk->cluster[cl][id].samplesInChunk = samplesInChunk;
1010 trk->cluster[cl][id].size = size;
1011 trk->cluster[cl][id].entries = samplesInChunk;
1012 if(enc->codec_type == CODEC_TYPE_VIDEO) {
1013 trk->cluster[cl][id].key_frame = enc->coded_frame->key_frame;
1014 if(enc->coded_frame->pict_type == FF_I_TYPE)
f578f938 1015 trk->hasKeyframes = 1;
1cb5f7fd 1016 }
e45ccf79
GB
1017 trk->enc = enc;
1018 trk->entry++;
1019 trk->sampleCount += samplesInChunk;
1020 trk->mdat_size += size;
1021
1cb5f7fd
MN
1022 put_buffer(pb, buf, size);
1023
1024 put_flush_packet(pb);
1025 return 0;
1026}
1027
1028static int mov_write_trailer(AVFormatContext *s)
1029{
1030 MOVContext *mov = s->priv_data;
1031 ByteIOContext *pb = &s->pb;
1032 int res = 0;
1033 int i, j;
1cb5f7fd 1034
69dde1ad 1035 offset_t moov_pos = url_ftell(pb);
1cb5f7fd
MN
1036
1037 /* Write size of mdat tag */
69dde1ad 1038 for (i=0, j=0; i<MAX_STREAMS; i++) {
1cb5f7fd
MN
1039 if(mov->tracks[i].ents_allocated > 0) {
1040 j += mov->tracks[i].mdat_size;
1041 }
1042 }
f578f938 1043 url_fseek(pb, mov->mdat_pos, SEEK_SET);
1cb5f7fd 1044 put_be32(pb, j+8);
69dde1ad 1045 url_fseek(pb, moov_pos, SEEK_SET);
1cb5f7fd 1046
69dde1ad 1047 mov_write_moov_tag(pb, mov, s);
1cb5f7fd
MN
1048
1049 for (i=0; i<MAX_STREAMS; i++) {
1050 for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) {
1051 av_free(mov->tracks[i].cluster[j]);
1052 }
1053 av_free(mov->tracks[i].cluster);
ec7d0d2e
GB
1054 if( mov->tracks[i].vosLen ) av_free( mov->tracks[i].vosData );
1055
1cb5f7fd
MN
1056 mov->tracks[i].cluster = NULL;
1057 mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0;
1058 }
69dde1ad 1059
1cb5f7fd
MN
1060 put_flush_packet(pb);
1061
1062 return res;
1063}
1064
1065static AVOutputFormat mov_oformat = {
1066 "mov",
1067 "mov format",
1068 NULL,
1069 "mov",
1070 sizeof(MOVContext),
69dde1ad 1071 CODEC_ID_AAC,
2187d948 1072 CODEC_ID_MPEG4,
1cb5f7fd
MN
1073 mov_write_header,
1074 mov_write_packet,
1075 mov_write_trailer,
1076};
1077
1078static AVOutputFormat _3gp_oformat = {
1079 "3gp",
1080 "3gp format",
1081 NULL,
1082 "3gp",
1083 sizeof(MOVContext),
1084 CODEC_ID_AMR_NB,
1085 CODEC_ID_H263,
1086 mov_write_header,
1087 mov_write_packet,
1088 mov_write_trailer,
1089};
1090
1091static AVOutputFormat mp4_oformat = {
1092 "mp4",
1093 "mp4 format",
4cb3f3b6
DC
1094 "application/mp4",
1095 "mp4,m4a",
1cb5f7fd
MN
1096 sizeof(MOVContext),
1097 CODEC_ID_AAC,
1098 CODEC_ID_MPEG4,
1099 mov_write_header,
1100 mov_write_packet,
1101 mov_write_trailer,
1102};
1103
1104int movenc_init(void)
1105{
1106 av_register_output_format(&mov_oformat);
1107 av_register_output_format(&_3gp_oformat);
1108 av_register_output_format(&mp4_oformat);
1109 return 0;
1110}