ppm vhook follow up patch by (Charles Yates <charles dot yates at pandora dot be>)
[libav.git] / libavformat / movenc.c
CommitLineData
1cb5f7fd
MN
1/*
2 * MOV, 3GP, MP4 encoder.
3 * Copyright (c) 2003 Thomas Raivio.
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 "avio.h"
21#include <time.h>
22
6e6d6dc0
MN
23#undef NDEBUG
24#include <assert.h>
25
1cb5f7fd
MN
26/*
27 * Limitations
28 * - Currently supports h.263, MPEG4 video codecs, and AMR audio codec.
29 */
30
31#define MOV_INDEX_CLUSTER_SIZE 16384
32#define globalTimescale 1000
33
34typedef struct MOVIentry {
35 unsigned int flags, pos, len;
36 unsigned int entries;
37} MOVIentry;
38
39typedef struct MOVIndex {
40 int entry;
41 int samples;
42 int mdat_size;
43 offset_t mdat_pos;
44 int ents_allocated;
45 long timescale;
46 long time;
47 long frameDuration;
48 long sampleDelta;
49 int trackID;
50 AVCodecContext *enc;
51
52 int vosLen;
6e6d6dc0 53 uint8_t *vosData;
1cb5f7fd
MN
54 MOVIentry** cluster;
55} MOVTrack;
56
57typedef struct {
58 long time;
59 int nb_streams;
60 offset_t movi_list;
61 long timescale;
62 MOVTrack tracks[MAX_STREAMS];
63} MOVContext;
64
6e6d6dc0
MN
65//FIXME supprt 64bit varaint with wide placeholders
66static int updateSize (ByteIOContext *pb, int pos)
1cb5f7fd
MN
67{
68 long curpos = url_ftell(pb);
69 url_fseek(pb, pos, SEEK_SET);
6e6d6dc0 70 put_be32(pb, curpos - pos); /* rewrite size */
1cb5f7fd 71 url_fseek(pb, curpos, SEEK_SET);
6e6d6dc0
MN
72
73 return curpos - pos;
1cb5f7fd
MN
74}
75
6e6d6dc0 76static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
77{
78 int i;
79 put_be32(pb, 16+track->entry*4); /* size */
80 put_tag(pb, "stco");
81 put_be32(pb, 0); /* version & flags */
82 put_be32(pb, track->entry); /* entry count */
83 for (i=0; i<track->entry; i++) {
84 int cl = i / MOV_INDEX_CLUSTER_SIZE;
85 int id = i % MOV_INDEX_CLUSTER_SIZE;
86 put_be32(pb, track->cluster[cl][id].pos);
87 }
88 return 16+track->entry*4;
89}
90
6e6d6dc0 91static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
92{
93 int i, size;
94
95 if(track->cluster[0][0].entries != 0)
96 size = 20;
97 else
98 size = 20+track->samples*4;
99 put_be32(pb, size); /* size */
100 put_tag(pb, "stsz");
101 put_be32(pb, 0); /* version & flags */
102
103 /* TODO: Ugly (and false) assumption: if we have a chunk of samples, assume
104 * all sizes are same */
105 if(track->cluster[0][0].entries != 0) {
106 int sSize = track->cluster[0][0].len/track->cluster[0][0].entries;
107 put_be32(pb, sSize); /* sample size */
108 put_be32(pb, track->samples); /* sample count */
109 }
110 else
111 {
112 put_be32(pb, 0); /* sample size */
113 put_be32(pb, track->samples); /* sample count */
114 for (i=0; i<track->samples; i++) {
115 int cl = i / MOV_INDEX_CLUSTER_SIZE;
116 int id = i % MOV_INDEX_CLUSTER_SIZE;
117 put_be32(pb, track->cluster[cl][id].len);
118 }
119 }
120 return size;
121}
122
6e6d6dc0 123static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
124{
125 int size;
126 if(track->cluster[0][0].entries != 0)
127 size = 16+track->entry*4*3;
128 else
129 size = 0x1c;
130 put_be32(pb, size); // size
131 put_tag(pb, "stsc");
132 put_be32(pb, 0); // version & flags
133 if(track->cluster[0][0].entries != 0) {
134 int i;
135 put_be32(pb, track->entry); // entry count
136 for (i=0; i<track->entry; i++) {
137 int cl = i / MOV_INDEX_CLUSTER_SIZE;
138 int id = i % MOV_INDEX_CLUSTER_SIZE;
139 put_be32(pb, i+1); // first chunk
140 put_be32(pb, track->cluster[cl][id].entries);
141 put_be32(pb, 0x1); // sample description index
142 }
143 }
144 else {
145 put_be32(pb, 1); // entry count
146 put_be32(pb, 0x1); // first chunk
147 put_be32(pb, 0x1); // samples per chunk
148 put_be32(pb, 0x1); // sample description index
149 }
150
151 return size;
152}
153
6e6d6dc0
MN
154//FIXME keyframes?
155static int mov_write_stss_tag(ByteIOContext *pb) //TRA OK
1cb5f7fd
MN
156{
157 put_be32(pb, 0x14); /* size */
158 put_tag(pb, "stss");
159 put_be32(pb, 0); /* version & flags */
160 put_be32(pb, 1); /* entry count */
161 put_be32(pb, 0x1); /* sample number */
162 return 0x14;
163}
164
6e6d6dc0 165static int mov_write_damr_tag(ByteIOContext *pb)
1cb5f7fd
MN
166{
167 put_be32(pb, 0x11); /* size */
168 put_tag(pb, "damr");
169 put_tag(pb, "FFMP");
170 put_byte(pb, 0);
171 put_be16(pb, 0x81ff); /* Mode set (all modes for AMR_NB) */
172 put_be16(pb, 1); /* Mode change period (no restriction) */
173 return 0x11;
174}
175
6e6d6dc0 176static int mov_write_samr_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 177{
6e6d6dc0 178 int pos = url_ftell(pb);
1cb5f7fd
MN
179 put_be32(pb, 0); /* size */
180 /* "samr" for AMR NB, "sawb" for AMR WB */
181 put_tag(pb, "samr");
182 put_be32(pb, 0); /* Reserved */
183 put_be16(pb, 0); /* Reserved */
184 put_be16(pb, 1); /* Data-reference index, XXX == 1 */
185 put_be32(pb, 0); /* Reserved */
186 put_be32(pb, 0); /* Reserved */
187
188 put_be16(pb, 2); /* Reserved */
189 put_be16(pb, 0x10); /* Reserved */
190 put_be32(pb, 0); /* Reserved */
191 put_be16(pb, track->timescale); /* Time scale */
192 put_be16(pb, 0); /* Reserved */
193
6e6d6dc0
MN
194 mov_write_damr_tag(pb);
195 return updateSize (pb, pos);
1cb5f7fd
MN
196}
197
6e6d6dc0 198static int mov_write_d263_tag(ByteIOContext *pb)
1cb5f7fd
MN
199{
200 put_be32(pb, 0xf); /* size */
201 put_tag(pb, "d263");
202 put_tag(pb, "FFMP");
203 put_be16(pb, 0x0a);
204 put_byte(pb, 0);
205 return 0xf;
206}
207
6e6d6dc0 208static int mov_write_s263_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 209{
6e6d6dc0 210 int pos = url_ftell(pb);
1cb5f7fd
MN
211 put_be32(pb, 0); /* size */
212 put_tag(pb, "s263");
213 put_be32(pb, 0); /* Reserved */
214 put_be16(pb, 0); /* Reserved */
215 put_be16(pb, 1); /* Data-reference index */
216 put_be32(pb, 0); /* Reserved */
217 put_be32(pb, 0); /* Reserved */
218 put_be32(pb, 0); /* Reserved */
219 put_be32(pb, 0); /* Reserved */
220 put_be16(pb, track->enc->width); /* Video width */
221 put_be16(pb, track->enc->height); /* Video height */
222 put_be32(pb, 0x00480000); /* Reserved */
223 put_be32(pb, 0x00480000); /* Reserved */
224 put_be32(pb, 0); /* Reserved */
225 put_be16(pb, 1); /* Reserved */
226 put_be32(pb, 0); /* Reserved */
227 put_be32(pb, 0); /* Reserved */
228 put_be32(pb, 0); /* Reserved */
229 put_be32(pb, 0); /* Reserved */
230 put_be32(pb, 0); /* Reserved */
231 put_be32(pb, 0); /* Reserved */
232 put_be32(pb, 0); /* Reserved */
233 put_be32(pb, 0); /* Reserved */
234 put_be16(pb, 0x18); /* Reserved */
235 put_be16(pb, 0xffff); /* Reserved */
6e6d6dc0
MN
236 mov_write_d263_tag(pb);
237 return updateSize (pb, pos);
1cb5f7fd
MN
238}
239
240static unsigned int esdsLength(unsigned int len)
241{
242 unsigned int result = 0;
243 unsigned char b = len & 0x7f;
244 result += b;
245 b = (len >> 8) & 0x7f;
246 result += (b + 0x80) << 8;
247 b = (len >> 16) & 0x7f;
248 result += (b + 0x80) << 16;
249 b = (len >> 24) & 0x7f;
250 result += (b + 0x80) << 24;
251 return result;
252}
253
6e6d6dc0 254static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
1cb5f7fd
MN
255{
256 put_be32(pb, track->vosLen+18+14+17);
257 put_tag(pb, "esds");
258 put_be32(pb, 0); // Version
259
260 put_byte(pb, 0x03); // tag = ES_DescriptorTag
261 put_be32(pb, esdsLength(track->vosLen+18+14)); // Length
262 put_be16(pb, 0x0001); // ID (= 1)
263 put_byte(pb, 0x00); // flags (= no flags)
264
265// Decoderconfigdescriptor = 4
266 put_byte(pb, 0x04); // tag = DecoderConfigDescriptor
267 put_be32(pb, esdsLength(track->vosLen+18)); // Length
268 put_byte(pb, 0x20); // Object type indication (Visual 14496-2)
269 put_byte(pb, 0x11); // flags (= Visualstream)
270 put_byte(pb, 0x0); // Buffersize DB (24 bits)
271 put_be16(pb, 0x0dd2); // Buffersize DB
272
273 // TODO: find real values for these
274 put_be32(pb, 0x0002e918); // maxbitrate
275 put_be32(pb, 0x00017e6b); // avg bitrate
276
277// Decoderspecific info Tag = 5
278 put_byte(pb, 0x05); // tag = Decoderspecific info
279 put_be32(pb, esdsLength(track->vosLen)); // length
280 put_buffer(pb, track->vosData, track->vosLen);
6e6d6dc0 281
1cb5f7fd
MN
282 put_byte(pb, 0x06);
283 put_be32(pb, esdsLength(1)); // length
284 put_byte(pb, 0x02);
285 return track->vosLen+18+14+17;
286}
287
6e6d6dc0 288static int mov_write_mp4v_tag(ByteIOContext *pb, MOVTrack* track) // Basic
1cb5f7fd 289{
6e6d6dc0
MN
290 int pos = url_ftell(pb);
291
292 put_be32(pb, 0);
1cb5f7fd
MN
293 put_tag(pb, "mp4v");
294 put_be32(pb, 0); // Reserved
295 put_be16(pb, 0); // Reserved
296 put_be16(pb, 1); // Data-reference index
297 put_be32(pb, 0); // Reserved
298 put_be32(pb, 0); // Reserved
299 put_be32(pb, 0); // Reserved
300 put_be32(pb, 0); // Reserved
301 put_be16(pb, track->enc->width); // Width
302 put_be16(pb, track->enc->height); // Height
303 put_be32(pb, 0x00480000); // Reserved
304 put_be32(pb, 0x00480000); // Reserved
305 put_be32(pb, 0); // Reserved
306 put_be16(pb, 1); // Reserved
307 put_be32(pb, 0); // Reserved
308 put_be32(pb, 0); // Reserved
309 put_be32(pb, 0); // Reserved
310 put_be32(pb, 0); // Reserved
311 put_be32(pb, 0); // Reserved
312 put_be32(pb, 0); // Reserved
313 put_be32(pb, 0); // Reserved
314 put_be32(pb, 0); // Reserved
315 put_be16(pb, 24); // Reserved
316 put_be16(pb, 0xFFFF); // Reserved
317 mov_write_esds_tag(pb, track);
6e6d6dc0 318 return updateSize(pb, pos);
1cb5f7fd
MN
319}
320
6e6d6dc0 321static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 322{
6e6d6dc0 323 int pos = url_ftell(pb);
1cb5f7fd
MN
324 put_be32(pb, 0); /* size */
325 put_tag(pb, "stsd");
326 put_be32(pb, 0); /* version & flags */
327 put_be32(pb, 1); /* entry count */
328 if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
329 if (track->enc->codec_id == CODEC_ID_H263)
6e6d6dc0 330 mov_write_s263_tag(pb, track);
1cb5f7fd 331 else if (track->enc->codec_id == CODEC_ID_MPEG4)
6e6d6dc0 332 mov_write_mp4v_tag(pb, track);
1cb5f7fd
MN
333 }
334 else if (track->enc->codec_type == CODEC_TYPE_AUDIO) {
335 if (track->enc->codec_id == CODEC_ID_AMR_NB)
6e6d6dc0 336 mov_write_samr_tag(pb, track);
1cb5f7fd 337 }
6e6d6dc0 338 return updateSize(pb, pos);
1cb5f7fd
MN
339}
340
6e6d6dc0 341static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
342{
343 put_be32(pb, 0x18); /* size */
344 put_tag(pb, "stts");
345 put_be32(pb, 0); /* version & flags */
346 put_be32(pb, 1); /* entry count */
347
348 put_be32(pb, track->samples); /* sample count */
349 put_be32(pb, track->sampleDelta); /* sample delta */
350 return 0x18;
351}
352
6e6d6dc0 353static int mov_write_dref_tag(ByteIOContext *pb)
1cb5f7fd
MN
354{
355 put_be32(pb, 28); /* size */
356 put_tag(pb, "dref");
357 put_be32(pb, 0); /* version & flags */
358 put_be32(pb, 1); /* entry count */
359
360 put_be32(pb, 0xc); /* size */
361 put_tag(pb, "url ");
362 put_be32(pb, 1); /* version & flags */
363
364 return 28;
365}
366
6e6d6dc0 367static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 368{
6e6d6dc0 369 int pos = url_ftell(pb);
1cb5f7fd
MN
370 put_be32(pb, 0); /* size */
371 put_tag(pb, "stbl");
6e6d6dc0
MN
372 mov_write_stsd_tag(pb, track);
373 mov_write_stts_tag(pb, track);
1cb5f7fd 374 if (track->enc->codec_type == CODEC_TYPE_VIDEO)
6e6d6dc0
MN
375 mov_write_stss_tag(pb);
376 mov_write_stsc_tag(pb, track);
377 mov_write_stsz_tag(pb, track);
378 mov_write_stco_tag(pb, track);
379 return updateSize(pb, pos);
1cb5f7fd
MN
380}
381
6e6d6dc0 382static int mov_write_dinf_tag(ByteIOContext *pb)
1cb5f7fd 383{
6e6d6dc0 384 int pos = url_ftell(pb);
1cb5f7fd
MN
385 put_be32(pb, 0); /* size */
386 put_tag(pb, "dinf");
6e6d6dc0
MN
387 mov_write_dref_tag(pb);
388 return updateSize(pb, pos);
1cb5f7fd
MN
389}
390
6e6d6dc0 391static int mov_write_smhd_tag(ByteIOContext *pb)
1cb5f7fd
MN
392{
393 put_be32(pb, 16); /* size */
394 put_tag(pb, "smhd");
395 put_be32(pb, 0); /* version & flags */
396 put_be16(pb, 0); /* reserved (balance, normally = 0) */
397 put_be16(pb, 0); /* reserved */
398 return 16;
399}
400
6e6d6dc0 401static int mov_write_vmhd_tag(ByteIOContext *pb)
1cb5f7fd
MN
402{
403 put_be32(pb, 0x14); /* size (always 0x14) */
404 put_tag(pb, "vmhd");
405 put_be32(pb, 0x01); /* version & flags */
406 put_be64(pb, 0); /* reserved (graphics mode = copy) */
407 return 0x14;
408}
409
6e6d6dc0 410static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 411{
6e6d6dc0 412 int pos = url_ftell(pb);
1cb5f7fd
MN
413 put_be32(pb, 0); /* size */
414 put_tag(pb, "minf");
415 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
6e6d6dc0 416 mov_write_vmhd_tag(pb);
1cb5f7fd 417 else
6e6d6dc0
MN
418 mov_write_smhd_tag(pb);
419 mov_write_dinf_tag(pb);
420 mov_write_stbl_tag(pb, track);
421 return updateSize(pb, pos);
1cb5f7fd
MN
422}
423
6e6d6dc0 424static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
425{
426 int size = 0;
427 size = 45;
428 put_be32(pb, size); /* size */
429 put_tag(pb, "hdlr");
430 put_be32(pb, 0); /* Version & flags */
431 put_be32(pb, 0); /* reserved */
432 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
433 put_tag(pb, "vide"); /* handler type */
434 else
435 put_tag(pb, "soun"); /* handler type */
436 put_byte(pb, 0); /* reserved */
437 put_byte(pb, 0); /* reserved */
438 put_byte(pb, 0); /* reserved */
439 put_byte(pb, 0); /* reserved */
440 put_byte(pb, 0); /* reserved */
441 put_byte(pb, 0); /* reserved */
442 put_byte(pb, 0); /* reserved */
443 put_byte(pb, 0); /* reserved */
444 put_byte(pb, 0); /* reserved */
445 put_byte(pb, 0); /* reserved */
446 put_byte(pb, 0); /* reserved */
447 put_byte(pb, 0); /* reserved */
448 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
449 put_buffer(pb, "VideoHandler", 13);
450 else
451 put_buffer(pb, "SoundHandler", 13);
452 return size;
453}
454
6e6d6dc0 455static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
456{
457 put_be32(pb, 32); /* size */
458 put_tag(pb, "mdhd");
459 put_be32(pb, 0); /* Version & flags */
460 put_be32(pb, track->time); /* creation time */
461 put_be32(pb, track->time); /* modification time */
462 put_be32(pb, track->timescale); /* time scale */
463
464 put_be32(pb, track->timescale*track->entry*track->frameDuration/globalTimescale); /* duration */
465 put_be16(pb, 0); /* language, 0 = english */
466 put_be16(pb, 0); /* reserved (quality) */
467 return 32;
468}
469
6e6d6dc0 470static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 471{
6e6d6dc0 472 int pos = url_ftell(pb);
1cb5f7fd
MN
473 put_be32(pb, 0); /* size */
474 put_tag(pb, "mdia");
6e6d6dc0
MN
475 mov_write_mdhd_tag(pb, track);
476 mov_write_hdlr_tag(pb, track);
477 mov_write_minf_tag(pb, track);
478 return updateSize(pb, pos);
1cb5f7fd
MN
479}
480
6e6d6dc0 481static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
482{
483 put_be32(pb, 0x5c); /* size (always 0x5c) */
484 put_tag(pb, "tkhd");
485 put_be32(pb, 1); /* version & flags (track enabled) */
486 put_be32(pb, track->time); /* creation time */
487 put_be32(pb, track->time); /* modification time */
488 put_be32(pb, track->trackID); /* track-id */
489 put_be32(pb, 0); /* reserved */
490 put_be32(pb, track->entry*track->frameDuration); /* duration */
491
492 put_be32(pb, 0); /* reserved */
493 put_be32(pb, 0); /* reserved */
494 put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
495 /* Volume, only for audio */
496 if(track->enc->codec_type == CODEC_TYPE_AUDIO)
497 put_be16(pb, 0x0100);
498 else
499 put_be16(pb, 0);
500 put_be16(pb, 0); /* reserved */
501
502 /* Matrix structure */
503 put_be32(pb, 0x00010000); /* reserved */
504 put_be32(pb, 0x0); /* reserved */
505 put_be32(pb, 0x0); /* reserved */
506 put_be32(pb, 0x0); /* reserved */
507 put_be32(pb, 0x00010000); /* reserved */
508 put_be32(pb, 0x0); /* reserved */
509 put_be32(pb, 0x0); /* reserved */
510 put_be32(pb, 0x0); /* reserved */
511 put_be32(pb, 0x40000000); /* reserved */
512
513 /* Track width and height, for visual only */
514 if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
515 put_be32(pb, 0x01400000);
516 put_be32(pb, 0x00f00000);
517 }
518 else {
519 put_be32(pb, 0);
520 put_be32(pb, 0);
521 }
522 return 0x5c;
523}
524
6e6d6dc0 525static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 526{
6e6d6dc0 527 int pos = url_ftell(pb);
1cb5f7fd
MN
528 put_be32(pb, 0); /* size */
529 put_tag(pb, "trak");
6e6d6dc0
MN
530 mov_write_tkhd_tag(pb, track);
531 mov_write_mdia_tag(pb, track);
532 return updateSize(pb, pos);
1cb5f7fd
MN
533}
534
535/* TODO: Not sorted out, but not necessary either */
6e6d6dc0 536static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd
MN
537{
538 put_be32(pb, 0x15); /* size */
539 put_tag(pb, "iods");
540 put_be32(pb, 0); /* version & flags */
541 put_be16(pb, 0x1007);
542 put_byte(pb, 0);
543 put_be16(pb, 0x4fff);
544 put_be16(pb, 0xfffe);
545 put_be16(pb, 0x01ff);
546 return 0x15;
547}
548
6e6d6dc0 549static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd
MN
550{
551 int maxTrackID = 1, maxTrackLen = 0, i;
552
553 put_be32(pb, 0x6c); /* size (always 0x6c) */
554 put_tag(pb, "mvhd");
555 put_be32(pb, 0); /* version & flags */
556 put_be32(pb, mov->time); /* creation time */
557 put_be32(pb, mov->time); /* modification time */
558 put_be32(pb, mov->timescale); /* timescale */
559 for (i=0; i<MAX_STREAMS; i++) {
560 if(mov->tracks[i].entry > 0) {
561 if(maxTrackLen < mov->tracks[i].entry*mov->tracks[i].frameDuration)
562 maxTrackLen = mov->tracks[i].entry*mov->tracks[i].frameDuration;
563 if(maxTrackID < mov->tracks[i].trackID)
564 maxTrackID = mov->tracks[i].trackID;
565 }
566 }
567 put_be32(pb, maxTrackLen); /* duration of longest track */
568
569 put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
570 put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
571 put_be16(pb, 0); /* reserved */
572 put_be32(pb, 0); /* reserved */
573 put_be32(pb, 0); /* reserved */
574
575 /* Matrix structure */
576 put_be32(pb, 0x00010000); /* reserved */
577 put_be32(pb, 0x0); /* reserved */
578 put_be32(pb, 0x0); /* reserved */
579 put_be32(pb, 0x0); /* reserved */
580 put_be32(pb, 0x00010000); /* reserved */
581 put_be32(pb, 0x0); /* reserved */
582 put_be32(pb, 0x0); /* reserved */
583 put_be32(pb, 0x0); /* reserved */
584 put_be32(pb, 0x40000000); /* reserved */
585
586 put_be32(pb, 0); /* reserved (preview time) */
587 put_be32(pb, 0); /* reserved (preview duration) */
588 put_be32(pb, 0); /* reserved (poster time) */
589 put_be32(pb, 0); /* reserved (selection time) */
590 put_be32(pb, 0); /* reserved (selection duration) */
591 put_be32(pb, 0); /* reserved (current time) */
592 put_be32(pb, maxTrackID+1); /* Next track id */
593 return 0x6c;
594}
595
6e6d6dc0 596static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd 597{
6e6d6dc0 598 int pos, i;
1cb5f7fd
MN
599 pos = url_ftell(pb);
600 put_be32(pb, 0); /* size placeholder*/
601 put_tag(pb, "moov");
602 mov->timescale = globalTimescale;
603
604 for (i=0; i<MAX_STREAMS; i++) {
605 if(mov->tracks[i].entry > 0) {
606 if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) {
607 mov->tracks[i].timescale = globalTimescale;
608 mov->tracks[i].sampleDelta = mov->tracks[i].frameDuration =
609 globalTimescale*mov->tracks[i].enc->frame_rate_base/mov->tracks[i].enc->frame_rate;
610 }
611 else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) {
612 /* If AMR, track timescale = 8000, AMR_WB = 16000 */
613 if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) {
614 mov->tracks[i].frameDuration = 20;
615 mov->tracks[i].sampleDelta = 160;
616 mov->tracks[i].timescale = 8000;
617 }
618 else {
619 mov->tracks[i].timescale = globalTimescale;
620 mov->tracks[i].frameDuration =
621 globalTimescale*mov->tracks[i].enc->frame_rate_base/mov->tracks[i].enc->frame_rate;
622 }
623 }
624 mov->tracks[i].time = mov->time;
625 mov->tracks[i].trackID = i+1;
626 }
627 }
628
6e6d6dc0
MN
629 mov_write_mvhd_tag(pb, mov);
630 //mov_write_iods_tag(pb, mov);
1cb5f7fd
MN
631 for (i=0; i<MAX_STREAMS; i++) {
632 if(mov->tracks[i].entry > 0) {
6e6d6dc0 633 mov_write_trak_tag(pb, &(mov->tracks[i]));
1cb5f7fd
MN
634 }
635 }
636
6e6d6dc0 637 return updateSize(pb, pos);
1cb5f7fd
MN
638}
639
640int mov_write_mdat_tag(ByteIOContext *pb, MOVTrack* track)
641{
642 track->mdat_pos = url_ftell(pb);
643 put_be32(pb, 0); /* size placeholder*/
644 put_tag(pb, "mdat");
645 return 0;
646}
647
648/* TODO: This needs to be more general */
649int mov_write_ftyp_tag(ByteIOContext *pb)
650{
651 put_be32(pb, 0x14 ); /* size */
652 put_tag(pb, "ftyp");
653 put_tag(pb, "3gp4");
654 put_be32(pb, 0x200 );
655 put_tag(pb, "3gp4");
656 return 0x14;
657}
658
659static int mov_write_header(AVFormatContext *s)
660{
661 ByteIOContext *pb = &s->pb;
662
663 /* write ftyp */
664 mov_write_ftyp_tag(pb);
665
666 put_flush_packet(pb);
667
668 return 0;
669}
670
671static int Timestamp() {
672 time_t ltime;
673 time ( &ltime );
674 return ltime+(24107*86400);
675}
676
677static int mov_write_packet(AVFormatContext *s, int stream_index,
49057904 678 const uint8_t *buf, int size, int64_t pts)
1cb5f7fd
MN
679{
680 MOVContext *mov = s->priv_data;
681 ByteIOContext *pb = &s->pb;
682 AVCodecContext *enc;
1a31840c 683 int cl, id;
1cb5f7fd
MN
684
685 enc = &s->streams[stream_index]->codec;
686 if (!url_is_streamed(&s->pb)) {
687 MOVTrack* trk = &mov->tracks[stream_index];
688 int sampleCount = 0;
689
690 /* We must find out how many AMR blocks there are in one packet */
6e6d6dc0 691 if(enc->codec_id == CODEC_ID_AMR_NB) {
1cb5f7fd
MN
692 static uint16_t packed_size[16] = {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0};
693 int len = 0;
694
695 while(len < size && sampleCount < 100) {
696 len += packed_size[(buf[len] >> 3) & 0x0F];
697 sampleCount++;
698 }
699 }
6e6d6dc0
MN
700
701 if(enc->codec_id == CODEC_ID_MPEG4 &&
1cb5f7fd
MN
702 trk->vosLen == 0)
703 {
6e6d6dc0
MN
704 assert(enc->extradata_size);
705
706 trk->vosLen = enc->extradata_size;
707 trk->vosData = av_malloc(trk->vosLen);
708 memcpy(trk->vosData, enc->extradata, trk->vosLen);
1cb5f7fd
MN
709 }
710
1a31840c
MM
711 cl = trk->entry / MOV_INDEX_CLUSTER_SIZE;
712 id = trk->entry % MOV_INDEX_CLUSTER_SIZE;
1cb5f7fd
MN
713
714 if (trk->ents_allocated <= trk->entry) {
715 trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*));
716 if (!trk->cluster)
717 return -1;
718 trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry));
719 if (!trk->cluster[cl])
720 return -1;
721 trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE;
722 }
723 if(stream_index == 0 && trk->entry == 0) {
724 mov_write_mdat_tag(pb, trk);
725 mov->time = Timestamp();
726 }
6e6d6dc0 727
1cb5f7fd
MN
728 trk->cluster[cl][id].pos = url_ftell(pb) - mov->movi_list;
729 trk->cluster[cl][id].len = size;
730 trk->cluster[cl][id].entries = sampleCount;
731 trk->enc = enc;
732 trk->entry++;
733 if(sampleCount == 0)
734 trk->samples++;
735 else
736 trk->samples += sampleCount;
737 trk->mdat_size += size;
738 }
739 put_buffer(pb, buf, size);
740
741 put_flush_packet(pb);
742 return 0;
743}
744
745static int mov_write_trailer(AVFormatContext *s)
746{
747 MOVContext *mov = s->priv_data;
748 ByteIOContext *pb = &s->pb;
749 int res = 0;
750 int i, j;
751 offset_t file_size;
752
753 file_size = url_ftell(pb);
754 j = 0;
755
756 /* Write size of mdat tag */
757 for (i=0; i<MAX_STREAMS; i++) {
758 if(mov->tracks[i].ents_allocated > 0) {
759 j += mov->tracks[i].mdat_size;
760 }
761 }
762 url_fseek(pb, mov->tracks[0].mdat_pos, SEEK_SET);
763 put_be32(pb, j+8);
764 url_fseek(pb, file_size, SEEK_SET);
765
766 mov_write_moov_tag(pb, mov);
767
768 for (i=0; i<MAX_STREAMS; i++) {
769 for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) {
770 av_free(mov->tracks[i].cluster[j]);
771 }
772 av_free(mov->tracks[i].cluster);
773 mov->tracks[i].cluster = NULL;
774 mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0;
775 }
776 put_flush_packet(pb);
777
778 return res;
779}
780
781static AVOutputFormat mov_oformat = {
782 "mov",
783 "mov format",
784 NULL,
785 "mov",
786 sizeof(MOVContext),
787 CODEC_ID_MP2,
2187d948 788 CODEC_ID_MPEG4,
1cb5f7fd
MN
789 mov_write_header,
790 mov_write_packet,
791 mov_write_trailer,
792};
793
794static AVOutputFormat _3gp_oformat = {
795 "3gp",
796 "3gp format",
797 NULL,
798 "3gp",
799 sizeof(MOVContext),
800 CODEC_ID_AMR_NB,
801 CODEC_ID_H263,
802 mov_write_header,
803 mov_write_packet,
804 mov_write_trailer,
805};
806
807static AVOutputFormat mp4_oformat = {
808 "mp4",
809 "mp4 format",
810 NULL,
811 "mp4",
812 sizeof(MOVContext),
813 CODEC_ID_AAC,
814 CODEC_ID_MPEG4,
815 mov_write_header,
816 mov_write_packet,
817 mov_write_trailer,
818};
819
820int movenc_init(void)
821{
822 av_register_output_format(&mov_oformat);
823 av_register_output_format(&_3gp_oformat);
824 av_register_output_format(&mp4_oformat);
825 return 0;
826}