1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16/**
17 ******************************************************************************
18 * @file    M4MP4W_Writer.c
19 * @brief   Implementation of the core MP4 writer
20 ******************************************************************************
21 */
22
23#include "NXPSW_CompilerSwitches.h"
24
25#ifndef _M4MP4W_USE_CST_MEMORY_WRITER
26
27#include "M4OSA_Error.h"
28#include "M4OSA_Debug.h"
29#include "M4MP4W_Writer.h"
30#include "M4MP4W_Utils.h"
31
32/* Check optimisation flags : BEGIN */
33#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
34#ifdef _M4MP4W_MOOV_FIRST
35#error "_M4MP4W_OPTIMIZE_FOR_PHONE should not be used with _M4MP4W_MOOV_FIRST"
36
37#endif
38
39#endif
40
41#ifdef _M4MP4W_UNBUFFERED_VIDEO
42#ifndef _M4MP4W_OPTIMIZE_FOR_PHONE
43#error "_M4MP4W_UNBUFFERED_VIDEO should be used with _M4MP4W_OPTIMIZE_FOR_PHONE"
44
45#endif
46
47#endif
48/* Check optimisation flags : END */
49
50#ifndef _M4MP4W_DONT_USE_TIME_H
51#include <time.h>
52
53#endif /*_M4MP4W_DONT_USE_TIME_H*/
54
55/*MACROS*/
56#define MAJOR_VERSION 3
57#define MINOR_VERSION 3
58#define REVISION 0
59
60#define ERR_CHECK(exp, err) if (!(exp)) { return err; }
61#define CLEANUPonERR(func) if ((err = func) != M4NO_ERROR) goto cleanup
62
63#define max(a,b) (((a) > (b)) ? (a) : (b))
64
65/***************/
66/*Static blocks*/
67/***************/
68
69/*CommonBlocks*/
70
71const M4OSA_UChar Default_ftyp [] =
72{
73    0x00, 0x00, 0x00, 0x18, 'f', 't', 'y', 'p', '3', 'g', 'p', '7', 0x00, 0x00,
74    0x03, 0x00, '3', 'g', 'p', '7', 'i', 's', 'o', 'm'
75};
76
77const M4OSA_UChar CommonBlock2 [] =
78{
79    'm', 'd', 'a', 't'
80};
81
82const M4OSA_UChar CommonBlock3 [] =
83{
84    'm', 'o', 'o', 'v', 0x00, 0x00, 0x00, 0x6C, 'm', 'v', 'h', 'd', 0x00,
85    0x00, 0x00, 0x00
86};
87
88const M4OSA_UChar CommonBlock4 [] =
89{
90    0x00, 0x00, 0x03, 0xE8
91};
92
93const M4OSA_UChar CommonBlock5 [] =
94{
95    0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
98    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03
102};
103
104const M4OSA_UChar CommonBlock6 [] =
105{
106    't', 'r', 'a', 'k', 0x00, 0x00, 0x00, 0x5C, 't', 'k', 'h', 'd', 0x00,
107    0x00, 0x00, 0x01
108};
109
110const M4OSA_UChar CommonBlock7 [] =
111{
112    0x00, 0x00, 0x00, 0x00
113};
114
115const M4OSA_UChar CommonBlock7bis [] =
116{
117    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118    0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
120    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121    0x40, 0x00, 0x00, 0x00
122};
123
124const M4OSA_UChar CommonBlock8 [] =
125{
126    'm', 'd', 'i', 'a', 0x00, 0x00, 0x00, 0x20, 'm', 'd', 'h', 'd', 0x00,
127    0x00, 0x00, 0x00
128};
129
130const M4OSA_UChar CommonBlock9 [] =
131{
132    0x55, 0xC4, 0x00, 0x00
133};
134
135const M4OSA_UChar CommonBlock10 [] =
136{
137    'm', 'i', 'n', 'f', 0x00, 0x00, 0x00, 0x24, 'd', 'i', 'n', 'f', 0x00,
138    0x00, 0x00, 0x1C, 'd', 'r', 'e', 'f', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139    0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 'u', 'r', 'l', ' ', 0x00, 0x00, 0x00,
140    0x01
141};
142
143const M4OSA_UChar CommonBlock11 [] =
144{
145    's', 't', 'b', 'l'
146};
147
148const M4OSA_UChar CommonBlock12 [] =
149{
150    's', 't', 't', 's', 0x00, 0x00, 0x00, 0x00
151};
152
153const M4OSA_UChar SampleDescriptionHeader [] =
154{
155    's', 't', 's', 'd', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
156};
157
158const M4OSA_UChar SampleDescriptionEntryStart [] =
159{
160    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
161    0x00, 0x00, 0x00, 0x00
162};
163
164const M4OSA_UChar CommonBlock15 [] =
165{
166    's', 't', 's', 'z', 0x00, 0x00, 0x00, 0x00
167};
168
169const M4OSA_UChar CommonBlock16 [] =
170{
171    's', 't', 's', 'c', 0x00, 0x00, 0x00, 0x00
172};
173
174const M4OSA_UChar CommonBlock17 [] =
175{
176    's', 't', 'c', 'o', 0x00, 0x00, 0x00, 0x00
177};
178
179const M4OSA_UChar BlockSignatureSkipHeader [] =
180{
181    0x00, 0x00, 0x00, 0x5E, 's', 'k', 'i', 'p'
182};
183/* due to current limitations, size must be 16 */
184const M4OSA_UChar BlockSignatureSkipDefaultEmbeddedString [] =
185{
186    'N', 'X', 'P', 'S', 'W', ' ', 'C', 'A', 'M', 'C', 'O', 'R', 'D', 'E',
187    'R', ' '
188};
189/* follows the version (like " 3.0.2"), then " -- " */
190/* due to current limitations, size must be 60 */
191const M4OSA_UChar BlockSignatureSkipDefaultIntegrationTag [] =
192{
193    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
194    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
195    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
196};
197
198/*VideoBlocks*/
199/* 320*240, now no longer hardcoded */
200/* const M4OSA_UChar VideoBlock1[] =
201    { 0x01, 0x40, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00 }; */
202const M4OSA_UChar VideoBlock1_1 [] =
203{
204    0x00, 0x00, 0x00, 0x21, 'h', 'd', 'l', 'r', 0x00, 0x00, 0x00, 0x00, 0x00,
205    0x00, 0x00, 0x00, 'v', 'i', 'd', 'e', 0x00, 0x00, 0x00, 0x00, 0x00,
206    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
207};
208
209const M4OSA_UChar SampleDescriptionEntryVideoBoilerplate1 [] =
210{
211    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
212};
213
214const M4OSA_UChar SampleDescriptionEntryVideoBoilerplate2 [] =
215{
216    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219    0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF
220};
221
222const M4OSA_UChar VideoBlock4 [] =
223{
224    's', 't', 's', 's', 0x00, 0x00, 0x00, 0x00
225}; /*STSS*/
226
227const M4OSA_UChar VideoBlock5 [] =
228{
229    0x00, 0x00, 0x00, 0x14, 'v', 'm', 'h', 'd', 0x00, 0x00, 0x00, 0x00, 0x00,
230    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
231};
232
233const M4OSA_UChar VideoResolutions [] =
234{
235    0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00
236};
237
238/*Mp4vBlocks*/
239const M4OSA_UChar Mp4vBlock1 [] =
240{
241    'm', 'p', '4', 'v'
242};
243
244const M4OSA_UChar Mp4vBlock3 [] =
245{
246    0x20, 0x11
247};
248
249/*H263Blocks*/
250const M4OSA_UChar H263Block1 [] =
251{
252    's', '2', '6', '3'
253};
254
255const M4OSA_UChar H263Block2 [] =
256{
257    0x00, 0x00, 0x00, 0x0F, 'd', '2', '6', '3'
258};
259
260const M4OSA_UChar H263Block2_bitr [] =
261{
262    0x00, 0x00, 0x00, 0x1F, 'd', '2', '6', '3'
263};
264
265const M4OSA_UChar H263Block3 [] =
266{
267    'P', 'H', 'L', 'P', 0x00, 0x0A, 0x00
268};
269
270const M4OSA_UChar H263Block4 [] =
271{
272    0x00, 0x00, 0x00, 0x10, 'b', 'i', 't', 'r'
273};
274
275/*H264Blocks*/
276const M4OSA_UChar H264Block1 [] =
277{
278    'a', 'v', 'c', '1'
279};
280
281/* Store the avcC field, the version (=1),
282    the profile (=66), the compatibility (=0), */
283
284/* the level (=10),111111 + NAL field Size (= 4 - 1),
285    111 + number of PPS (=1) */
286
287const M4OSA_UChar H264Block2 [] =
288{
289        // Remove the hardcoded DSI values of H264Block2
290        'a' , 'v' , 'c' , 'C'
291};
292
293/*AMRBlocks*/
294const M4OSA_UChar AMRBlock1 [] =
295{
296    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
297};
298
299const M4OSA_UChar AMRBlock1_1 [] =
300{
301    0x00, 0x00, 0x00, 0x21, 'h', 'd', 'l', 'r', 0x00, 0x00, 0x00, 0x00, 0x00,
302    0x00, 0x00, 0x00, 's', 'o', 'u', 'n', 0x00, 0x00, 0x00, 0x00, 0x00,
303    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
304};
305
306const M4OSA_UChar AudioSampleDescEntryBoilerplate [] =
307{
308    0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00
309};
310
311const M4OSA_UChar AMRDSIHeader [] =
312{
313    0x00, 0x00, 0x00, 0x11, 'd', 'a', 'm', 'r'
314};
315
316const M4OSA_UChar AMRDefaultDSI [] =
317{
318    'P', 'H', 'L', 'P', 0x00, 0x00, 0x80, 0x00, 0x01
319};
320
321const M4OSA_UChar AMRBlock4 [] =
322{
323    0x00, 0x00, 0x00, 0x10, 's', 'm', 'h', 'd', 0x00, 0x00, 0x00, 0x00, 0x00,
324    0x00, 0x00, 0x00
325};
326
327/*AMR8Blocks*/
328const M4OSA_UChar AMR8Block1 [] =
329{
330    's', 'a', 'm', 'r'
331};
332
333/*AMR16Blocks*/
334/*const M4OSA_UChar AMR16Block1[] = { 's', 'a', 'w', 'b'};*/
335
336/*AACBlocks*/
337const M4OSA_UChar AACBlock1 [] =
338{
339    'm', 'p', '4', 'a'
340};
341
342const M4OSA_UChar AACBlock2 [] =
343{
344    0x40, 0x15
345};
346
347/*MPEGConfigBlocks (AAC & MP4V)*/
348const M4OSA_UChar MPEGConfigBlock0 [] =
349{
350    'e', 's', 'd', 's', 0x00, 0x00, 0x00, 0x00, 0x03
351};
352
353const M4OSA_UChar MPEGConfigBlock1 [] =
354{
355    0x00, 0x00, 0x00, 0x04
356};
357
358const M4OSA_UChar MPEGConfigBlock2 [] = { 0x05 };
359const M4OSA_UChar MPEGConfigBlock3 [] =
360{
361    0x06, 0x01, 0x02
362};
363
364/*EVRCBlocks*/
365const M4OSA_UChar EVRCBlock3_1 [] =
366{
367    0x00, 0x00, 0x00, 0x0E, 'd', 'e', 'v', 'c'
368};
369
370const M4OSA_UChar EVRCBlock3_2 [] =
371{
372    'P', 'H', 'L', 'P', 0x00, 0x00
373};
374
375/*EVRC8Blocks*/
376const M4OSA_UChar EVRC8Block1 [] =
377{
378    's', 'e', 'v', 'c'
379};
380
381/***********/
382/* Methods */
383/***********/
384
385/*******************************************************************************/
386M4OSA_ERR M4MP4W_getVersion(M4OSA_UInt8 *major, M4OSA_UInt8 *minor,
387                            M4OSA_UInt8 *revision )
388/*******************************************************************************/
389{
390    ERR_CHECK(M4OSA_NULL != major, M4ERR_PARAMETER);
391    ERR_CHECK(M4OSA_NULL != minor, M4ERR_PARAMETER);
392    ERR_CHECK(M4OSA_NULL != revision, M4ERR_PARAMETER);
393
394    *major = MAJOR_VERSION;
395    *minor = MINOR_VERSION;
396    *revision = REVISION;
397
398    return M4NO_ERROR;
399}
400
401static M4OSA_UInt32 M4MP4W_STTS_ALLOC_SIZE;
402static M4OSA_UInt32 M4MP4W_STSZ_ALLOC_SIZE;
403static M4OSA_UInt32 M4MP4W_STSS_ALLOC_SIZE;
404static M4OSA_UInt32 M4MP4W_CHUNK_ALLOC_NB;
405static M4OSA_UInt32 M4MP4W_STTS_AUDIO_ALLOC_SIZE;
406static M4OSA_UInt32 M4MP4W_STSZ_AUDIO_ALLOC_SIZE;
407static M4OSA_UInt32 M4MP4W_CHUNK_AUDIO_ALLOC_NB;
408
409#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
410#ifdef _M4MP4W_UNBUFFERED_VIDEO
411/* stsc[ ] table is splitted at 12 bits */
412#define M4MP4W_VIDEO_MAX_AU_PER_CHUNK 4095 /* 0=notused */
413
414#else
415#define M4MP4W_VIDEO_MAX_AU_PER_CHUNK 10   /* 0=notused */
416
417#endif
418
419#endif
420
421/*******************************************************************************/
422
423M4OSA_ERR M4MP4W_initializeAllocationParameters(M4MP4W_Mp4FileData *Ptr )
424/*******************************************************************************/
425{
426#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
427
428    M4OSA_UInt32 maxMemory, vesMemory;
429    M4OSA_UInt32 nbVideoFrames, nbAudioFrames;
430    M4OSA_UInt32 averageVideoChunk;
431
432    /*-----------*/
433    /* NB_FRAMES */
434    /*-----------*/
435
436    /* magical formula : memory = vesMemory + 12 * framerate * duration */
437
438#ifdef _M4MP4W_UNBUFFERED_VIDEO
439
440    vesMemory = 0x32000; /* 200 kB */
441
442#else
443
444    vesMemory = 0x3E800; /* 250 kB */
445
446#endif
447
448#define VIDEO_POOL_MEMORY 1000000
449
450    maxMemory = VIDEO_POOL_MEMORY;
451
452    if (maxMemory < vesMemory) {
453        return M4ERR_ALLOC;
454    }
455
456    nbVideoFrames = ( maxMemory - vesMemory) / 12;
457
458    M4OSA_TRACE1_1("M4MP4W: %d images max", nbVideoFrames);
459
460    /* VIDEO */
461#ifdef _M4MP4W_UNBUFFERED_VIDEO
462    /* assume an average of 25 fpc : reference = 15 fps * 2s * 0.8 */
463
464    averageVideoChunk = 2500;
465
466#else
467
468    if (M4MP4W_VIDEO_MAX_AU_PER_CHUNK > 0)
469    {
470        averageVideoChunk = 100 * M4MP4W_VIDEO_MAX_AU_PER_CHUNK - 20
471            * (M4MP4W_VIDEO_MAX_AU_PER_CHUNK - 1); /* margin 20% */
472    }
473    else
474    {
475        /* assume an average of 50 fpc */
476        averageVideoChunk = 5000;
477    }
478
479#endif
480
481    M4MP4W_STTS_ALLOC_SIZE = nbVideoFrames * sizeof(M4OSA_UInt32);
482    M4MP4W_STSZ_ALLOC_SIZE = nbVideoFrames * sizeof(M4OSA_UInt16);
483    M4MP4W_STSS_ALLOC_SIZE = nbVideoFrames * sizeof(
484        M4OSA_UInt32); /* very conservative (all images are intra) */
485
486    M4MP4W_CHUNK_ALLOC_NB = ( nbVideoFrames * 100) / averageVideoChunk + 1;
487
488    /* AUDIO */
489
490    nbAudioFrames = nbVideoFrames;
491    /* audio is 5 fps, which is the smallest framerate for video */
492
493    M4MP4W_STTS_AUDIO_ALLOC_SIZE = 100; /* compressed */
494    M4MP4W_STSZ_AUDIO_ALLOC_SIZE = 100; /* compressed */
495
496#ifdef _M4MP4W_UNBUFFERED_VIDEO
497
498    M4MP4W_CHUNK_AUDIO_ALLOC_NB = nbAudioFrames / 10 + 1;
499
500#else
501
502    M4MP4W_CHUNK_AUDIO_ALLOC_NB = nbAudioFrames / 38 + 1;
503
504#endif
505
506    return M4NO_ERROR;
507
508#else
509
510    /* VIDEO 5 min at 25 fps null-enc */
511
512    M4MP4W_STTS_ALLOC_SIZE = 20000;
513    M4MP4W_STSZ_ALLOC_SIZE = 18000;
514    M4MP4W_STSS_ALLOC_SIZE = 5000;
515    M4MP4W_CHUNK_ALLOC_NB = 500;
516
517    /* AUDIO 2 min aac+ null-enc */
518
519    M4MP4W_STTS_AUDIO_ALLOC_SIZE = 32000;
520    M4MP4W_STSZ_AUDIO_ALLOC_SIZE = 20000;
521    M4MP4W_CHUNK_AUDIO_ALLOC_NB = 1000;
522
523    return M4NO_ERROR;
524
525#endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
526
527}
528
529/*******************************************************************************/
530M4OSA_ERR M4MP4W_openWrite(M4OSA_Context *contextPtr,
531                           void *outputFileDescriptor,
532                           M4OSA_FileWriterPointer *fileWriterFunction,
533                           void *tempFileDescriptor,
534                           M4OSA_FileReadPointer *fileReaderFunction )
535/*******************************************************************************/
536{
537    M4OSA_ERR err = M4NO_ERROR;
538    M4MP4W_Mp4FileData *mMp4FileDataPtr = M4OSA_NULL;
539
540    ERR_CHECK(M4OSA_NULL != contextPtr, M4ERR_PARAMETER);
541    ERR_CHECK(M4OSA_NULL != outputFileDescriptor, M4ERR_PARAMETER);
542    ERR_CHECK(M4OSA_NULL != fileWriterFunction, M4ERR_PARAMETER);
543#ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
544    /* Optional, feature won't be used if NULL */
545
546    M4OSA_TRACE2_1("tempFileDescriptor = %p", tempFileDescriptor);
547
548    if (M4OSA_NULL == tempFileDescriptor)
549    {
550        M4OSA_TRACE1_0(
551            "tempFileDescriptor is NULL, RESERVED_MOOV_DISK_SPACE feature not used");
552    }
553
554#else /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
555    /* Not used : ERR_CHECK(M4OSA_NULL != tempFileDescriptor, M4ERR_PARAMETER); */
556#endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
557    /* Not used : ERR_CHECK(M4OSA_NULL != fileReaderFunction, M4ERR_PARAMETER); */
558
559    /* The context reuse mode was suppressed*/
560
561    mMp4FileDataPtr =
562        (M4MP4W_Mp4FileData *)M4OSA_32bitAlignedMalloc(sizeof(M4MP4W_Mp4FileData),
563        M4MP4_WRITER, (M4OSA_Char *)"MP4 writer context");
564    ERR_CHECK(mMp4FileDataPtr != M4OSA_NULL, M4ERR_ALLOC);
565    mMp4FileDataPtr->url = outputFileDescriptor;
566    mMp4FileDataPtr->audioTrackPtr = M4OSA_NULL;
567    mMp4FileDataPtr->videoTrackPtr = M4OSA_NULL;
568    mMp4FileDataPtr->MaxChunkSize = M4MP4W_DefaultMaxChunkSize; /*default  */
569    mMp4FileDataPtr->MaxAUSize = M4MP4W_DefaultMaxAuSize;       /*default  */
570    mMp4FileDataPtr->InterleaveDur =
571        M4MP4W_DefaultInterleaveDur; /*default = 0, i.e. not used*/
572    mMp4FileDataPtr->MaxFileSize = 0; /*default = 0, i.e. not used*/
573    mMp4FileDataPtr->camcoderVersion = 0; /*default is " 0.0.0"*/
574    mMp4FileDataPtr->embeddedString =
575        M4OSA_NULL; /*default is in BlockSignatureSkipDefaultEmbeddedString */
576    mMp4FileDataPtr->integrationTag = M4OSA_NULL; /*default is 0 */
577    mMp4FileDataPtr->MaxFileDuration = 0; /*default = 0, i.e. not used*/
578
579    mMp4FileDataPtr->fileWriterFunctions = fileWriterFunction;
580    mMp4FileDataPtr->hasAudio = M4OSA_FALSE;
581    mMp4FileDataPtr->hasVideo = M4OSA_FALSE;
582    mMp4FileDataPtr->state = M4MP4W_opened;
583    mMp4FileDataPtr->duration = 0; /*i*/
584    /*patch for integrationTag 174 -> 238 (+64)*/
585    mMp4FileDataPtr->filesize =
586        238; /*initialization with constant part in ftyp+mdat+moov+skip*/
587
588    mMp4FileDataPtr->estimateAudioSize = M4OSA_FALSE;
589    mMp4FileDataPtr->audioMsChunkDur =
590        0; /*set and used only when estimateAudioSize is true*/
591    mMp4FileDataPtr->audioMsStopTime =
592        0; /*set and used only when estimateAudioSize is true*/
593
594    mMp4FileDataPtr->fileWriterContext = M4OSA_NULL;
595    /* + CRLV6775 -H.264 trimming */
596    mMp4FileDataPtr->bMULPPSSPS = M4OSA_FALSE;
597    /* - CRLV6775 -H.264 trimming */
598
599#ifndef _M4MP4W_MOOV_FIRST
600
601    mMp4FileDataPtr->absoluteCurrentPos =
602        32; /*init with ftyp + beginning of mdat size*/
603
604#endif
605
606#ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
607
608    mMp4FileDataPtr->safetyFileUrl = tempFileDescriptor;
609    mMp4FileDataPtr->cleanSafetyFile =
610        M4OSA_FALSE; /* No need to clean it just yet. */
611
612#endif               /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
613
614    /* ftyp atom */
615
616    memset((void *) &mMp4FileDataPtr->ftyp,0,
617        sizeof(mMp4FileDataPtr->ftyp));
618
619    *contextPtr = mMp4FileDataPtr;
620
621    M4MP4W_initializeAllocationParameters(mMp4FileDataPtr);
622
623    return err;
624}
625
626/*******************************************************************************/
627M4OSA_ERR M4MP4W_addStream(M4OSA_Context context,
628                           M4SYS_StreamDescription *streamDescPtr )
629/*******************************************************************************/
630{
631    M4OSA_ERR err = M4NO_ERROR;
632
633    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
634
635    ERR_CHECK(M4OSA_NULL != context, M4ERR_PARAMETER);
636
637    ERR_CHECK(( mMp4FileDataPtr->state == M4MP4W_opened)
638        || (mMp4FileDataPtr->state == M4MP4W_ready), M4ERR_STATE);
639    mMp4FileDataPtr->state = M4MP4W_ready;
640
641    switch (streamDescPtr->streamType)
642    {
643        case M4SYS_kAMR:
644        case M4SYS_kAAC:
645        case M4SYS_kEVRC:
646            /*Audio*/
647            ERR_CHECK(streamDescPtr->streamID == AudioStreamID,
648                M4ERR_PARAMETER);
649
650            /*check if an audio track has already been added*/
651            ERR_CHECK(mMp4FileDataPtr->hasAudio == M4OSA_FALSE,
652                M4ERR_BAD_CONTEXT);
653
654            /*check if alloc need to be done*/
655            if (mMp4FileDataPtr->audioTrackPtr == M4OSA_NULL)
656            {
657                mMp4FileDataPtr->audioTrackPtr = (M4MP4W_AudioTrackData
658                    *)M4OSA_32bitAlignedMalloc(sizeof(M4MP4W_AudioTrackData),
659                    M4MP4_WRITER, (M4OSA_Char *)"M4MP4W_AudioTrackData");
660                ERR_CHECK(mMp4FileDataPtr->audioTrackPtr != M4OSA_NULL,
661                    M4ERR_ALLOC);
662
663                /**
664                * We must init these pointers in case an alloc bellow fails */
665                mMp4FileDataPtr->audioTrackPtr->Chunk = M4OSA_NULL;
666                mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable = M4OSA_NULL;
667                mMp4FileDataPtr->audioTrackPtr->chunkSizeTable = M4OSA_NULL;
668                mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable = M4OSA_NULL;
669                mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable = M4OSA_NULL;
670                mMp4FileDataPtr->audioTrackPtr->TABLE_STTS = M4OSA_NULL;
671                mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ = M4OSA_NULL;
672                mMp4FileDataPtr->audioTrackPtr->DSI = M4OSA_NULL;
673
674                /*now dynamic*/
675
676#ifdef _M4MP4W_MOOV_FIRST
677
678                mMp4FileDataPtr->audioTrackPtr->Chunk =
679                    (M4OSA_UChar ** )M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_AUDIO_ALLOC_NB
680                    * sizeof(M4OSA_UChar *),
681                    M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->Chunk");
682                ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->Chunk != M4OSA_NULL,
683                    M4ERR_ALLOC);
684
685#else
686
687                mMp4FileDataPtr->audioTrackPtr->Chunk =
688                    (M4OSA_UChar ** )M4OSA_32bitAlignedMalloc(sizeof(M4OSA_UChar *),
689                    M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->Chunk");
690                ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->Chunk != M4OSA_NULL,
691                    M4ERR_ALLOC);
692                mMp4FileDataPtr->audioTrackPtr->Chunk[0] = M4OSA_NULL;
693
694                mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable =
695                    (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_AUDIO_ALLOC_NB
696                    * sizeof(M4OSA_UInt32),
697                    M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->chunkOffsetTable");
698                ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable
699                    != M4OSA_NULL, M4ERR_ALLOC);
700
701#endif /*_M4MP4W_MOOV_FIRST*/
702
703                mMp4FileDataPtr->audioTrackPtr->TABLE_STTS =
704                    (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_STTS_AUDIO_ALLOC_SIZE,
705                    M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->TABLE_STTS");
706                ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->TABLE_STTS
707                    != M4OSA_NULL, M4ERR_ALLOC);
708                mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedSttsBlocks = 1;
709
710                mMp4FileDataPtr->audioTrackPtr->chunkSizeTable =
711                    (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_AUDIO_ALLOC_NB
712                    * sizeof(M4OSA_UInt32),
713                    M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->chunkSizeTable");
714                ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkSizeTable
715                    != M4OSA_NULL, M4ERR_ALLOC);
716                mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable =
717                    (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_AUDIO_ALLOC_NB
718                    * sizeof(M4OSA_UInt32),
719                    M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->chunkSampleNbTable");
720                ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable
721                    != M4OSA_NULL, M4ERR_ALLOC);
722                mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable =
723                    (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_AUDIO_ALLOC_NB
724                    * sizeof(M4OSA_UInt32),
725                    M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->chunkTimeMsTable");
726                ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable
727                    != M4OSA_NULL, M4ERR_ALLOC);
728
729                mMp4FileDataPtr->audioTrackPtr->LastAllocatedChunk = 0;
730            }
731            mMp4FileDataPtr->hasAudio = M4OSA_TRUE;
732            mMp4FileDataPtr->filesize += 402;
733            mMp4FileDataPtr->audioTrackPtr->MaxChunkSize =
734                mMp4FileDataPtr->MaxChunkSize; /* init value */
735            mMp4FileDataPtr->audioTrackPtr->MaxAUSize =
736                mMp4FileDataPtr->MaxAUSize;
737            mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS = 0;
738            mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb = 0;
739            mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize = 0;
740            mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb = 1;
741            mMp4FileDataPtr->audioTrackPtr->CommonData.timescale =
742                streamDescPtr->timeScale;
743            mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[0] = 0;     /*init*/
744            mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable[0] = 0; /*init*/
745            mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable[0] = 0;   /*init*/
746            mMp4FileDataPtr->audioTrackPtr->currentChunk =
747                0; /*1st chunk is Chunk[0]*/
748            mMp4FileDataPtr->audioTrackPtr->currentPos = 0;
749#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
750
751            mMp4FileDataPtr->audioTrackPtr->currentStsc = 0;
752
753#endif
754
755            mMp4FileDataPtr->audioTrackPtr->microState = M4MP4W_ready;
756            mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedStszBlocks = 0;
757            mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ = M4OSA_NULL;
758
759            mMp4FileDataPtr->audioTrackPtr->avgBitrate =
760                streamDescPtr->averageBitrate;
761            mMp4FileDataPtr->audioTrackPtr->maxBitrate =
762                streamDescPtr->maxBitrate;
763
764            if (streamDescPtr->streamType == M4SYS_kAMR)
765            {
766
767                mMp4FileDataPtr->audioTrackPtr->CommonData.trackType =
768                    M4SYS_kAMR;
769                ERR_CHECK(streamDescPtr->timeScale == 8000, M4ERR_PARAMETER);
770                mMp4FileDataPtr->audioTrackPtr->sampleDuration =
771                    160; /*AMR8+timescale=8000 => sample duration 160 constant*/
772
773                /*Use given DSI if passed, else use default value*/
774                if (streamDescPtr->decoderSpecificInfoSize != 0)
775                {
776                    /*amr DSI is 9 bytes long !*/
777                    mMp4FileDataPtr->audioTrackPtr->dsiSize =
778                        9; /*always 9 for amr*/
779                    ERR_CHECK(streamDescPtr->decoderSpecificInfoSize == 9,
780                        M4ERR_PARAMETER);
781                    mMp4FileDataPtr->audioTrackPtr->DSI =
782                        (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(9, M4MP4_WRITER,
783                        (M4OSA_Char *)"audioTrackPtr->DSI");
784                    ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL,
785                        M4ERR_ALLOC);
786                    memcpy(
787                        (void *)mMp4FileDataPtr->audioTrackPtr->DSI,
788                        (void *)streamDescPtr->decoderSpecificInfo,
789                        9);
790                }
791                else
792                {
793                    mMp4FileDataPtr->audioTrackPtr->DSI =
794                        M4OSA_NULL; /*default static block will be used*/
795                    mMp4FileDataPtr->audioTrackPtr->dsiSize =
796                        0; /*but the actual static dsi is 9 bytes !*/
797                }
798            }
799            else if (streamDescPtr->streamType == M4SYS_kEVRC)
800            {
801
802                mMp4FileDataPtr->audioTrackPtr->CommonData.trackType =
803                    M4SYS_kEVRC;
804                ERR_CHECK(streamDescPtr->timeScale == 8000, M4ERR_PARAMETER);
805                mMp4FileDataPtr->audioTrackPtr->sampleDuration =
806                    160; /*EVRC+timescale=8000 => sample duration 160 constant*/
807
808                /*Use given DSI if passed, else use default value*/
809                if (streamDescPtr->decoderSpecificInfoSize != 0)
810                {
811                    /*evrc DSI is 6 bytes long !*/
812                    mMp4FileDataPtr->audioTrackPtr->dsiSize =
813                        6; /*always 6 for evrc*/
814                    ERR_CHECK(streamDescPtr->decoderSpecificInfoSize == 6,
815                        M4ERR_PARAMETER);
816                    mMp4FileDataPtr->audioTrackPtr->DSI =
817                        (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(6, M4MP4_WRITER,
818                        (M4OSA_Char *)"audioTrackPtr->DSI");
819                    ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL,
820                        M4ERR_ALLOC);
821                    memcpy(
822                        (void *)mMp4FileDataPtr->audioTrackPtr->DSI,
823                        (void *)streamDescPtr->decoderSpecificInfo,
824                        6);
825                }
826                else
827                {
828                    mMp4FileDataPtr->audioTrackPtr->DSI =
829                        M4OSA_NULL; /*default static block will be used*/
830                    mMp4FileDataPtr->audioTrackPtr->dsiSize =
831                        0; /*but the actual static dsi is 6 bytes !*/
832                }
833            }
834            else /*M4SYS_kAAC*/
835            {
836                /*avg bitrate should be set*/
837                ERR_CHECK(streamDescPtr->averageBitrate != -1, M4ERR_PARAMETER);
838                ERR_CHECK(streamDescPtr->maxBitrate != -1, M4ERR_PARAMETER);
839
840                mMp4FileDataPtr->audioTrackPtr->CommonData.trackType =
841                    M4SYS_kAAC;
842                mMp4FileDataPtr->audioTrackPtr->sampleDuration =
843                    0; /*don't know for aac, so set 0*/
844
845                mMp4FileDataPtr->audioTrackPtr->dsiSize =
846                    (M4OSA_UInt8)streamDescPtr->decoderSpecificInfoSize;
847
848                if (mMp4FileDataPtr->audioTrackPtr->dsiSize != 0)
849                {
850                    mMp4FileDataPtr->audioTrackPtr->DSI =
851                        (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(
852                        streamDescPtr->decoderSpecificInfoSize,
853                        M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->DSI");
854                    ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL,
855                        M4ERR_ALLOC);
856                    memcpy(
857                        (void *)mMp4FileDataPtr->audioTrackPtr->DSI,
858                        (void *)streamDescPtr->decoderSpecificInfo,
859                        streamDescPtr->decoderSpecificInfoSize);
860                }
861                else
862                {
863                    /*no dsi: return bad parameter ?*/
864                    return M4ERR_PARAMETER;
865                }
866            }
867
868            break;
869
870        case (M4SYS_kMPEG_4):
871        case (M4SYS_kH264):
872        case (M4SYS_kH263):
873            /*Video*/
874            ERR_CHECK(streamDescPtr->streamID == VideoStreamID,
875                M4ERR_PARAMETER);
876
877            /*check if a video track has already been added*/
878            ERR_CHECK(mMp4FileDataPtr->hasVideo == M4OSA_FALSE,
879                M4ERR_BAD_CONTEXT);
880
881            /*check if alloc need to be done*/
882            if (mMp4FileDataPtr->videoTrackPtr == M4OSA_NULL)
883            {
884                mMp4FileDataPtr->videoTrackPtr = (M4MP4W_VideoTrackData
885                    *)M4OSA_32bitAlignedMalloc(sizeof(M4MP4W_VideoTrackData),
886                    M4MP4_WRITER, (M4OSA_Char *)"M4MP4W_VideoTrackData");
887                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr != M4OSA_NULL,
888                    M4ERR_ALLOC);
889
890                /**
891                * We must init these pointers in case an alloc bellow fails */
892                mMp4FileDataPtr->videoTrackPtr->Chunk = M4OSA_NULL;
893                mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable = M4OSA_NULL;
894                mMp4FileDataPtr->videoTrackPtr->chunkSizeTable = M4OSA_NULL;
895                mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable = M4OSA_NULL;
896                mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable = M4OSA_NULL;
897                mMp4FileDataPtr->videoTrackPtr->TABLE_STTS = M4OSA_NULL;
898                mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ = M4OSA_NULL;
899                mMp4FileDataPtr->videoTrackPtr->TABLE_STSS = M4OSA_NULL;
900                mMp4FileDataPtr->videoTrackPtr->DSI = M4OSA_NULL;
901
902                /*now dynamic*/
903
904#ifdef _M4MP4W_MOOV_FIRST
905
906                mMp4FileDataPtr->videoTrackPtr->Chunk =
907                    (M4OSA_UChar ** )M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_ALLOC_NB
908                    * sizeof(M4OSA_UChar *),
909                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->Chunk");
910                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->Chunk != M4OSA_NULL,
911                    M4ERR_ALLOC);
912
913#else
914                /*re-use the same chunk and flush it when full*/
915
916                mMp4FileDataPtr->videoTrackPtr->Chunk =
917                    (M4OSA_UChar ** )M4OSA_32bitAlignedMalloc(sizeof(M4OSA_UChar *),
918                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->Chunk");
919                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->Chunk != M4OSA_NULL,
920                    M4ERR_ALLOC);
921                mMp4FileDataPtr->videoTrackPtr->Chunk[0] = M4OSA_NULL;
922
923                mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable =
924                    (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_ALLOC_NB
925                    * sizeof(M4OSA_UInt32),
926                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->chunkOffsetTable");
927                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable
928                    != M4OSA_NULL, M4ERR_ALLOC);
929
930#endif /*_M4MP4W_MOOV_FIRST*/
931
932                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->Chunk != M4OSA_NULL,
933                    M4ERR_ALLOC);
934                mMp4FileDataPtr->videoTrackPtr->chunkSizeTable =
935                    (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_ALLOC_NB
936                    * sizeof(M4OSA_UInt32),
937                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->chunkSizeTable");
938                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkSizeTable
939                    != M4OSA_NULL, M4ERR_ALLOC);
940                mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable =
941                    (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_ALLOC_NB
942                    * sizeof(M4OSA_UInt32),
943                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->chunkSampleNbTable");
944                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable
945                    != M4OSA_NULL, M4ERR_ALLOC);
946                mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable =
947                    (M4MP4W_Time32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_ALLOC_NB
948                    * sizeof(M4MP4W_Time32),
949                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->chunkTimeMsTable");
950                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable
951                    != M4OSA_NULL, M4ERR_ALLOC);
952
953                mMp4FileDataPtr->videoTrackPtr->LastAllocatedChunk = 0;
954                /*tables are now dynamic*/
955                mMp4FileDataPtr->videoTrackPtr->TABLE_STTS =
956                    (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_STTS_ALLOC_SIZE,
957                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->TABLE_STTS");
958                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STTS
959                    != M4OSA_NULL, M4ERR_ALLOC);
960                mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks = 1;
961#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
962
963                mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ =
964                    (M4OSA_UInt16 *)M4OSA_32bitAlignedMalloc(M4MP4W_STSZ_ALLOC_SIZE,
965                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->TABLE_STSZ");
966
967#else
968
969                mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ =
970                    (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_STSZ_ALLOC_SIZE,
971                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->TABLE_STSZ");
972
973#endif
974
975                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ
976                    != M4OSA_NULL, M4ERR_ALLOC);
977                mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks = 1;
978                mMp4FileDataPtr->videoTrackPtr->TABLE_STSS =
979                    (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_STSS_ALLOC_SIZE,
980                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->TABLE_STSS");
981                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STSS
982                    != M4OSA_NULL, M4ERR_ALLOC);
983                mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks = 1;
984            }
985            mMp4FileDataPtr->hasVideo = M4OSA_TRUE;
986            mMp4FileDataPtr->filesize += 462;
987            mMp4FileDataPtr->videoTrackPtr->width = M4MP4W_DefaultWidth;
988            mMp4FileDataPtr->videoTrackPtr->height = M4MP4W_DefaultHeight;
989            mMp4FileDataPtr->videoTrackPtr->MaxAUSize =
990                mMp4FileDataPtr->MaxAUSize;
991            mMp4FileDataPtr->videoTrackPtr->CommonData.trackType =
992                streamDescPtr->streamType;
993            mMp4FileDataPtr->videoTrackPtr->MaxChunkSize =
994                mMp4FileDataPtr->MaxChunkSize; /* init value */
995#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
996
997            mMp4FileDataPtr->videoTrackPtr->MaxAUperChunk =
998                M4MP4W_VIDEO_MAX_AU_PER_CHUNK;
999
1000#endif
1001
1002            ERR_CHECK(streamDescPtr->timeScale == 1000, M4ERR_PARAMETER);
1003            mMp4FileDataPtr->videoTrackPtr->CommonData.timescale = 1000;
1004            mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS = 0;
1005            mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb = 0;
1006            mMp4FileDataPtr->videoTrackPtr->CommonData.sampleSize = 0;
1007            mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb = 1;
1008            mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[0] = 0;     /*init*/
1009            mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable[0] = 0; /*init*/
1010            mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable[0] = 0;   /*init*/
1011            mMp4FileDataPtr->videoTrackPtr->currentChunk =
1012                0; /*1st chunk is Chunk[0]*/
1013            mMp4FileDataPtr->videoTrackPtr->currentPos = 0;
1014#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
1015
1016            mMp4FileDataPtr->videoTrackPtr->currentStsc = 0;
1017
1018#endif
1019
1020            mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb = 0;
1021            mMp4FileDataPtr->videoTrackPtr->microState = M4MP4W_ready;
1022
1023            if (streamDescPtr->streamType == M4SYS_kH263)
1024            {
1025                if (( streamDescPtr->averageBitrate == -1)
1026                    || (streamDescPtr->maxBitrate == -1))
1027                {
1028                    /*the bitrate will not be written if the bitrate information
1029                     is not fully set */
1030                    mMp4FileDataPtr->videoTrackPtr->avgBitrate = -1;
1031                    mMp4FileDataPtr->videoTrackPtr->maxBitrate = -1;
1032                }
1033                else
1034                {
1035                    /*proprietary storage of h263 bitrate.
1036                     Warning: not the actual bitrate (bit set to 1).*/
1037                    mMp4FileDataPtr->videoTrackPtr->avgBitrate =
1038                        streamDescPtr->averageBitrate;
1039                    mMp4FileDataPtr->videoTrackPtr->maxBitrate =
1040                        streamDescPtr->maxBitrate;
1041                }
1042
1043                if (( 0 != streamDescPtr->decoderSpecificInfoSize)
1044                    && (M4OSA_NULL != streamDescPtr->decoderSpecificInfo))
1045                {
1046                    /*decoder specific info size is supposed to be always 7 bytes long */
1047                    ERR_CHECK(streamDescPtr->decoderSpecificInfoSize == 7,
1048                        M4ERR_PARAMETER);
1049                    mMp4FileDataPtr->videoTrackPtr->dsiSize =
1050                        (M4OSA_UInt8)streamDescPtr->decoderSpecificInfoSize;
1051                    mMp4FileDataPtr->videoTrackPtr->DSI =
1052                        (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(
1053                        streamDescPtr->decoderSpecificInfoSize,
1054                        M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
1055                    ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI != M4OSA_NULL,
1056                        M4ERR_ALLOC);
1057                    memcpy(
1058                        (void *)mMp4FileDataPtr->videoTrackPtr->DSI,
1059                        (void *)streamDescPtr->decoderSpecificInfo,
1060                        streamDescPtr->decoderSpecificInfoSize);
1061                }
1062                else
1063                {
1064                    /*use the default dsi*/
1065                    mMp4FileDataPtr->videoTrackPtr->DSI = M4OSA_NULL;
1066                    mMp4FileDataPtr->videoTrackPtr->dsiSize = 0;
1067                }
1068            }
1069
1070            if (streamDescPtr->streamType == M4SYS_kMPEG_4)
1071            {
1072                mMp4FileDataPtr->filesize += 22; /*extra bytes (from h263)*/
1073                /* allow DSI to be M4OSA_NULL, in which case the actual DSI will be
1074                 set by setOption. */
1075                if (( 0 == streamDescPtr->decoderSpecificInfoSize)
1076                    || (M4OSA_NULL == streamDescPtr->decoderSpecificInfo))
1077                {
1078                    mMp4FileDataPtr->videoTrackPtr->DSI = M4OSA_NULL;
1079                    mMp4FileDataPtr->videoTrackPtr->dsiSize = 0;
1080                }
1081                else
1082                {
1083                    /*MP4V specific*/
1084                    /*decoder specific info size is supposed to be always <
1085                        105 so that ESD size can be coded with 1 byte*/
1086                    /*(this should not be restrictive because dsi is always shorter !)*/
1087                    ERR_CHECK(streamDescPtr->decoderSpecificInfoSize < 105,
1088                        M4ERR_PARAMETER);
1089                    mMp4FileDataPtr->videoTrackPtr->dsiSize =
1090                        (M4OSA_UInt8)streamDescPtr->decoderSpecificInfoSize;
1091                    mMp4FileDataPtr->videoTrackPtr->DSI =
1092                        (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(
1093                        streamDescPtr->decoderSpecificInfoSize,
1094                        M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
1095                    ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI != M4OSA_NULL,
1096                        M4ERR_ALLOC);
1097                    memcpy(
1098                        (void *)mMp4FileDataPtr->videoTrackPtr->DSI,
1099                        (void *)streamDescPtr->decoderSpecificInfo,
1100                        streamDescPtr->decoderSpecificInfoSize);
1101                    mMp4FileDataPtr->filesize +=
1102                        streamDescPtr->decoderSpecificInfoSize;
1103                }
1104                /*avg bitrate should be set*/
1105                ERR_CHECK(streamDescPtr->averageBitrate != -1, M4ERR_PARAMETER);
1106                mMp4FileDataPtr->videoTrackPtr->avgBitrate =
1107                    streamDescPtr->averageBitrate;
1108                mMp4FileDataPtr->videoTrackPtr->maxBitrate =
1109                    streamDescPtr->averageBitrate;
1110            }
1111
1112            if (streamDescPtr->streamType == M4SYS_kH264)
1113            {
1114                /* H264 specific information */
1115                mMp4FileDataPtr->videoTrackPtr->avgBitrate =
1116                    streamDescPtr->averageBitrate;
1117                mMp4FileDataPtr->videoTrackPtr->maxBitrate =
1118                    streamDescPtr->maxBitrate;
1119
1120                if ((0 != streamDescPtr->decoderSpecificInfoSize)
1121                    && (M4OSA_NULL != streamDescPtr->decoderSpecificInfo))
1122                {
1123                    /* + H.264 trimming */
1124                    if (M4OSA_TRUE == mMp4FileDataPtr->bMULPPSSPS)
1125                    {
1126                        M4OSA_UInt16 SPSLength, PPSLength;
1127                        M4OSA_UInt16 *DSI;
1128                        /* Store the DSI size */
1129                        mMp4FileDataPtr->videoTrackPtr->dsiSize =
1130                            (M4OSA_UInt8)streamDescPtr->decoderSpecificInfoSize
1131                            - 24;
1132
1133                        /* Copy the DSI (SPS + PPS) */
1134                        mMp4FileDataPtr->videoTrackPtr->DSI =
1135                            (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(
1136                            streamDescPtr->decoderSpecificInfoSize,
1137                            M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
1138                        ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
1139                            != M4OSA_NULL, M4ERR_ALLOC);
1140
1141                        DSI =
1142                            (M4OSA_UInt16 *)streamDescPtr->decoderSpecificInfo;
1143                        SPSLength = DSI[6];
1144                        PPSLength = DSI[10];
1145                        memcpy(
1146                            (void *)mMp4FileDataPtr->videoTrackPtr->DSI,
1147                            (void *)((streamDescPtr->
1148                            decoderSpecificInfo)+12), 2);
1149                        memcpy(
1150                            (void *)((mMp4FileDataPtr->videoTrackPtr->
1151                            DSI)+2), (void *)((streamDescPtr->
1152                            decoderSpecificInfo)+28), SPSLength);
1153
1154                        memcpy(
1155                            (void *)((mMp4FileDataPtr->videoTrackPtr->
1156                            DSI)+2 + SPSLength),
1157                            (void *)((streamDescPtr->
1158                            decoderSpecificInfo)+20), 2);
1159                        memcpy(
1160                            (void *)((mMp4FileDataPtr->videoTrackPtr->
1161                            DSI)+4 + SPSLength),
1162                            (void *)((streamDescPtr->
1163                            decoderSpecificInfo)+28 + SPSLength),
1164                            PPSLength);
1165                        /* - H.264 trimming */
1166                    }
1167                    else
1168                    {
1169                        /* Store the DSI size */
1170                        mMp4FileDataPtr->videoTrackPtr->dsiSize =
1171                            (M4OSA_UInt8)streamDescPtr->decoderSpecificInfoSize;
1172
1173                        /* Copy the DSI (SPS + PPS) */
1174                        mMp4FileDataPtr->videoTrackPtr->DSI =
1175                            (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(
1176                            streamDescPtr->decoderSpecificInfoSize,
1177                            M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
1178                        ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
1179                            != M4OSA_NULL, M4ERR_ALLOC);
1180                        memcpy(
1181                            (void *)mMp4FileDataPtr->videoTrackPtr->DSI,
1182                            (void *)streamDescPtr->
1183                            decoderSpecificInfo,
1184                            streamDescPtr->decoderSpecificInfoSize);
1185                    }
1186                }
1187                else
1188                {
1189                    /*use the default dsi*/
1190                    mMp4FileDataPtr->videoTrackPtr->DSI = M4OSA_NULL;
1191                    mMp4FileDataPtr->videoTrackPtr->dsiSize = 0;
1192                }
1193            }
1194            break;
1195
1196        default:
1197            err = M4ERR_PARAMETER;
1198    }
1199
1200    return err;
1201}
1202
1203/*******************************************************************************/
1204M4OSA_ERR M4MP4W_startWriting( M4OSA_Context context )
1205/*******************************************************************************/
1206{
1207    M4OSA_ERR err = M4NO_ERROR;
1208    M4OSA_UInt32 fileModeAccess = M4OSA_kFileWrite | M4OSA_kFileCreate;
1209    M4OSA_UInt32 i;
1210    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
1211    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
1212
1213    ERR_CHECK((mMp4FileDataPtr->state == M4MP4W_ready), M4ERR_STATE);
1214    mMp4FileDataPtr->state = M4MP4W_writing;
1215
1216    /*audio microstate */
1217    /*    if (mMp4FileDataPtr->audioTrackPtr != M4OSA_NULL)*/
1218    if (mMp4FileDataPtr->hasAudio)
1219    {
1220        ERR_CHECK((mMp4FileDataPtr->audioTrackPtr->microState == M4MP4W_ready),
1221            M4ERR_STATE);
1222        mMp4FileDataPtr->audioTrackPtr->microState = M4MP4W_writing;
1223
1224        /* First audio chunk allocation */
1225        mMp4FileDataPtr->audioTrackPtr->Chunk[0] = (M4OSA_UChar
1226            *)M4OSA_32bitAlignedMalloc(mMp4FileDataPtr->audioTrackPtr->MaxChunkSize,
1227            M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->Chunk[0]");
1228        ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->Chunk[0] != M4OSA_NULL,
1229            M4ERR_ALLOC);
1230    }
1231
1232    /*video microstate*/
1233    /*    if (mMp4FileDataPtr->videoTrackPtr != M4OSA_NULL)*/
1234    if (mMp4FileDataPtr->hasVideo)
1235    {
1236        ERR_CHECK((mMp4FileDataPtr->videoTrackPtr->microState == M4MP4W_ready),
1237            M4ERR_STATE);
1238        mMp4FileDataPtr->videoTrackPtr->microState = M4MP4W_writing;
1239
1240        /* First video chunk allocation */
1241        mMp4FileDataPtr->videoTrackPtr->Chunk[0] = (M4OSA_UChar
1242            *)M4OSA_32bitAlignedMalloc(mMp4FileDataPtr->videoTrackPtr->MaxChunkSize,
1243            M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->Chunk[0]");
1244        ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->Chunk[0] != M4OSA_NULL,
1245            M4ERR_ALLOC);
1246    }
1247
1248    if (mMp4FileDataPtr->estimateAudioSize == M4OSA_TRUE)
1249    {
1250        /*set audioMsChunkDur (duration in ms before a new chunk is created)
1251         for audio size estimation*/
1252        ERR_CHECK(mMp4FileDataPtr->hasVideo, M4ERR_BAD_CONTEXT);
1253        ERR_CHECK(mMp4FileDataPtr->hasAudio, M4ERR_BAD_CONTEXT);
1254
1255        mMp4FileDataPtr->audioMsChunkDur =
1256            20 * mMp4FileDataPtr->audioTrackPtr->MaxChunkSize
1257            / mMp4FileDataPtr->audioTrackPtr->MaxAUSize;
1258
1259        if (( mMp4FileDataPtr->InterleaveDur != 0)
1260            && (mMp4FileDataPtr->InterleaveDur
1261            < 20 *mMp4FileDataPtr->audioTrackPtr->MaxChunkSize
1262            / mMp4FileDataPtr->audioTrackPtr->MaxAUSize))
1263        {
1264            mMp4FileDataPtr->audioMsChunkDur = mMp4FileDataPtr->InterleaveDur;
1265        }
1266    }
1267
1268#ifndef _M4MP4W_MOOV_FIRST
1269
1270    /*open file in write binary mode*/
1271
1272    err = mMp4FileDataPtr->fileWriterFunctions->openWrite(
1273        &mMp4FileDataPtr->fileWriterContext,
1274        mMp4FileDataPtr->url, fileModeAccess);
1275    ERR_CHECK((M4NO_ERROR == err), err);
1276
1277    /*ftyp atom*/
1278    if (mMp4FileDataPtr->ftyp.major_brand != 0)
1279    {
1280        /* Put customized ftyp box */
1281        err =
1282            M4MP4W_putBE32(16 + (mMp4FileDataPtr->ftyp.nbCompatibleBrands * 4),
1283            mMp4FileDataPtr->fileWriterFunctions,
1284            mMp4FileDataPtr->fileWriterContext);
1285        ERR_CHECK((M4NO_ERROR == err), err);
1286        err = M4MP4W_putBE32(M4MPAC_FTYP_TAG,
1287            mMp4FileDataPtr->fileWriterFunctions,
1288            mMp4FileDataPtr->fileWriterContext);
1289        ERR_CHECK((M4NO_ERROR == err), err);
1290        err = M4MP4W_putBE32(mMp4FileDataPtr->ftyp.major_brand,
1291            mMp4FileDataPtr->fileWriterFunctions,
1292            mMp4FileDataPtr->fileWriterContext);
1293        ERR_CHECK((M4NO_ERROR == err), err);
1294        err = M4MP4W_putBE32(mMp4FileDataPtr->ftyp.minor_version,
1295            mMp4FileDataPtr->fileWriterFunctions,
1296            mMp4FileDataPtr->fileWriterContext);
1297        ERR_CHECK((M4NO_ERROR == err), err);
1298
1299        for ( i = 0; i < mMp4FileDataPtr->ftyp.nbCompatibleBrands; i++ )
1300        {
1301            err = M4MP4W_putBE32(mMp4FileDataPtr->ftyp.compatible_brands[i],
1302                mMp4FileDataPtr->fileWriterFunctions,
1303                mMp4FileDataPtr->fileWriterContext);
1304            ERR_CHECK((M4NO_ERROR == err), err);
1305        }
1306    }
1307    else
1308    {
1309        /* Put default ftyp box */
1310        err = M4MP4W_putBlock(Default_ftyp, sizeof(Default_ftyp),
1311            mMp4FileDataPtr->fileWriterFunctions,
1312            mMp4FileDataPtr->fileWriterContext);
1313        ERR_CHECK((M4NO_ERROR == err), err);
1314    }
1315
1316    /*init mdat value with 0 but the right value is set just before the file is closed*/
1317    err = M4MP4W_putBE32(0, mMp4FileDataPtr->fileWriterFunctions,
1318        mMp4FileDataPtr->fileWriterContext);
1319    ERR_CHECK((M4NO_ERROR == err), err);
1320    err = M4MP4W_putBlock(CommonBlock2, sizeof(CommonBlock2),
1321        mMp4FileDataPtr->fileWriterFunctions,
1322        mMp4FileDataPtr->fileWriterContext);
1323    ERR_CHECK((M4NO_ERROR == err), err);
1324
1325#endif /*_M4MP4W_MOOV_FIRST*/
1326
1327#ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
1328
1329    if (0 != mMp4FileDataPtr->MaxFileSize
1330        && M4OSA_NULL != mMp4FileDataPtr->safetyFileUrl)
1331    {
1332        M4OSA_ERR err2 = M4NO_ERROR;
1333        M4OSA_Context safetyFileContext = M4OSA_NULL;
1334        M4OSA_UInt32 safetyFileSize = 0, addendum = 0;
1335        M4OSA_UChar dummyData[100]; /* To fill the safety file with */
1336
1337        err =
1338            mMp4FileDataPtr->fileWriterFunctions->openWrite(&safetyFileContext,
1339            mMp4FileDataPtr->safetyFileUrl, fileModeAccess);
1340        ERR_CHECK((M4NO_ERROR == err), err);
1341
1342        mMp4FileDataPtr->cleanSafetyFile = M4OSA_TRUE;
1343
1344        /* 10% seems to be a reasonable worst case, but also provision for 1kb of moov overhead.*/
1345        safetyFileSize = 1000 + (mMp4FileDataPtr->MaxFileSize * 10 + 99) / 100;
1346
1347        /* Here we add space to take into account the fact we have to flush any pending
1348        chunk in closeWrite, this space is the sum of the maximum chunk sizes, for each
1349        track. */
1350
1351#ifndef _M4MP4W_UNBUFFERED_VIDEO
1352
1353        if (mMp4FileDataPtr->hasVideo)
1354        {
1355            safetyFileSize += mMp4FileDataPtr->videoTrackPtr->MaxChunkSize;
1356        }
1357
1358#endif
1359
1360        if (mMp4FileDataPtr->hasAudio)
1361        {
1362            safetyFileSize += mMp4FileDataPtr->audioTrackPtr->MaxChunkSize;
1363        }
1364
1365        memset((void *)dummyData, 0xCA,sizeof(dummyData)); /* For extra safety. */
1366
1367        for ( i = 0;
1368            i < (safetyFileSize + sizeof(dummyData) - 1) / sizeof(dummyData);
1369            i++ )
1370        {
1371            err = mMp4FileDataPtr->fileWriterFunctions->writeData(
1372                safetyFileContext, dummyData, sizeof(dummyData));
1373
1374            if (M4NO_ERROR != err)
1375                break;
1376            /* Don't return from the function yet, as we need to close the file first. */
1377        }
1378
1379        /* I don't need to keep it open. */
1380        err2 =
1381            mMp4FileDataPtr->fileWriterFunctions->closeWrite(safetyFileContext);
1382
1383        if (M4NO_ERROR != err)
1384        {
1385            return err;
1386        }
1387        else
1388            ERR_CHECK((M4NO_ERROR == err2), err2);
1389
1390        M4OSA_TRACE1_0("Safety file correctly created");
1391    }
1392#endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
1393
1394    return err;
1395}
1396
1397/*******************************************************************************/
1398M4OSA_ERR M4MP4W_newAudioChunk( M4OSA_Context context,
1399                               M4OSA_UInt32 *leftSpaceInChunk )
1400/*******************************************************************************/
1401{
1402    M4OSA_ERR err = M4NO_ERROR;
1403
1404    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
1405    M4OSA_Double scale_audio;
1406
1407#ifndef _M4MP4W_OPTIMIZE_FOR_PHONE
1408
1409    M4OSA_UInt32 reallocNb;
1410
1411#endif
1412
1413    /* video only */
1414
1415    if (mMp4FileDataPtr->audioTrackPtr == M4OSA_NULL)
1416        return M4NO_ERROR;
1417
1418    M4OSA_TRACE1_0(" M4MP4W_newAudioChunk - flush audio");
1419    M4OSA_TRACE1_2("current chunk = %d  offset = 0x%x",
1420        mMp4FileDataPtr->audioTrackPtr->currentChunk,
1421        mMp4FileDataPtr->absoluteCurrentPos);
1422
1423    scale_audio = 1000.0 / mMp4FileDataPtr->audioTrackPtr->CommonData.timescale;
1424
1425#ifndef _M4MP4W_MOOV_FIRST
1426    /*flush chunk*/
1427
1428    err = M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[0],
1429        mMp4FileDataPtr->audioTrackPtr->currentPos,
1430        mMp4FileDataPtr->fileWriterFunctions,
1431        mMp4FileDataPtr->fileWriterContext);
1432
1433    if (M4NO_ERROR != err)
1434    {
1435        M4OSA_FilePosition temp = mMp4FileDataPtr->absoluteCurrentPos;
1436        M4OSA_TRACE2_1(
1437            "M4MP4W_newAudioChunk: putBlock error when flushing chunk: %#X",
1438            err);
1439        /* Ouch, we got an error writing to the file, but we need to properly react so that the
1440         state is still consistent and we can properly close the file so that what has been
1441         recorded so far is not lost. Yay error recovery! */
1442
1443        /* First, we do not know where we are in the file. Put us back at where we were before
1444        attempting to write the data. That way, we're consistent with the chunk state data. */
1445        err = mMp4FileDataPtr->fileWriterFunctions->seek(
1446            mMp4FileDataPtr->fileWriterContext,
1447            M4OSA_kFileSeekBeginning, &temp);
1448
1449        M4OSA_TRACE2_3(
1450            "Backtracking to position 0x%08X, seek returned %d and position %08X",
1451            mMp4FileDataPtr->absoluteCurrentPos, err, temp);
1452
1453        /* Then, do not update any info whatsoever in the writing state. This will have the
1454         consequence that it will be as if the chunk has not been flushed yet, and therefore
1455         it will be done as part of closeWrite (where there could be room to do so,
1456         if some emergency room is freed for that purpose). */
1457
1458        /* And lastly (for here), return that we've reached the limit of available space. */
1459
1460        return M4WAR_MP4W_OVERSIZE;
1461    }
1462
1463    /*update chunk offset*/
1464    mMp4FileDataPtr->audioTrackPtr->
1465        chunkOffsetTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
1466        mMp4FileDataPtr->absoluteCurrentPos;
1467
1468    /*add chunk size to absoluteCurrentPos*/
1469    mMp4FileDataPtr->absoluteCurrentPos +=
1470        mMp4FileDataPtr->audioTrackPtr->currentPos;
1471
1472#endif /*_M4MP4W_MOOV_FIRST*/
1473
1474    /*update chunk info */
1475
1476    mMp4FileDataPtr->audioTrackPtr->
1477        chunkSizeTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
1478        mMp4FileDataPtr->audioTrackPtr->currentPos;
1479    mMp4FileDataPtr->audioTrackPtr->
1480        chunkTimeMsTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
1481        mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS;
1482
1483    mMp4FileDataPtr->audioTrackPtr->currentChunk += 1;
1484    /*if audio amount of data is not estimated*/
1485    if (mMp4FileDataPtr->estimateAudioSize == M4OSA_FALSE)
1486        mMp4FileDataPtr->filesize += 16;
1487
1488    /*alloc new chunk*/
1489    /*only if not already allocated*/
1490    if (mMp4FileDataPtr->audioTrackPtr->currentChunk
1491            > mMp4FileDataPtr->audioTrackPtr->LastAllocatedChunk)
1492    {
1493        /*update LastAllocatedChunk ( -> = currentChunk)*/
1494        mMp4FileDataPtr->audioTrackPtr->LastAllocatedChunk += 1;
1495
1496        /*max nb of chunk is now dynamic*/
1497#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
1498
1499        if (mMp4FileDataPtr->audioTrackPtr->LastAllocatedChunk
1500            + 3 > M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1501        {
1502            M4OSA_TRACE1_0("M4MP4W_newAudioChunk : audio chunk table is full");
1503            return M4WAR_MP4W_OVERSIZE;
1504        }
1505
1506#else
1507
1508        if (((mMp4FileDataPtr->audioTrackPtr->LastAllocatedChunk)
1509            % M4MP4W_CHUNK_AUDIO_ALLOC_NB) == 0)
1510        {
1511            reallocNb = mMp4FileDataPtr->audioTrackPtr->LastAllocatedChunk
1512                + M4MP4W_CHUNK_AUDIO_ALLOC_NB;
1513
1514#ifdef _M4MP4W_MOOV_FIRST
1515
1516            mMp4FileDataPtr->audioTrackPtr->Chunk =
1517                (M4OSA_UChar ** )M4MP4W_realloc(
1518                (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->Chunk,
1519                ( reallocNb - M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1520                * sizeof(M4OSA_UChar *),
1521                reallocNb * sizeof(M4OSA_UChar *));
1522            ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->Chunk != M4OSA_NULL,
1523                M4ERR_ALLOC);
1524
1525#else
1526
1527            mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable =
1528                (M4OSA_UInt32 *)M4MP4W_realloc(
1529                (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->
1530                chunkOffsetTable,
1531                ( reallocNb - M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1532                * sizeof(M4OSA_UInt32),
1533                reallocNb * sizeof(M4OSA_UInt32));
1534            ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable
1535                != M4OSA_NULL, M4ERR_ALLOC);
1536
1537#endif /*_M4MP4W_MOOV_FIRST*/
1538
1539            mMp4FileDataPtr->audioTrackPtr->chunkSizeTable =
1540                (M4OSA_UInt32 *)M4MP4W_realloc(
1541                (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->
1542                chunkSizeTable,
1543                ( reallocNb - M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1544                * sizeof(M4OSA_UInt32),
1545                reallocNb * sizeof(M4OSA_UInt32));
1546            ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkSizeTable
1547                != M4OSA_NULL, M4ERR_ALLOC);
1548
1549            mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable =
1550                (M4OSA_UInt32 *)M4MP4W_realloc(
1551                (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->
1552                chunkSampleNbTable,
1553                ( reallocNb - M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1554                * sizeof(M4OSA_UInt32),
1555                reallocNb * sizeof(M4OSA_UInt32));
1556            ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable
1557                != M4OSA_NULL, M4ERR_ALLOC);
1558
1559            mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable =
1560                (M4MP4W_Time32 *)M4MP4W_realloc(
1561                (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->
1562                chunkTimeMsTable,
1563                ( reallocNb - M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1564                * sizeof(M4MP4W_Time32),
1565                reallocNb * sizeof(M4MP4W_Time32));
1566            ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable
1567                != M4OSA_NULL, M4ERR_ALLOC);
1568        }
1569#endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
1570
1571#ifdef _M4MP4W_MOOV_FIRST
1572
1573        mMp4FileDataPtr->audioTrackPtr->
1574            Chunk[mMp4FileDataPtr->audioTrackPtr->currentChunk] = (M4OSA_UChar
1575            *)M4OSA_32bitAlignedMalloc(mMp4FileDataPtr->audioTrackPtr->MaxChunkSize,
1576            M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->currentChunk");
1577        ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->
1578            Chunk[mMp4FileDataPtr->audioTrackPtr->currentChunk]
1579        != M4OSA_NULL, M4ERR_ALLOC);
1580
1581#endif /*_M4MP4W_MOOV_FIRST*/
1582
1583    }
1584
1585    /*update leftSpaceInChunk, currentPos and currentChunkDur*/
1586    *leftSpaceInChunk = mMp4FileDataPtr->audioTrackPtr->MaxChunkSize;
1587    mMp4FileDataPtr->audioTrackPtr->currentPos = 0;
1588
1589#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
1590    /* check wether to use a new stsc or not */
1591
1592    if (mMp4FileDataPtr->audioTrackPtr->currentStsc > 0)
1593    {
1594        if (( mMp4FileDataPtr->audioTrackPtr->
1595            chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->
1596            currentStsc] & 0xFFF) != (mMp4FileDataPtr->audioTrackPtr->
1597            chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->currentStsc
1598            - 1] & 0xFFF))
1599            mMp4FileDataPtr->audioTrackPtr->currentStsc += 1;
1600    }
1601    else
1602        mMp4FileDataPtr->audioTrackPtr->currentStsc += 1;
1603
1604    /* max nb of chunk is now dynamic */
1605    if (mMp4FileDataPtr->audioTrackPtr->currentStsc
1606        + 3 > M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1607    {
1608        M4OSA_TRACE1_0("M4MP4W_newAudioChunk : audio stsc table is full");
1609        return M4WAR_MP4W_OVERSIZE;
1610    }
1611
1612    /* set nb of samples in the new chunk to 0 */
1613    mMp4FileDataPtr->audioTrackPtr->
1614        chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->currentStsc] =
1615        0 + (mMp4FileDataPtr->audioTrackPtr->currentChunk << 12);
1616
1617#else
1618    /*set nb of samples in the new chunk to 0*/
1619
1620    mMp4FileDataPtr->audioTrackPtr->
1621        chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] = 0;
1622
1623#endif
1624
1625    /*set time of the new chunk to lastCTS (for initialization, but updated further to the
1626    CTS of the last sample in the chunk)*/
1627
1628    mMp4FileDataPtr->audioTrackPtr->
1629        chunkTimeMsTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
1630        (M4OSA_UInt32)(mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS
1631        * scale_audio);
1632
1633    return err;
1634}
1635
1636/*******************************************************************************/
1637M4OSA_ERR M4MP4W_newVideoChunk( M4OSA_Context context,
1638                               M4OSA_UInt32 *leftSpaceInChunk )
1639/*******************************************************************************/
1640{
1641    M4OSA_ERR err = M4NO_ERROR;
1642
1643    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
1644    M4OSA_Double scale_video;
1645
1646#ifndef _M4MP4W_OPTIMIZE_FOR_PHONE
1647
1648    M4OSA_UInt32 reallocNb;
1649
1650#endif
1651
1652    /* audio only */
1653
1654    if (mMp4FileDataPtr->videoTrackPtr == M4OSA_NULL)
1655        return M4NO_ERROR;
1656
1657    M4OSA_TRACE1_0("M4MP4W_newVideoChunk - flush video");
1658    M4OSA_TRACE1_2("current chunk = %d  offset = 0x%x",
1659        mMp4FileDataPtr->videoTrackPtr->currentChunk,
1660        mMp4FileDataPtr->absoluteCurrentPos);
1661
1662    scale_video = 1000.0 / mMp4FileDataPtr->videoTrackPtr->CommonData.timescale;
1663
1664#ifndef _M4MP4W_MOOV_FIRST
1665
1666#ifdef _M4MP4W_UNBUFFERED_VIDEO
1667    /* samples are already written to file */
1668#else
1669    /*flush chunk*/
1670
1671    err = M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[0],
1672        mMp4FileDataPtr->videoTrackPtr->currentPos,
1673        mMp4FileDataPtr->fileWriterFunctions,
1674        mMp4FileDataPtr->fileWriterContext);
1675
1676    if (M4NO_ERROR != err)
1677    {
1678        M4OSA_FilePosition temp = mMp4FileDataPtr->absoluteCurrentPos;
1679        M4OSA_TRACE2_1(
1680            "M4MP4W_newVideoChunk: putBlock error when flushing chunk: %#X",
1681            err);
1682        /* Ouch, we got an error writing to the file, but we need to properly react so that the
1683         state is still consistent and we can properly close the file so that what has been
1684         recorded so far is not lost. Yay error recovery! */
1685
1686        /* First, we do not know where we are in the file. Put us back at where we were before
1687        attempting to write the data. That way, we're consistent with the chunk state data. */
1688        err = mMp4FileDataPtr->fileWriterFunctions->seek(
1689            mMp4FileDataPtr->fileWriterContext,
1690            M4OSA_kFileSeekBeginning, &temp);
1691
1692        M4OSA_TRACE2_3(
1693            "Backtracking to position 0x%08X, seek returned %d and position %08X",
1694            mMp4FileDataPtr->absoluteCurrentPos, err, temp);
1695        /* Then, do not update any info whatsoever in the writing state. This will have the
1696         consequence that it will be as if the chunk has not been flushed yet, and therefore it
1697         will be done as part of closeWrite (where there could be room to do so, if some
1698         emergency room is freed for that purpose). */
1699
1700        /* And lastly (for here), return that we've reached the limit of available space.
1701         We don't care about the error originally returned by putBlock. */
1702
1703        return M4WAR_MP4W_OVERSIZE;
1704    }
1705
1706#endif
1707
1708    /*update chunk offset*/
1709
1710    mMp4FileDataPtr->videoTrackPtr->
1711        chunkOffsetTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
1712        mMp4FileDataPtr->absoluteCurrentPos;
1713
1714    /*add chunk size to absoluteCurrentPos*/
1715    mMp4FileDataPtr->absoluteCurrentPos +=
1716        mMp4FileDataPtr->videoTrackPtr->currentPos;
1717
1718#endif /*_M4MP4W_MOOV_FIRST*/
1719
1720    /*update chunk info before to go for a new one*/
1721
1722    mMp4FileDataPtr->videoTrackPtr->
1723        chunkSizeTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
1724        mMp4FileDataPtr->videoTrackPtr->currentPos;
1725    mMp4FileDataPtr->videoTrackPtr->
1726        chunkTimeMsTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
1727        (M4OSA_UInt32)(mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS
1728        * scale_video);
1729
1730    mMp4FileDataPtr->videoTrackPtr->currentChunk += 1;
1731    mMp4FileDataPtr->filesize += 16;
1732
1733    /*alloc new chunk*/
1734    /*only if not already allocated*/
1735    if (mMp4FileDataPtr->videoTrackPtr->currentChunk
1736        > mMp4FileDataPtr->videoTrackPtr->LastAllocatedChunk)
1737    {
1738        /*update LastAllocatedChunk ( -> = currentChunk)*/
1739        mMp4FileDataPtr->videoTrackPtr->LastAllocatedChunk += 1;
1740
1741        /*max nb of chunk is now dynamic*/
1742#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
1743
1744        if ( mMp4FileDataPtr->videoTrackPtr->LastAllocatedChunk
1745            + 3 > M4MP4W_CHUNK_ALLOC_NB)
1746        {
1747            M4OSA_TRACE1_0("M4MP4W_newVideoChunk : video chunk table is full");
1748            return M4WAR_MP4W_OVERSIZE;
1749        }
1750
1751#else
1752
1753        if (((mMp4FileDataPtr->videoTrackPtr->LastAllocatedChunk)
1754            % M4MP4W_CHUNK_ALLOC_NB) == 0)
1755        {
1756            reallocNb = mMp4FileDataPtr->videoTrackPtr->LastAllocatedChunk
1757                + M4MP4W_CHUNK_ALLOC_NB;
1758
1759#ifdef _M4MP4W_MOOV_FIRST
1760
1761            mMp4FileDataPtr->videoTrackPtr->Chunk =
1762                (M4OSA_UChar ** )M4MP4W_realloc(
1763                (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->Chunk,
1764                ( reallocNb
1765                - M4MP4W_CHUNK_ALLOC_NB) * sizeof(M4OSA_UChar *),
1766                reallocNb * sizeof(M4OSA_UChar *));
1767            ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->Chunk != M4OSA_NULL,
1768                M4ERR_ALLOC);
1769
1770#else
1771
1772            mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable =
1773                (M4OSA_UInt32 *)M4MP4W_realloc(
1774                (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
1775                chunkOffsetTable, ( reallocNb - M4MP4W_CHUNK_ALLOC_NB)
1776                * sizeof(M4OSA_UInt32),
1777                reallocNb * sizeof(M4OSA_UInt32));
1778            ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable
1779                != M4OSA_NULL, M4ERR_ALLOC);
1780
1781#endif /*_M4MP4W_MOOV_FIRST*/
1782
1783            mMp4FileDataPtr->videoTrackPtr->chunkSizeTable =
1784                (M4OSA_UInt32 *)M4MP4W_realloc(
1785                (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
1786                chunkSizeTable, ( reallocNb - M4MP4W_CHUNK_ALLOC_NB)
1787                * sizeof(M4OSA_UInt32),
1788                reallocNb * sizeof(M4OSA_UInt32));
1789            ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkSizeTable
1790                != M4OSA_NULL, M4ERR_ALLOC);
1791
1792            mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable =
1793                (M4OSA_UInt32 *)M4MP4W_realloc(
1794                (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
1795                chunkSampleNbTable, ( reallocNb - M4MP4W_CHUNK_ALLOC_NB)
1796                * sizeof(M4OSA_UInt32),
1797                reallocNb * sizeof(M4OSA_UInt32));
1798            ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable
1799                != M4OSA_NULL, M4ERR_ALLOC);
1800
1801            mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable =
1802                (M4MP4W_Time32 *)M4MP4W_realloc(
1803                (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
1804                chunkTimeMsTable, ( reallocNb
1805                - M4MP4W_CHUNK_ALLOC_NB) * sizeof(M4MP4W_Time32),
1806                reallocNb * sizeof(M4MP4W_Time32));
1807            ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable
1808                != M4OSA_NULL, M4ERR_ALLOC);
1809        }
1810#endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
1811
1812#ifdef _M4MP4W_MOOV_FIRST
1813
1814        mMp4FileDataPtr->videoTrackPtr->
1815            Chunk[mMp4FileDataPtr->videoTrackPtr->currentChunk] = (M4OSA_UChar
1816            *)M4OSA_32bitAlignedMalloc(mMp4FileDataPtr->videoTrackPtr->MaxChunkSize,
1817            M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->MaxChunkSize");
1818        ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->
1819            Chunk[mMp4FileDataPtr->videoTrackPtr->currentChunk]
1820        != M4OSA_NULL, M4ERR_ALLOC);
1821
1822#endif /*_M4MP4W_MOOV_FIRST*/
1823
1824    }
1825
1826    /*update leftSpaceInChunk, currentPos and currentChunkDur*/
1827    *leftSpaceInChunk = mMp4FileDataPtr->videoTrackPtr->MaxChunkSize;
1828    mMp4FileDataPtr->videoTrackPtr->currentPos = 0;
1829
1830#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
1831    /* check wether to use a new stsc or not */
1832
1833    if (mMp4FileDataPtr->videoTrackPtr->currentStsc > 0)
1834    {
1835        if ((mMp4FileDataPtr->videoTrackPtr->
1836            chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->
1837            currentStsc] & 0xFFF) != (mMp4FileDataPtr->videoTrackPtr->
1838            chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentStsc
1839            - 1] & 0xFFF))
1840            mMp4FileDataPtr->videoTrackPtr->currentStsc += 1;
1841    }
1842    else
1843        mMp4FileDataPtr->videoTrackPtr->currentStsc += 1;
1844
1845    /* max nb of chunk is now dynamic */
1846    if (mMp4FileDataPtr->videoTrackPtr->currentStsc
1847        + 3 > M4MP4W_CHUNK_ALLOC_NB)
1848    {
1849        M4OSA_TRACE1_0("M4MP4W_newVideoChunk : video stsc table is full");
1850        return M4WAR_MP4W_OVERSIZE;
1851    }
1852
1853    /* set nb of samples in the new chunk to 0 */
1854    mMp4FileDataPtr->videoTrackPtr->
1855        chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentStsc] =
1856        0 + (mMp4FileDataPtr->videoTrackPtr->currentChunk << 12);
1857
1858#else
1859    /*set nb of samples in the new chunk to 0*/
1860
1861    mMp4FileDataPtr->videoTrackPtr->
1862        chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] = 0;
1863
1864#endif
1865
1866    /*set time of the new chunk to lastCTS (for initialization, but updated further to the
1867    CTS of the last sample in the chunk)*/
1868
1869    mMp4FileDataPtr->videoTrackPtr->
1870        chunkTimeMsTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
1871        (M4OSA_UInt32)(mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS
1872        * scale_video);
1873
1874    return err;
1875}
1876
1877/*******************************************************************************/
1878M4OSA_ERR M4MP4W_startAU( M4OSA_Context context, M4SYS_StreamID streamID,
1879                         M4SYS_AccessUnit *auPtr )
1880/*******************************************************************************/
1881{
1882    M4OSA_ERR err = M4NO_ERROR;
1883
1884    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
1885
1886    M4OSA_UInt32 leftSpaceInChunk;
1887    M4MP4W_Time32 chunkDurMs;
1888
1889    M4OSA_Double scale_audio;
1890    M4OSA_Double scale_video;
1891
1892    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
1893    ERR_CHECK(auPtr != M4OSA_NULL, M4ERR_PARAMETER);
1894
1895    M4OSA_TRACE2_0("----- M4MP4W_startAU -----");
1896
1897    /*check macro state*/
1898    ERR_CHECK((mMp4FileDataPtr->state == M4MP4W_writing), M4ERR_STATE);
1899
1900    if (streamID == AudioStreamID) /*audio stream*/
1901    {
1902        M4OSA_TRACE2_0("M4MP4W_startAU -> audio");
1903
1904        scale_audio =
1905            1000.0 / mMp4FileDataPtr->audioTrackPtr->CommonData.timescale;
1906
1907        /*audio microstate*/
1908        ERR_CHECK((mMp4FileDataPtr->audioTrackPtr->microState
1909            == M4MP4W_writing), M4ERR_STATE);
1910        mMp4FileDataPtr->audioTrackPtr->microState = M4MP4W_writing_startAU;
1911
1912        leftSpaceInChunk = mMp4FileDataPtr->audioTrackPtr->MaxChunkSize
1913            - mMp4FileDataPtr->audioTrackPtr->currentPos;
1914
1915        M4OSA_TRACE2_2("audio %d  %d",
1916            mMp4FileDataPtr->audioTrackPtr->currentPos, leftSpaceInChunk);
1917
1918        chunkDurMs =
1919            (M4OSA_UInt32)(( mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS
1920            * scale_audio) - mMp4FileDataPtr->audioTrackPtr->
1921            chunkTimeMsTable[mMp4FileDataPtr->audioTrackPtr->
1922            currentChunk]);
1923
1924        if ((leftSpaceInChunk < mMp4FileDataPtr->audioTrackPtr->MaxAUSize)
1925            || (( mMp4FileDataPtr->InterleaveDur != 0)
1926            && (chunkDurMs >= mMp4FileDataPtr->InterleaveDur)))
1927        {
1928#ifdef _M4MP4W_UNBUFFERED_VIDEO
1929            /* only if there is at least 1 video sample in the chunk */
1930
1931            if ((mMp4FileDataPtr->videoTrackPtr != M4OSA_NULL)
1932                && (mMp4FileDataPtr->videoTrackPtr->currentPos > 0))
1933            {
1934                /* close the opened video chunk before creating a new audio one */
1935                err = M4MP4W_newVideoChunk(context, &leftSpaceInChunk);
1936
1937                if (err != M4NO_ERROR)
1938                    return err;
1939            }
1940
1941#endif
1942            /* not enough space in current chunk: create a new one */
1943
1944            err = M4MP4W_newAudioChunk(context, &leftSpaceInChunk);
1945
1946            if (err != M4NO_ERROR)
1947                return err;
1948        }
1949
1950        auPtr->size = leftSpaceInChunk;
1951
1952#ifdef _M4MP4W_MOOV_FIRST
1953
1954        auPtr->dataAddress = (M4OSA_MemAddr32)(mMp4FileDataPtr->audioTrackPtr->
1955            Chunk[mMp4FileDataPtr->audioTrackPtr->currentChunk]
1956        + mMp4FileDataPtr->audioTrackPtr->currentPos);
1957
1958#else
1959
1960        auPtr->dataAddress =
1961            (M4OSA_MemAddr32)(mMp4FileDataPtr->audioTrackPtr->Chunk[0]
1962        + mMp4FileDataPtr->audioTrackPtr->currentPos);
1963
1964#endif                                   /*_M4MP4W_MOOV_FIRST*/
1965
1966    }
1967    else if (streamID == VideoStreamID) /*video stream*/
1968    {
1969        M4OSA_TRACE2_0("M4MP4W_startAU -> video");
1970
1971        scale_video =
1972            1000.0 / mMp4FileDataPtr->videoTrackPtr->CommonData.timescale;
1973
1974        /*video microstate*/
1975        ERR_CHECK((mMp4FileDataPtr->videoTrackPtr->microState
1976            == M4MP4W_writing), M4ERR_STATE);
1977        mMp4FileDataPtr->videoTrackPtr->microState = M4MP4W_writing_startAU;
1978
1979        leftSpaceInChunk = mMp4FileDataPtr->videoTrackPtr->MaxChunkSize
1980            - mMp4FileDataPtr->videoTrackPtr->currentPos;
1981
1982        chunkDurMs =
1983            (M4OSA_UInt32)(( mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS
1984            * scale_video) - mMp4FileDataPtr->videoTrackPtr->
1985            chunkTimeMsTable[mMp4FileDataPtr->videoTrackPtr->
1986            currentChunk]);
1987
1988#ifdef _M4MP4W_UNBUFFERED_VIDEO
1989
1990        leftSpaceInChunk = mMp4FileDataPtr->videoTrackPtr->MaxChunkSize;
1991
1992#endif
1993
1994        M4OSA_TRACE2_2("video %d  %d",
1995            mMp4FileDataPtr->videoTrackPtr->currentPos, leftSpaceInChunk);
1996
1997        if (( leftSpaceInChunk < mMp4FileDataPtr->videoTrackPtr->MaxAUSize)
1998            || (( mMp4FileDataPtr->InterleaveDur != 0)
1999            && (chunkDurMs >= mMp4FileDataPtr->InterleaveDur))
2000#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2001
2002            || (( mMp4FileDataPtr->videoTrackPtr->MaxAUperChunk != 0)
2003            && (( mMp4FileDataPtr->videoTrackPtr->
2004            chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->
2005            currentStsc] & 0xFFF)
2006            == mMp4FileDataPtr->videoTrackPtr->MaxAUperChunk))
2007
2008#endif
2009
2010            )
2011        {
2012            /*not enough space in current chunk: create a new one*/
2013            err = M4MP4W_newVideoChunk(context, &leftSpaceInChunk);
2014
2015            if (err != M4NO_ERROR)
2016                return err;
2017        }
2018
2019        M4OSA_TRACE2_3("startAU: size 0x%x pos 0x%x chunk %u", auPtr->size,
2020            mMp4FileDataPtr->videoTrackPtr->currentPos,
2021            mMp4FileDataPtr->videoTrackPtr->currentChunk);
2022
2023        M4OSA_TRACE3_1("adr = 0x%p", auPtr->dataAddress);
2024
2025        if (auPtr->dataAddress)
2026        {
2027            M4OSA_TRACE3_3(" data = %08X %08X %08X", auPtr->dataAddress[0],
2028                auPtr->dataAddress[1], auPtr->dataAddress[2]);
2029        }
2030
2031        auPtr->size = leftSpaceInChunk;
2032#ifdef _M4MP4W_MOOV_FIRST
2033
2034        if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
2035            == M4SYS_kH264)
2036            auPtr->dataAddress =
2037            (M4OSA_MemAddr32)(mMp4FileDataPtr->videoTrackPtr->
2038            Chunk[mMp4FileDataPtr->videoTrackPtr->currentChunk]
2039        + mMp4FileDataPtr->videoTrackPtr->currentPos + 4);
2040        else
2041            auPtr->dataAddress =
2042            (M4OSA_MemAddr32)(mMp4FileDataPtr->videoTrackPtr->
2043            Chunk[mMp4FileDataPtr->videoTrackPtr->currentChunk]
2044        + mMp4FileDataPtr->videoTrackPtr->currentPos);
2045
2046#else
2047#ifdef _M4MP4W_UNBUFFERED_VIDEO
2048
2049        if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
2050            == M4SYS_kH264)
2051            auPtr->dataAddress =
2052            (M4OSA_MemAddr32)(mMp4FileDataPtr->videoTrackPtr->Chunk[0] + 4);
2053        else
2054            auPtr->dataAddress =
2055            (M4OSA_MemAddr32)(mMp4FileDataPtr->videoTrackPtr->Chunk[0]);
2056
2057#else
2058
2059        if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
2060            == M4SYS_kH264)
2061            auPtr->dataAddress =
2062            (M4OSA_MemAddr32)(mMp4FileDataPtr->videoTrackPtr->Chunk[0]
2063        + mMp4FileDataPtr->videoTrackPtr->currentPos
2064            + 4); /* In H264, we must start by the length of the NALU, coded in 4 bytes */
2065        else
2066            auPtr->dataAddress =
2067            (M4OSA_MemAddr32)(mMp4FileDataPtr->videoTrackPtr->Chunk[0]
2068        + mMp4FileDataPtr->videoTrackPtr->currentPos);
2069
2070#endif /*_M4MP4W_UNBUFFERED_VIDEO*/
2071
2072#endif /*_M4MP4W_MOOV_FIRST*/
2073
2074    }
2075    else
2076        return M4ERR_BAD_STREAM_ID;
2077
2078    M4OSA_TRACE1_3("M4MPW_startAU: start address:%p, size:%lu, stream:%d",
2079        auPtr->dataAddress, auPtr->size, streamID);
2080
2081    return err;
2082}
2083
2084/*******************************************************************************/
2085M4OSA_ERR M4MP4W_processAU( M4OSA_Context context, M4SYS_StreamID streamID,
2086                           M4SYS_AccessUnit *auPtr )
2087/*******************************************************************************/
2088{
2089    M4OSA_ERR err = M4NO_ERROR;
2090    M4MP4W_Time32 delta;
2091    M4MP4W_Time32 lastSampleDur;
2092    M4OSA_UInt32 i;
2093    /*expectedSize is the max filesize to forecast when adding a new AU:*/
2094    M4OSA_UInt32 expectedSize =
2095        32; /*initialized with an estimation of the max metadata space needed for an AU.*/
2096    M4OSA_Double scale_audio = 0.0;
2097    M4OSA_Double scale_video = 0.0;
2098
2099    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
2100    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
2101
2102    /*check macro state*/
2103    ERR_CHECK((mMp4FileDataPtr->state == M4MP4W_writing), M4ERR_STATE);
2104
2105    M4OSA_TRACE2_0("M4MP4W_processAU");
2106
2107    if (streamID == AudioStreamID)
2108        scale_audio =
2109        1000.0 / mMp4FileDataPtr->audioTrackPtr->CommonData.timescale;
2110
2111    if (streamID == VideoStreamID)
2112        scale_video =
2113        1000.0 / mMp4FileDataPtr->videoTrackPtr->CommonData.timescale;
2114
2115    /* PL 27/10/2008: after the resurgence of the AAC 128 bug, I added a debug check that
2116     the encoded data didn't overflow the available space in the AU */
2117
2118    switch( streamID )
2119    {
2120        case AudioStreamID:
2121            M4OSA_DEBUG_IF1(auPtr->size
2122                + mMp4FileDataPtr->audioTrackPtr->currentPos
2123            > mMp4FileDataPtr->audioTrackPtr->MaxChunkSize,
2124            M4ERR_CONTEXT_FAILED,
2125            "Uh oh. Buffer overflow in the writer. Abandon ship!");
2126            M4OSA_DEBUG_IF2(auPtr->size
2127                > mMp4FileDataPtr->audioTrackPtr->MaxAUSize,
2128                M4ERR_CONTEXT_FAILED,
2129                "Oops. An AU went over the declared Max AU size.\
2130                 You might wish to investigate that.");
2131            break;
2132
2133        case VideoStreamID:
2134            M4OSA_DEBUG_IF1(auPtr->size
2135                + mMp4FileDataPtr->videoTrackPtr->currentPos
2136                    > mMp4FileDataPtr->videoTrackPtr->MaxChunkSize,
2137                    M4ERR_CONTEXT_FAILED,
2138                    "Uh oh. Buffer overflow in the writer. Abandon ship!");
2139            M4OSA_DEBUG_IF2(auPtr->size
2140                    > mMp4FileDataPtr->videoTrackPtr->MaxAUSize,
2141                    M4ERR_CONTEXT_FAILED,
2142                    "Oops. An AU went over the declared Max AU size.\
2143                     You might wish to investigate that.");
2144            break;
2145    }
2146
2147    /*only if not in the case audio with estimateAudioSize
2148    (else, size already estimated at this point)*/
2149    if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_FALSE)
2150        || (streamID == VideoStreamID))
2151    {
2152        /*check filesize if needed*/
2153        if (mMp4FileDataPtr->MaxFileSize != 0)
2154        {
2155            expectedSize += mMp4FileDataPtr->filesize + auPtr->size;
2156
2157            if ((streamID == VideoStreamID)
2158                && (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
2159                == M4SYS_kH264))
2160            {
2161                expectedSize += 4;
2162            }
2163
2164            if (expectedSize > mMp4FileDataPtr->MaxFileSize)
2165            {
2166                M4OSA_TRACE1_0("processAU : !! FILESIZE EXCEEDED !!");
2167
2168                /* patch for autostop is MaxFileSize exceeded */
2169                M4OSA_TRACE1_0("M4MP4W_processAU : stop at targeted filesize");
2170                return M4WAR_MP4W_OVERSIZE;
2171            }
2172        }
2173    }
2174
2175    /*case audioMsStopTime has already been set during video processing,
2176     and now check it for audio*/
2177    if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_TRUE)
2178        && (streamID == AudioStreamID))
2179    {
2180        if (mMp4FileDataPtr->audioMsStopTime <= (auPtr->CTS *scale_audio))
2181        {
2182            /* bugfix: if a new chunk was just created, cancel it before to close */
2183            if ((mMp4FileDataPtr->audioTrackPtr->currentChunk != 0)
2184                && (mMp4FileDataPtr->audioTrackPtr->currentPos == 0))
2185            {
2186                mMp4FileDataPtr->audioTrackPtr->currentChunk--;
2187            }
2188            M4OSA_TRACE1_0("M4MP4W_processAU : audio stop time reached");
2189            return M4WAR_MP4W_OVERSIZE;
2190        }
2191    }
2192
2193    if (streamID == AudioStreamID) /*audio stream*/
2194    {
2195        M4OSA_TRACE2_0("M4MP4W_processAU -> audio");
2196
2197        /*audio microstate*/
2198        ERR_CHECK((mMp4FileDataPtr->audioTrackPtr->microState
2199            == M4MP4W_writing_startAU), M4ERR_STATE);
2200        mMp4FileDataPtr->audioTrackPtr->microState = M4MP4W_writing;
2201
2202        mMp4FileDataPtr->audioTrackPtr->currentPos += auPtr->size;
2203        /* Warning: time conversion cast 64to32! */
2204        delta = (M4MP4W_Time32)auPtr->CTS
2205            - mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS;
2206
2207        /* DEBUG stts entries which are equal to 0 */
2208        M4OSA_TRACE2_1("A_DELTA = %ld\n", delta);
2209
2210        if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb
2211            == 0) /*test if first AU*/
2212        {
2213            /*set au size*/
2214            mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize = auPtr->size;
2215
2216            /*sample duration is a priori constant in audio case, */
2217            /*but if an Au at least has different size, a stsz table will be created */
2218
2219            /*mMp4FileDataPtr->audioTrackPtr->sampleDuration = delta; */
2220            /*TODO test sample duration? (should be 20ms in AMR8, 160 tics with timescale 8000) */
2221        }
2222        else
2223        {
2224            /*check if au size is constant (audio) */
2225            /*0 sample size means non constant size*/
2226            if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize != 0)
2227            {
2228                if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize
2229                    != auPtr->size)
2230                {
2231                    /*first AU with different size => non constant size => STSZ table needed*/
2232                    /*computation of the nb of block of size M4MP4W_STSZ_ALLOC_SIZE to allocate*/
2233                    mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedStszBlocks =
2234                        1 + mMp4FileDataPtr->audioTrackPtr->
2235                        CommonData.sampleNb
2236                        * 4 / M4MP4W_STSZ_AUDIO_ALLOC_SIZE;
2237                    mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ =
2238                        (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(
2239                        mMp4FileDataPtr->audioTrackPtr->
2240                        nbOfAllocatedStszBlocks
2241                        * M4MP4W_STSZ_AUDIO_ALLOC_SIZE,
2242                        M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->TABLE_STSZ");
2243                    ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ
2244                        != M4OSA_NULL, M4ERR_ALLOC);
2245
2246                    for ( i = 0;
2247                        i < mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
2248                        i++ )
2249                    {
2250                        mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ[i] =
2251                            mMp4FileDataPtr->audioTrackPtr->
2252                            CommonData.sampleSize;
2253                    }
2254                    mMp4FileDataPtr->audioTrackPtr->
2255                        TABLE_STSZ[mMp4FileDataPtr->audioTrackPtr->
2256                        CommonData.sampleNb] = auPtr->size;
2257                    mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize =
2258                        0; /*used as a flag in that case*/
2259                    /*more bytes in the file in that case:*/
2260                    if (mMp4FileDataPtr->estimateAudioSize == M4OSA_FALSE)
2261                        mMp4FileDataPtr->filesize +=
2262                        4 * mMp4FileDataPtr->audioTrackPtr->
2263                        CommonData.sampleNb;
2264                }
2265            }
2266            /*else table already exists*/
2267            else
2268            {
2269#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2270
2271                if (4 *(mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb + 3)
2272                    >= mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedStszBlocks
2273                    *M4MP4W_STSZ_AUDIO_ALLOC_SIZE)
2274                {
2275                    M4OSA_TRACE1_0(
2276                        "M4MP4W_processAU : audio stsz table is full");
2277                    return M4WAR_MP4W_OVERSIZE;
2278                }
2279
2280#else
2281
2282                if (4 *mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb
2283                    >= mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedStszBlocks
2284                    *M4MP4W_STSZ_AUDIO_ALLOC_SIZE)
2285                {
2286                    mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedStszBlocks +=
2287                        1;
2288                    mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ =
2289                        (M4OSA_UInt32 *)M4MP4W_realloc(
2290                        (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->
2291                        TABLE_STSZ, ( mMp4FileDataPtr->audioTrackPtr->
2292                        nbOfAllocatedStszBlocks - 1)
2293                        * M4MP4W_STSZ_AUDIO_ALLOC_SIZE,
2294                        mMp4FileDataPtr->audioTrackPtr->
2295                        nbOfAllocatedStszBlocks
2296                        * M4MP4W_STSZ_AUDIO_ALLOC_SIZE);
2297                    ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ
2298                        != M4OSA_NULL, M4ERR_ALLOC);
2299                }
2300
2301#endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
2302
2303                mMp4FileDataPtr->audioTrackPtr->
2304                    TABLE_STSZ[mMp4FileDataPtr->audioTrackPtr->
2305                    CommonData.sampleNb] = auPtr->size;
2306
2307                if (mMp4FileDataPtr->estimateAudioSize == M4OSA_FALSE)
2308                    mMp4FileDataPtr->filesize += 4;
2309            }
2310        }
2311
2312        if (delta > mMp4FileDataPtr->audioTrackPtr->sampleDuration)
2313        {
2314            /* keep track of real sample duration*/
2315            mMp4FileDataPtr->audioTrackPtr->sampleDuration = delta;
2316        }
2317
2318        if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb
2319            == 0) /*test if first AU*/
2320        {
2321            mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[0] = 1;
2322            mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[1] = 0;
2323            mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb = 1;
2324            mMp4FileDataPtr->filesize += 8;
2325        }
2326        else if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb
2327            == 1) /*test if second AU*/
2328        {
2329#ifndef DUPLICATE_STTS_IN_LAST_AU
2330
2331            mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[0] += 1;
2332
2333#endif /*DUPLICATE_STTS_IN_LAST_AU*/
2334
2335            mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[1] = delta;
2336            mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb += 1;
2337            mMp4FileDataPtr->filesize += 8;
2338        }
2339        else
2340        {
2341            /*retrieve last sample delta*/
2342            lastSampleDur = mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2
2343                * (mMp4FileDataPtr->audioTrackPtr->
2344                CommonData.sttsTableEntryNb - 1) - 1];
2345
2346#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2347
2348            if (8 *(mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb
2349                + 3) >= mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedSttsBlocks
2350                *M4MP4W_STTS_AUDIO_ALLOC_SIZE)
2351            {
2352                M4OSA_TRACE1_0("M4MP4W_processAU : audio stts table is full");
2353                return M4WAR_MP4W_OVERSIZE;
2354            }
2355
2356#else
2357
2358            if (8 *mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb
2359                >= mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedSttsBlocks
2360                *M4MP4W_STTS_AUDIO_ALLOC_SIZE)
2361            {
2362                mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedSttsBlocks += 1;
2363                mMp4FileDataPtr->audioTrackPtr->TABLE_STTS =
2364                    (M4OSA_UInt32 *)M4MP4W_realloc(
2365                    (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->
2366                    TABLE_STTS, ( mMp4FileDataPtr->audioTrackPtr->
2367                    nbOfAllocatedSttsBlocks
2368                    - 1) * M4MP4W_STTS_AUDIO_ALLOC_SIZE,
2369                    mMp4FileDataPtr->audioTrackPtr->
2370                    nbOfAllocatedSttsBlocks
2371                    * M4MP4W_STTS_AUDIO_ALLOC_SIZE);
2372                ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->TABLE_STTS
2373                    != M4OSA_NULL, M4ERR_ALLOC);
2374            }
2375
2376#endif                                   /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
2377
2378            if (delta != lastSampleDur) /*new entry in the table*/
2379            {
2380                mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2 *(
2381                    mMp4FileDataPtr->audioTrackPtr->
2382                    CommonData.sttsTableEntryNb - 1)] = 1;
2383                mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2 *(
2384                    mMp4FileDataPtr->audioTrackPtr->
2385                    CommonData.sttsTableEntryNb - 1) + 1] = delta;
2386                mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb +=
2387                    1;
2388                mMp4FileDataPtr->filesize += 8;
2389            }
2390            else
2391            {
2392                /*increase of 1 the number of consecutive AUs with same duration*/
2393                mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2 *(
2394                    mMp4FileDataPtr->audioTrackPtr->
2395                    CommonData.sttsTableEntryNb - 1) - 2] += 1;
2396            }
2397        }
2398        mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb += 1;
2399#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2400
2401        mMp4FileDataPtr->audioTrackPtr->
2402            chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->currentStsc] +=
2403            1;
2404
2405#else
2406
2407        mMp4FileDataPtr->audioTrackPtr->
2408            chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] +=
2409            1;
2410
2411#endif
2412        /* Warning: time conversion cast 64to32! */
2413
2414        mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS =
2415            (M4MP4W_Time32)auPtr->CTS;
2416    }
2417    else if (streamID == VideoStreamID) /*video stream*/
2418    {
2419        M4OSA_TRACE2_0("M4MP4W_processAU -> video");
2420
2421        /* In h264, the size of the AU must be added to the data */
2422        if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
2423            == M4SYS_kH264)
2424        {
2425            /* Add the size of the NALU in BE */
2426            M4OSA_MemAddr8 pTmpDataAddress = M4OSA_NULL;
2427            auPtr->dataAddress -= 1;
2428            pTmpDataAddress = (M4OSA_MemAddr8)auPtr->dataAddress;
2429
2430            // bit manipulation
2431            *pTmpDataAddress++ = (M4OSA_UInt8)((auPtr->size >> 24) & 0x000000FF);
2432            *pTmpDataAddress++ = (M4OSA_UInt8)((auPtr->size >> 16) & 0x000000FF);
2433            *pTmpDataAddress++ = (M4OSA_UInt8)((auPtr->size >> 8)  & 0x000000FF);
2434            *pTmpDataAddress++ = (M4OSA_UInt8)((auPtr->size)       & 0x000000FF);
2435
2436            auPtr->size += 4;
2437        }
2438
2439        /*video microstate*/
2440        ERR_CHECK((mMp4FileDataPtr->videoTrackPtr->microState
2441            == M4MP4W_writing_startAU), M4ERR_STATE);
2442        mMp4FileDataPtr->videoTrackPtr->microState = M4MP4W_writing;
2443
2444#ifdef _M4MP4W_UNBUFFERED_VIDEO
2445        /* samples are written to file now */
2446
2447        err = M4MP4W_putBlock((M4OSA_UChar *)auPtr->dataAddress, auPtr->size,
2448            mMp4FileDataPtr->fileWriterFunctions,
2449            mMp4FileDataPtr->fileWriterContext);
2450
2451        if (err != M4NO_ERROR)
2452        {
2453            M4OSA_FilePosition temp = mMp4FileDataPtr->absoluteCurrentPos
2454                + mMp4FileDataPtr->videoTrackPtr->currentPos;
2455            M4OSA_TRACE2_1(
2456                "M4MP4W_processAU: putBlock error when writing unbuffered video sample: %#X",
2457                err);
2458            /* Ouch, we got an error writing to the file, but we need to properly react so that
2459             the state is still consistent and we can properly close the file so that what has
2460              been recorded so far is not lost. Yay error recovery! */
2461
2462            /* First, we do not know where we are in the file. Put us back at where we were before
2463            attempting to write the data. That way, we're consistent with the chunk and sample
2464             state data.absoluteCurrentPos is only updated for chunks, it points to the beginning
2465             of the chunk,therefore we need to add videoTrackPtr->currentPos to know where we
2466             were in the file. */
2467            err = mMp4FileDataPtr->fileWriterFunctions->seek(
2468                mMp4FileDataPtr->fileWriterContext,
2469                M4OSA_kFileSeekBeginning, &temp);
2470
2471            M4OSA_TRACE2_3(
2472                "Backtracking to position 0x%08X, seek returned %d and position %08X",
2473                mMp4FileDataPtr->absoluteCurrentPos
2474                + mMp4FileDataPtr->videoTrackPtr->currentPos, err, temp);
2475
2476            /* Then, do not update any info whatsoever in the writing state. This will have the
2477             consequence that it will be as if the sample has never been written, so the chunk
2478             will be merely closed after the previous sample (the sample we attempted to write
2479             here is lost). */
2480
2481            /* And lastly (for here), return that we've reached the limit of available space.
2482             We don't care about the error originally returned by putBlock. */
2483
2484            return M4WAR_MP4W_OVERSIZE;
2485        }
2486
2487#endif
2488
2489        mMp4FileDataPtr->videoTrackPtr->currentPos += auPtr->size;
2490
2491        /* Warning: time conversion cast 64to32! */
2492        delta = (M4MP4W_Time32)auPtr->CTS
2493            - mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS;
2494
2495        /* DEBUG stts entries which are equal to 0 */
2496        M4OSA_TRACE2_1("V_DELTA = %ld\n", delta);
2497
2498#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2499
2500        if (2 *(mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb + 3)
2501            >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks
2502            *M4MP4W_STSZ_ALLOC_SIZE)
2503        {
2504            M4OSA_TRACE1_0("M4MP4W_processAU : video stsz table is full");
2505            return M4WAR_MP4W_OVERSIZE;
2506        }
2507
2508        mMp4FileDataPtr->videoTrackPtr->
2509            TABLE_STSZ[mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb] =
2510            (M4OSA_UInt16)auPtr->size;
2511        mMp4FileDataPtr->filesize += 4;
2512
2513#else
2514
2515        if (4 *mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
2516            >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks
2517            *M4MP4W_STSZ_ALLOC_SIZE)
2518        {
2519            mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks += 1;
2520
2521            mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ =
2522                (M4OSA_UInt32 *)M4MP4W_realloc(
2523                (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ,
2524                ( mMp4FileDataPtr->videoTrackPtr->
2525                nbOfAllocatedStszBlocks
2526                - 1) * M4MP4W_STSZ_ALLOC_SIZE,
2527                mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks
2528                * M4MP4W_STSZ_ALLOC_SIZE);
2529
2530            ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ != M4OSA_NULL,
2531                M4ERR_ALLOC);
2532        }
2533
2534        mMp4FileDataPtr->videoTrackPtr->
2535            TABLE_STSZ[mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb] =
2536            auPtr->size;
2537        mMp4FileDataPtr->filesize += 4;
2538
2539#endif
2540
2541        if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
2542            == 0) /*test if first AU*/
2543        {
2544#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2545
2546            M4MP4W_put32_Lo(&mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0], 1);
2547            M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0], 0);
2548
2549#else
2550
2551            mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0] = 1;
2552            mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] = 0;
2553
2554#endif
2555
2556            mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb = 1;
2557            mMp4FileDataPtr->filesize += 8;
2558        }
2559        else if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
2560            == 1 ) /*test if second AU*/
2561        {
2562#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2563
2564            M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0],
2565                (M4OSA_UInt16)delta);
2566
2567#else
2568
2569            mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] = delta;
2570
2571#endif
2572
2573        }
2574        else
2575        {
2576            /*retrieve last sample delta*/
2577#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2578
2579            lastSampleDur = M4MP4W_get32_Hi(&mMp4FileDataPtr->videoTrackPtr->
2580                TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
2581                CommonData.sttsTableEntryNb - 1]);
2582
2583            if (4 *(mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
2584                + 3) >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks
2585                *M4MP4W_STTS_ALLOC_SIZE)
2586            {
2587                M4OSA_TRACE1_0("M4MP4W_processAU : video stts table is full");
2588                return M4WAR_MP4W_OVERSIZE;
2589            }
2590
2591#else
2592
2593            lastSampleDur = mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
2594                * (mMp4FileDataPtr->videoTrackPtr->
2595                CommonData.sttsTableEntryNb - 1) + 1];
2596
2597            if (8 *mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
2598                >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks
2599                *M4MP4W_STTS_ALLOC_SIZE)
2600            {
2601                mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks += 1;
2602                mMp4FileDataPtr->videoTrackPtr->TABLE_STTS =
2603                    (M4OSA_UInt32 *)M4MP4W_realloc(
2604                    (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
2605                    TABLE_STTS, ( mMp4FileDataPtr->videoTrackPtr->
2606                    nbOfAllocatedSttsBlocks
2607                    - 1) * M4MP4W_STTS_ALLOC_SIZE,
2608                    mMp4FileDataPtr->videoTrackPtr->
2609                    nbOfAllocatedSttsBlocks
2610                    * M4MP4W_STTS_ALLOC_SIZE);
2611                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STTS
2612                    != M4OSA_NULL, M4ERR_ALLOC);
2613            }
2614
2615#endif                                   /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
2616
2617            if (delta != lastSampleDur) /*new entry in the table*/
2618            {
2619#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2620
2621                M4MP4W_put32_Lo(&mMp4FileDataPtr->videoTrackPtr->
2622                    TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
2623                    CommonData.sttsTableEntryNb], 1);
2624                M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->
2625                    TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
2626                    CommonData.sttsTableEntryNb], (M4OSA_UInt16)delta);
2627
2628#else
2629
2630                mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2 *(
2631                    mMp4FileDataPtr->videoTrackPtr->
2632                    CommonData.sttsTableEntryNb)] = 1;
2633                mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
2634                    *(mMp4FileDataPtr->videoTrackPtr->
2635                    CommonData.sttsTableEntryNb)+1] = delta;
2636
2637#endif
2638
2639                mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb +=
2640                    1;
2641                mMp4FileDataPtr->filesize += 8;
2642            }
2643            else
2644            {
2645                /*increase of 1 the number of consecutive AUs with same duration*/
2646#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2647
2648                mMp4FileDataPtr->videoTrackPtr->
2649                    TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
2650                    CommonData.sttsTableEntryNb - 1] += 1;
2651
2652#else
2653
2654                mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2 *(
2655                    mMp4FileDataPtr->videoTrackPtr->
2656                    CommonData.sttsTableEntryNb - 1)] += 1;
2657
2658#endif
2659
2660            }
2661        }
2662
2663        mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb += 1;
2664#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2665
2666        mMp4FileDataPtr->videoTrackPtr->
2667            chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentStsc] +=
2668            1;
2669
2670#else
2671
2672        mMp4FileDataPtr->videoTrackPtr->
2673            chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] +=
2674            1;
2675
2676#endif
2677
2678        if (auPtr->attribute == AU_RAP)
2679        {
2680#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2681
2682            if (4 *(mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb + 3)
2683                >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks
2684                *M4MP4W_STSS_ALLOC_SIZE)
2685            {
2686                M4OSA_TRACE1_0("M4MP4W_processAU : video stss table is full");
2687                return M4WAR_MP4W_OVERSIZE;
2688            }
2689
2690#else
2691
2692            if (4 *mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb
2693                >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks
2694                *M4MP4W_STSS_ALLOC_SIZE)
2695            {
2696                mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks += 1;
2697                mMp4FileDataPtr->videoTrackPtr->TABLE_STSS =
2698                    (M4OSA_UInt32 *)M4MP4W_realloc(
2699                    (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
2700                    TABLE_STSS, ( mMp4FileDataPtr->videoTrackPtr->
2701                    nbOfAllocatedStssBlocks
2702                    - 1) * M4MP4W_STSS_ALLOC_SIZE,
2703                    mMp4FileDataPtr->videoTrackPtr->
2704                    nbOfAllocatedStssBlocks
2705                    * M4MP4W_STSS_ALLOC_SIZE);
2706                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STSS
2707                    != M4OSA_NULL, M4ERR_ALLOC);
2708            }
2709
2710#endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
2711
2712            mMp4FileDataPtr->videoTrackPtr->
2713                TABLE_STSS[mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb] =
2714                mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb;
2715            mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb += 1;
2716            mMp4FileDataPtr->filesize += 4;
2717        }
2718
2719        /* Warning: time conversion cast 64to32! */
2720        mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS =
2721            (M4MP4W_Time32)auPtr->CTS;
2722    }
2723    else
2724        return M4ERR_BAD_STREAM_ID;
2725
2726    /* I moved some state modification to after we know the sample has been written correctly. */
2727    if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_TRUE)
2728        && (streamID == VideoStreamID))
2729    {
2730        mMp4FileDataPtr->audioMsStopTime =
2731            (M4MP4W_Time32)(auPtr->CTS * scale_video);
2732    }
2733
2734    if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_FALSE)
2735        || (streamID == VideoStreamID))
2736    {
2737        /*update fileSize*/
2738        mMp4FileDataPtr->filesize += auPtr->size;
2739    }
2740
2741    if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_TRUE)
2742        && (streamID == VideoStreamID))
2743    {
2744        /*update filesize with estimated audio data that will be added later.    */
2745        /*Warning: Assumption is made that:                                     */
2746        /* - audio samples have constant size (e.g. no sid).                    */
2747        /* - max audio sample size has been set, and is the actual sample size. */
2748
2749        ERR_CHECK(mMp4FileDataPtr->audioMsChunkDur != 0,
2750            M4WAR_MP4W_NOT_EVALUABLE);
2751        mMp4FileDataPtr->filesize -=
2752            (M4OSA_UInt32)(( mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS
2753            * scale_video) * (0.05/*always 50 AMR samples per second*/
2754            *(M4OSA_Double)mMp4FileDataPtr->audioTrackPtr->MaxAUSize
2755            + 16/*additional data for a new chunk*/
2756            / (M4OSA_Double)mMp4FileDataPtr->audioMsChunkDur));
2757
2758        mMp4FileDataPtr->filesize += (M4OSA_UInt32)(( auPtr->CTS * scale_video)
2759            * (0.05/*always 50 AMR samples per second*/
2760            *(M4OSA_Double)mMp4FileDataPtr->audioTrackPtr->MaxAUSize
2761            + 16/*additional data for a new chunk*/
2762            / (M4OSA_Double)mMp4FileDataPtr->audioMsChunkDur));
2763    }
2764
2765    M4OSA_TRACE1_4("processAU : size 0x%x mode %d filesize %lu limit %lu",
2766        auPtr->size, auPtr->attribute, mMp4FileDataPtr->filesize,
2767        mMp4FileDataPtr->MaxFileSize);
2768
2769    return err;
2770}
2771
2772/*******************************************************************************/
2773M4OSA_ERR M4MP4W_closeWrite( M4OSA_Context context )
2774/*******************************************************************************/
2775{
2776    M4OSA_ERR err = M4NO_ERROR;
2777    M4OSA_ERR err2 = M4NO_ERROR, err3 = M4NO_ERROR;
2778
2779    /*Warning: test should be done here to ensure context->pContext is not M4OSA_NULL,
2780     but C is not C++...*/
2781    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
2782
2783    M4OSA_UChar camcoder_maj, camcoder_min, camcoder_rev; /*camcoder version*/
2784    M4OSA_Bool bAudio =
2785        (( mMp4FileDataPtr->hasAudio)
2786        && (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb
2787        != 0)); /*((mMp4FileDataPtr->audioTrackPtr != M4OSA_NULL) &&
2788                    (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb != 0));*/
2789    M4OSA_Bool bVideo =
2790        (( mMp4FileDataPtr->hasVideo)
2791        && (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
2792        != 0)); /*((mMp4FileDataPtr->videoTrackPtr != M4OSA_NULL) &&
2793                    (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb != 0));*/
2794    M4OSA_Bool bH263 = M4OSA_FALSE;
2795    M4OSA_Bool bH264 = M4OSA_FALSE;
2796    M4OSA_Bool bMP4V = M4OSA_FALSE;
2797    M4OSA_Bool bAAC = M4OSA_FALSE;
2798    M4OSA_Bool bEVRC = M4OSA_FALSE;
2799
2800    /*intermediate variables*/
2801    M4OSA_UInt32 A, B, N, AB4N;
2802
2803    /*Trak variables*/
2804    M4OSA_UInt32 a_trakId = AudioStreamID; /*     (audio=1)*/
2805    /* first trak offset is 32+moovSize, second equals 32+moovSize+1st_track_size*/
2806    M4OSA_UInt32 a_trakOffset = 32;
2807    M4OSA_UInt32 a_sttsSize = 24;          /* A (audio=24)*/
2808    M4OSA_UInt32 a_stszSize = 20;          /* B (audio=20)*/
2809    M4OSA_UInt32 a_trakSize = 402;         /*     (audio=402)*/
2810    M4OSA_UInt32 a_mdiaSize = 302;         /*     (audio=302)*/
2811    M4OSA_UInt32 a_minfSize = 229;         /*     (audio=229)*/
2812    M4OSA_UInt32 a_stblSize = 169;         /*     (audio=169)*/
2813    M4OSA_UInt32 a_stsdSize = 69;          /*     (audio=69 )*/
2814    M4OSA_UInt32 a_esdSize = 53;           /*     (audio=53 )*/
2815    M4OSA_UInt32 a_dataSize = 0;           /* temp: At the end, = currentPos*/
2816    M4MP4W_Time32 a_trakDuration = 0;      /* equals lastCTS*/
2817    M4MP4W_Time32 a_msTrakDuration = 0;
2818    M4OSA_UInt32 a_stscSize = 28;          /* 16+12*nbchunksaudio*/
2819    M4OSA_UInt32 a_stcoSize = 20;          /* 16+4*nbchunksaudio*/
2820
2821    M4OSA_UInt32 v_trakId = VideoStreamID; /* (video=2)*/
2822    /* first trak offset is 32+moovSize, second equals 32+moovSize+1st_track_size*/
2823    M4OSA_UInt32 v_trakOffset = 32;
2824    M4OSA_UInt32 v_sttsSize = 0;      /* A (video=16+8J)*/
2825    M4OSA_UInt32 v_stszSize = 0;      /* B (video=20+4K)*/
2826    M4OSA_UInt32 v_trakSize = 0; /* (h263=A+B+4N+426), (mp4v=A+B+dsi+4N+448) */
2827    M4OSA_UInt32 v_mdiaSize = 0; /* (h263=A+B+4N+326), (mp4v=A+B+dsi+4N+348) */
2828    M4OSA_UInt32 v_minfSize = 0; /* (h263=A+B+4N+253), (mp4v=A+B+dsi+4N+275) */
2829    M4OSA_UInt32 v_stblSize = 0; /* (h263=A+B+4N+189), (mp4v=A+B+dsi+4N+211) */
2830    M4OSA_UInt32 v_stsdSize = 0;      /* (h263=117)        , (mp4v=139+dsi    )*/
2831    M4OSA_UInt32 v_esdSize = 0;       /* (h263=101)        , (mp4v=153+dsi    )*/
2832    M4OSA_UInt32 v_dataSize = 0;      /* temp: At the end, = currentPos*/
2833    M4MP4W_Time32 v_trakDuration = 0; /* equals lastCTS*/
2834    M4MP4W_Time32 v_msTrakDuration = 0;
2835    M4OSA_UInt32 v_stscSize = 28;     /* 16+12*nbchunksvideo*/
2836    M4OSA_UInt32 v_stcoSize = 20;     /* 16+4*nbchunksvideo*/
2837
2838    /*video variables*/
2839    M4OSA_UInt32 v_stssSize = 0; /* 4*N+16     STSS*/
2840
2841    /*aac & mp4v temp variable*/
2842    M4OSA_UInt8 dsi = 0;
2843
2844    /*H264 variables*/
2845    M4OSA_UInt32 v_avcCSize = 0; /* dsi+15*/
2846
2847    /*MP4V variables*/
2848    M4OSA_UInt32 v_esdsSize = 0;        /* dsi+37*/
2849    M4OSA_UInt8 v_ESDescriptorSize =
2850        0; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
2851    M4OSA_UInt8 v_DCDescriptorSize = 0; /* dsi+15*/
2852
2853    /*AAC variables*/
2854    M4OSA_UInt32 a_esdsSize = 0;        /* dsi+37*/
2855    M4OSA_UInt8 a_ESDescriptorSize =
2856        0; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
2857    M4OSA_UInt8 a_DCDescriptorSize = 0; /* dsi+15*/
2858
2859    /*General variables*/
2860
2861    /* audio chunk size + video chunk size*/
2862    M4OSA_UInt32 mdatSize = 8;
2863    M4OSA_UInt32 moovSize = 116; /* 116 + 402(audio) +    (A+B+4N+426)(h263) or */
2864    /*                        (A+B+dsi+4N+448)(mp4v)    */
2865    M4OSA_UInt32 creationTime; /* C */
2866
2867    /*flag to set up the chunk interleave strategy*/
2868    M4OSA_Bool bInterleaveAV =
2869        (bAudio && bVideo && (mMp4FileDataPtr->InterleaveDur != 0));
2870
2871    M4OSA_Context fileWriterContext = mMp4FileDataPtr->fileWriterContext;
2872
2873    M4OSA_UInt32 i;
2874
2875    M4OSA_Double scale_audio = 0.0;
2876    M4OSA_Double scale_video = 0.0;
2877    M4MP4W_Time32 delta;
2878
2879#ifndef _M4MP4W_MOOV_FIRST
2880
2881    M4OSA_FilePosition moovPos, mdatPos;
2882
2883#endif /*_M4MP4W_MOOV_FIRST*/
2884
2885    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
2886
2887    /*macro state */
2888    mMp4FileDataPtr->state = M4MP4W_closed;
2889
2890    /*if no data !*/
2891    if ((!bAudio) && (!bVideo))
2892    {
2893        err = M4NO_ERROR; /*would be better to return a warning ?*/
2894        goto cleanup;
2895    }
2896
2897#ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
2898    /* Remove safety file to make room for what needs to be written out here
2899    (chunk flushing and moov). */
2900
2901    if (M4OSA_TRUE == mMp4FileDataPtr->cleanSafetyFile)
2902    {
2903        M4OSA_Context tempContext;
2904        err = mMp4FileDataPtr->fileWriterFunctions->openWrite(&tempContext,
2905            mMp4FileDataPtr->safetyFileUrl,
2906            M4OSA_kFileWrite | M4OSA_kFileCreate);
2907
2908        if (M4NO_ERROR != err)
2909            goto cleanup;
2910        err = mMp4FileDataPtr->fileWriterFunctions->closeWrite(tempContext);
2911
2912        if (M4NO_ERROR != err)
2913            goto cleanup;
2914        mMp4FileDataPtr->safetyFileUrl = M4OSA_NULL;
2915        mMp4FileDataPtr->cleanSafetyFile = M4OSA_FALSE;
2916    }
2917
2918#endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
2919
2920    if (bVideo)
2921    {
2922        if ((M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable)
2923            || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->chunkSizeTable)
2924            || (M4OSA_NULL
2925            == mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable)
2926            || (M4OSA_NULL
2927            == mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable)
2928            || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ)
2929            || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->TABLE_STTS)
2930            || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->TABLE_STSS))
2931        {
2932            mMp4FileDataPtr->fileWriterFunctions->closeWrite(
2933                fileWriterContext); /**< close the stream anyway */
2934            M4MP4W_freeContext(context); /**< Free the context content */
2935            return M4ERR_ALLOC;
2936        }
2937
2938        /*video microstate*/
2939        mMp4FileDataPtr->videoTrackPtr->microState = M4MP4W_closed;
2940
2941        /*current chunk is the last one and gives the total number of video chunks (-1)*/
2942        for ( i = 0; i < mMp4FileDataPtr->videoTrackPtr->currentChunk; i++ )
2943        {
2944            v_dataSize += mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i];
2945        }
2946
2947#ifndef _M4MP4W_MOOV_FIRST
2948#ifndef _M4MP4W_UNBUFFERED_VIDEO
2949        /*flush chunk*/
2950
2951        if (mMp4FileDataPtr->videoTrackPtr->currentPos > 0)
2952        {
2953            err = M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[0],
2954                mMp4FileDataPtr->videoTrackPtr->currentPos,
2955                mMp4FileDataPtr->fileWriterFunctions,
2956                mMp4FileDataPtr->fileWriterContext);
2957
2958            if (M4NO_ERROR != err)
2959                goto cleanup;
2960        }
2961
2962#endif
2963
2964        M4OSA_TRACE1_0("flush video | CLOSE");
2965        M4OSA_TRACE1_3("current chunk = %d  offset = 0x%x size = 0x%08X",
2966            mMp4FileDataPtr->videoTrackPtr->currentChunk,
2967            mMp4FileDataPtr->absoluteCurrentPos,
2968            mMp4FileDataPtr->videoTrackPtr->currentPos);
2969
2970        /*update chunk offset*/
2971        mMp4FileDataPtr->videoTrackPtr->
2972            chunkOffsetTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
2973            mMp4FileDataPtr->absoluteCurrentPos;
2974
2975        /*add chunk size to absoluteCurrentPos*/
2976        mMp4FileDataPtr->absoluteCurrentPos +=
2977            mMp4FileDataPtr->videoTrackPtr->currentPos;
2978#endif /*_M4MP4W_MOOV_FIRST*/
2979
2980        /*update last chunk size, and add this value to v_dataSize*/
2981
2982        mMp4FileDataPtr->videoTrackPtr->
2983            chunkSizeTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
2984            mMp4FileDataPtr->videoTrackPtr->currentPos;
2985        v_dataSize +=
2986            mMp4FileDataPtr->videoTrackPtr->currentPos; /*add last chunk size*/
2987
2988        v_trakDuration = mMp4FileDataPtr->videoTrackPtr->
2989            CommonData.lastCTS; /* equals lastCTS*/
2990
2991        /* bugfix: if a new chunk was just created, cancel it before to close */
2992        if ((mMp4FileDataPtr->videoTrackPtr->currentChunk != 0)
2993            && (mMp4FileDataPtr->videoTrackPtr->currentPos == 0))
2994        {
2995            mMp4FileDataPtr->videoTrackPtr->currentChunk--;
2996        }
2997#ifdef _M4MP4W_UNBUFFERED_VIDEO
2998
2999        if ((mMp4FileDataPtr->videoTrackPtr->
3000            chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->
3001            currentStsc] & 0xFFF) == 0)
3002        {
3003            mMp4FileDataPtr->videoTrackPtr->currentStsc--;
3004        }
3005
3006#endif /*_M4MP4W_UNBUFFERED_VIDEO*/
3007
3008        /* Last sample duration */
3009        /* If we have the file duration we use it, else we duplicate the last AU */
3010
3011        if (mMp4FileDataPtr->MaxFileDuration > 0)
3012        {
3013            /* use max file duration to calculate delta of last AU */
3014            delta = mMp4FileDataPtr->MaxFileDuration
3015                - mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS;
3016            v_trakDuration = mMp4FileDataPtr->MaxFileDuration;
3017
3018            if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb > 1)
3019            {
3020                /* if more than 1 frame, create a new stts entry (else already created) */
3021                mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb++;
3022            }
3023
3024#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3025
3026            M4MP4W_put32_Lo(&mMp4FileDataPtr->videoTrackPtr->
3027                TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
3028                CommonData.sttsTableEntryNb - 1], 1);
3029            M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->
3030                TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
3031                CommonData.sttsTableEntryNb - 1], delta);
3032
3033#else
3034
3035            mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
3036                *(mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
3037                - 1)] = 1;
3038            mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
3039                *(mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
3040                - 1) + 1] = delta;
3041
3042#endif
3043
3044        }
3045        else
3046        {
3047            /* duplicate the delta of the previous frame */
3048            if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb > 1)
3049            {
3050                /* if more than 1 frame, duplicate the stts entry (else already exists) */
3051#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3052
3053                v_trakDuration +=
3054                    M4MP4W_get32_Hi(&mMp4FileDataPtr->videoTrackPtr->
3055                    TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
3056                    CommonData.sttsTableEntryNb - 1]);
3057                mMp4FileDataPtr->videoTrackPtr->
3058                    TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
3059                    CommonData.sttsTableEntryNb - 1] += 1;
3060
3061#else
3062
3063                v_trakDuration += mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
3064                    * (mMp4FileDataPtr->videoTrackPtr->
3065                    CommonData.sttsTableEntryNb - 1) + 1];
3066                mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2 *(
3067                    mMp4FileDataPtr->videoTrackPtr->
3068                    CommonData.sttsTableEntryNb - 1)] += 1;
3069
3070#endif
3071
3072            }
3073            else
3074            {
3075                M4OSA_TRACE1_0("M4MP4W_closeWrite : ! videoTrackPtr,\
3076                     cannot know the duration of the unique AU !");
3077                /* If there is an audio track, we use it as a file duration
3078                (and so, as AU duration...) */
3079                if (mMp4FileDataPtr->audioTrackPtr != M4OSA_NULL)
3080                {
3081                    M4OSA_TRACE1_0(
3082                        "M4MP4W_closeWrite : ! Let's use the audio track duration !");
3083                    mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] =
3084                        (M4OSA_UInt32)(
3085                        mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS
3086                        * (1000.0 / mMp4FileDataPtr->audioTrackPtr->
3087                        CommonData.timescale));
3088                    v_trakDuration =
3089                        mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1];
3090                }
3091                /* Else, we use a MAGICAL value (66 ms) */
3092                else
3093                {
3094                    M4OSA_TRACE1_0(
3095                        "M4MP4W_closeWrite : ! No audio track -> use magical value (66) !"); /*    */
3096                    mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] = 66;
3097                    v_trakDuration = 66;
3098                }
3099            }
3100        }
3101
3102        /* Calculate table sizes */
3103        A = v_sttsSize = 16 + 8 * mMp4FileDataPtr->videoTrackPtr->
3104            CommonData.sttsTableEntryNb; /* A (video=16+8J)*/
3105        B = v_stszSize = 20 + 4 * mMp4FileDataPtr->videoTrackPtr->
3106            CommonData.sampleNb; /* B (video=20+4K)*/
3107        N = mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb;
3108        AB4N = A + B + 4 * N;
3109
3110        scale_video =
3111            1000.0 / mMp4FileDataPtr->videoTrackPtr->CommonData.timescale;
3112        v_msTrakDuration = (M4OSA_UInt32)(v_trakDuration * scale_video);
3113
3114        /*Convert integers in the table from LE into BE*/
3115#ifndef _M4MP4W_OPTIMIZE_FOR_PHONE
3116
3117        M4MP4W_table32ToBE(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ,
3118            mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb);
3119        M4MP4W_table32ToBE(mMp4FileDataPtr->videoTrackPtr->TABLE_STTS,
3120            2 * (mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb));
3121
3122#endif
3123
3124        M4MP4W_table32ToBE(mMp4FileDataPtr->videoTrackPtr->TABLE_STSS,
3125            mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb);
3126
3127        if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
3128            == M4SYS_kH263)
3129        {
3130            bH263 = M4OSA_TRUE;
3131            v_trakSize = AB4N + 426; /* (h263=A+B+4N+426)*/
3132            v_mdiaSize = AB4N + 326; /* (h263=A+B+4N+326)*/
3133            v_minfSize = AB4N + 253; /* (h263=A+B+4N+253)*/
3134            v_stblSize = AB4N + 189; /* (h263=A+B+4N+189)*/
3135            v_stsdSize = 117;        /* (h263=117)*/
3136            v_esdSize = 101;         /* (h263=101)*/
3137
3138            moovSize += AB4N + 426;
3139
3140            if (((M4OSA_Int32)mMp4FileDataPtr->videoTrackPtr->avgBitrate) != -1)
3141            {
3142                /*the optional 'bitr' atom is appended to the dsi,so filesize is 16 bytes bigger*/
3143                v_trakSize += 16;
3144                v_mdiaSize += 16;
3145                v_minfSize += 16;
3146                v_stblSize += 16;
3147                v_stsdSize += 16;
3148                v_esdSize += 16;
3149                moovSize += 16;
3150            }
3151        }
3152        else if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
3153            == M4SYS_kH264)
3154        {
3155            bH264 = M4OSA_TRUE;
3156            /* For H264 there is no default DSI, and its presence is mandatory,
3157            so check the DSI has been set*/
3158            if (0 == mMp4FileDataPtr->videoTrackPtr->dsiSize
3159                || M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
3160            {
3161                M4OSA_TRACE1_0(
3162                    "M4MP4W_closeWrite: error, no H264 DSI has been set!");
3163                err = M4ERR_STATE;
3164                goto cleanup;
3165            }
3166
3167            /*H264 sizes of the atom*/
3168
3169            // Remove the hardcoded DSI values of H264Block2
3170            // TODO: check bMULPPSSPS case
3171            v_avcCSize = sizeof(M4OSA_UInt32) + sizeof(H264Block2) +
3172                mMp4FileDataPtr->videoTrackPtr->dsiSize;
3173
3174            v_trakSize = AB4N + v_avcCSize + 411;
3175            v_mdiaSize = AB4N + v_avcCSize + 311;
3176            v_minfSize = AB4N + v_avcCSize + 238;
3177            v_stblSize = AB4N + v_avcCSize + 174;
3178            v_stsdSize =        v_avcCSize + 102;
3179            v_esdSize  =        v_avcCSize + 86;
3180
3181            moovSize   += AB4N + v_avcCSize + 411;
3182
3183        }
3184        else if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
3185            == M4SYS_kMPEG_4)
3186        {
3187            bMP4V = M4OSA_TRUE;
3188            /* For MPEG4 there is no default DSI, and its presence is mandatory,
3189            so check the DSI has been set*/
3190            if (0 == mMp4FileDataPtr->videoTrackPtr->dsiSize
3191                || M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
3192            {
3193                M4OSA_TRACE1_0(
3194                    "M4MP4W_closeWrite: error, no MPEG4 DSI has been set!");
3195                err = M4ERR_STATE;
3196                goto cleanup;
3197            }
3198
3199            /*MP4V variables*/
3200            dsi = mMp4FileDataPtr->videoTrackPtr->dsiSize;
3201            v_esdsSize = 37 + dsi;         /* dsi+37*/
3202            v_ESDescriptorSize =
3203                23
3204                + dsi; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
3205            v_DCDescriptorSize = 15 + dsi; /* dsi+15*/
3206
3207            v_trakSize = AB4N + dsi + 448; /* (mp4v=A+B+dsi+4N+448)    */
3208            v_mdiaSize = AB4N + dsi + 348; /* (mp4v=A+B+dsi+4N+348)    */
3209            v_minfSize = AB4N + dsi + 275; /* (mp4v=A+B+dsi+4N+275)    */
3210            v_stblSize = AB4N + dsi + 211; /* (mp4v=A+B+dsi+4N+211)    */
3211            v_stsdSize = dsi + 139;        /* (mp4v=139+dsi)*/
3212            v_esdSize = dsi + 123;         /* (mp4v=123+dsi)*/
3213
3214            moovSize += AB4N + dsi + 448;
3215        }
3216
3217        /*video variables*/
3218        v_stssSize = 16 + 4 * N; /* 4*N+16     STSS*/
3219
3220#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3221        /* stsc update */
3222
3223        v_stscSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3224        v_stblSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3225        v_minfSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3226        v_mdiaSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3227        v_trakSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3228        moovSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3229
3230        /* stco update */
3231        v_stcoSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3232        v_stblSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3233        v_minfSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3234        v_mdiaSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3235        v_trakSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3236        moovSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3237
3238#else
3239        /*stsc/stco update*/
3240
3241        v_stscSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3242        v_stcoSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3243        v_stblSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3244        v_minfSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3245        v_mdiaSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3246        v_trakSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3247        moovSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3248
3249#endif
3250
3251        /*update last chunk time*/
3252
3253        mMp4FileDataPtr->videoTrackPtr->
3254            chunkTimeMsTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
3255            v_msTrakDuration;
3256    }
3257
3258    if (bAudio)
3259    {
3260        if ((M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable)
3261            || (M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->chunkSizeTable)
3262            || (M4OSA_NULL
3263            == mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable)
3264            || (M4OSA_NULL
3265            == mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable)
3266            || (M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->TABLE_STTS))
3267        {
3268            mMp4FileDataPtr->fileWriterFunctions->closeWrite(
3269                fileWriterContext); /**< close the stream anyway */
3270            M4MP4W_freeContext(context); /**< Free the context content */
3271            return M4ERR_ALLOC;
3272        }
3273
3274        /*audio microstate*/
3275        mMp4FileDataPtr->audioTrackPtr->microState = M4MP4W_closed;
3276
3277        if (mMp4FileDataPtr->audioTrackPtr->CommonData.trackType == M4SYS_kAAC)
3278        {
3279            bAAC =
3280                M4OSA_TRUE; /*else, audio is implicitely amr in the following*/
3281            dsi = mMp4FileDataPtr->audioTrackPtr->dsiSize; /*variable size*/
3282
3283            a_esdsSize = 37 + dsi;                         /* dsi+37*/
3284            a_ESDescriptorSize =
3285                23
3286                + dsi; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
3287            a_DCDescriptorSize = 15 + dsi;                 /* dsi+15*/
3288
3289            a_esdSize = dsi + 73; /*overwrite a_esdSize with aac value*/
3290            /*add dif. between amr & aac sizes: (- 53 + dsi + 37)*/
3291            a_stsdSize += dsi + 20;
3292            a_stblSize += dsi + 20;
3293            a_minfSize += dsi + 20;
3294            a_mdiaSize += dsi + 20;
3295            a_trakSize += dsi + 20;
3296            moovSize += dsi + 20;
3297        }
3298
3299        if (mMp4FileDataPtr->audioTrackPtr->CommonData.trackType
3300            == M4SYS_kEVRC)
3301        {
3302            bEVRC =
3303                M4OSA_TRUE; /*else, audio is implicitely amr in the following*/
3304
3305            /* evrc dsi is only 6 bytes while amr dsi is 9 bytes,all other blocks are unchanged */
3306            a_esdSize -= 3;
3307            a_stsdSize -= 3;
3308            a_stblSize -= 3;
3309            a_minfSize -= 3;
3310            a_mdiaSize -= 3;
3311            a_trakSize -= 3;
3312            moovSize -= 3;
3313        }
3314
3315        if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize == 0)
3316        {
3317            if (M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ)
3318            {
3319                mMp4FileDataPtr->fileWriterFunctions->closeWrite(
3320                    fileWriterContext); /**< close the stream anyway */
3321                M4MP4W_freeContext(context); /**< Free the context content */
3322                return M4ERR_ALLOC;
3323            }
3324            /*Convert integers in the table from LE into BE*/
3325            M4MP4W_table32ToBE(mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ,
3326                mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb);
3327            a_stszSize +=
3328                4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3329            a_stblSize +=
3330                4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3331            a_minfSize +=
3332                4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3333            a_mdiaSize +=
3334                4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3335            a_trakSize +=
3336                4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3337            moovSize += 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3338        }
3339
3340        moovSize += 402;
3341
3342        /*current chunk is the last one and gives the total number of audio chunks (-1)*/
3343        for ( i = 0; i < mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
3344        {
3345            a_dataSize += mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i];
3346        }
3347
3348#ifndef _M4MP4W_MOOV_FIRST
3349        /*flush chunk*/
3350
3351        if (mMp4FileDataPtr->audioTrackPtr->currentPos > 0)
3352        {
3353            err = M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[0],
3354                mMp4FileDataPtr->audioTrackPtr->currentPos,
3355                mMp4FileDataPtr->fileWriterFunctions,
3356                mMp4FileDataPtr->fileWriterContext);
3357
3358            if (M4NO_ERROR != err)
3359                goto cleanup;
3360        }
3361
3362        M4OSA_TRACE1_0("flush audio | CLOSE");
3363        M4OSA_TRACE1_2("current chunk = %d  offset = 0x%x",
3364            mMp4FileDataPtr->audioTrackPtr->currentChunk,
3365            mMp4FileDataPtr->absoluteCurrentPos);
3366
3367        /*update chunk offset*/
3368        mMp4FileDataPtr->audioTrackPtr->
3369            chunkOffsetTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
3370            mMp4FileDataPtr->absoluteCurrentPos;
3371
3372        /*add chunk size to absoluteCurrentPos*/
3373        mMp4FileDataPtr->absoluteCurrentPos +=
3374            mMp4FileDataPtr->audioTrackPtr->currentPos;
3375
3376#endif /*_M4MP4W_MOOV_FIRST*/
3377
3378        /*update last chunk size, and add this value to a_dataSize*/
3379
3380        mMp4FileDataPtr->audioTrackPtr->
3381            chunkSizeTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
3382            mMp4FileDataPtr->audioTrackPtr->currentPos;
3383        a_dataSize +=
3384            mMp4FileDataPtr->audioTrackPtr->currentPos; /*add last chunk size*/
3385
3386        /* bugfix: if a new chunk was just created, cancel it before to close */
3387        if ((mMp4FileDataPtr->audioTrackPtr->currentChunk != 0)
3388            && (mMp4FileDataPtr->audioTrackPtr->currentPos == 0))
3389        {
3390            mMp4FileDataPtr->audioTrackPtr->currentChunk--;
3391        }
3392#ifdef _M4MP4W_UNBUFFERED_VIDEO
3393
3394        if ((mMp4FileDataPtr->audioTrackPtr->
3395            chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->
3396            currentStsc] & 0xFFF) == 0)
3397        {
3398            mMp4FileDataPtr->audioTrackPtr->currentStsc--;
3399        }
3400
3401#endif                                                          /*_M4MP4W_UNBUFFERED_VIDEO*/
3402
3403        a_trakDuration = mMp4FileDataPtr->audioTrackPtr->
3404            CommonData.lastCTS; /* equals lastCTS*/
3405        /* add last sample dur */
3406
3407        if (mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb != 1)
3408        {
3409#ifdef DUPLICATE_STTS_IN_LAST_AU
3410            /*increase of 1 the number of consecutive AUs with same duration*/
3411
3412            mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2
3413                *(mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb
3414                - 1) - 2] += 1;
3415
3416#endif /*DUPLICATE_STTS_IN_LAST_AU*/
3417
3418            a_trakDuration += mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2
3419                * (mMp4FileDataPtr->audioTrackPtr->
3420                CommonData.sttsTableEntryNb - 1) - 1];
3421        }
3422        else if (0 == mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS)
3423        {
3424            if (mMp4FileDataPtr->audioTrackPtr->CommonData.trackType
3425                == M4SYS_kAMR)
3426            {
3427                if (12200 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3428                {
3429                    a_trakDuration = a_dataSize / 32
3430                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3431                }
3432                else if (10200 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3433                {
3434                    a_trakDuration = a_dataSize / 27
3435                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3436                }
3437                else if (7950 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3438                {
3439                    a_trakDuration = a_dataSize / 21
3440                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3441                }
3442                else if (7400 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3443                {
3444                    a_trakDuration = a_dataSize / 20
3445                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3446                }
3447                else if (6700 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3448                {
3449                    a_trakDuration = a_dataSize / 18
3450                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3451                }
3452                else if (5900 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3453                {
3454                    a_trakDuration = a_dataSize / 16
3455                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3456                }
3457                else if (5150 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3458                {
3459                    a_trakDuration = a_dataSize / 14
3460                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3461                }
3462                else if (4750 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3463                {
3464                    a_trakDuration = a_dataSize / 13
3465                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3466                }
3467            }
3468        }
3469
3470        scale_audio =
3471            1000.0 / mMp4FileDataPtr->audioTrackPtr->CommonData.timescale;
3472        a_msTrakDuration = (M4OSA_UInt32)(a_trakDuration * scale_audio);
3473
3474#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3475        /* stsc update */
3476
3477        a_stscSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3478        a_stblSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3479        a_minfSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3480        a_mdiaSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3481        a_trakSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3482        moovSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3483
3484        /* stso update */
3485        a_stcoSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3486        a_stblSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3487        a_minfSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3488        a_mdiaSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3489        a_trakSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3490        moovSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3491
3492#else
3493        /*stsc/stco update*/
3494
3495        a_stscSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3496        a_stcoSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3497        a_stblSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3498        a_minfSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3499        a_mdiaSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3500        a_trakSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3501        moovSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3502
3503#endif
3504
3505        /* compute the new size of stts*/
3506
3507        a_sttsSize = 16 + 8 * (mMp4FileDataPtr->audioTrackPtr->
3508            CommonData.sttsTableEntryNb - 1);
3509
3510        moovSize += a_sttsSize - 24;
3511        a_mdiaSize += a_sttsSize - 24;
3512        a_minfSize += a_sttsSize - 24;
3513        a_stblSize += a_sttsSize - 24;
3514        a_trakSize += a_sttsSize - 24;
3515
3516        /*update last chunk time*/
3517        mMp4FileDataPtr->audioTrackPtr->
3518            chunkTimeMsTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
3519            a_msTrakDuration;
3520    }
3521
3522    /* changing the way the mdat size is computed.
3523    The real purpose of the mdat size is to know the amount to skip to get to the next
3524    atom, which is the moov; the size of media in the mdat is almost secondary. Therefore,
3525    it is of utmost importance that the mdat size "points" to where the moov actually
3526    begins. Now, the moov begins right after the last data we wrote, so how could the sum
3527    of all chunk sizes be different from the total size of what has been written? Well, it
3528    can happen when the writing was unexpectedly stopped (because of lack of disk space,
3529    for instance), in this case a chunk may be partially written (the partial write is not
3530    necessarily erased) but it may not be reflected in the chunk size list (which may
3531    believe it hasn't been written or on the contrary that it has been fully written). In
3532    the case of such a mismatch, there is either unused data in the mdat (not very good,
3533    but tolerable) or when reading the last chunk it will read the beginning of the moov
3534    as part of the chunk (which means the last chunk won't be correctly decoded), both of
3535    which are still better than losing the whole recording. In the long run it'll probably
3536    be attempted to always clean up back to a consistent state, but at any rate it is
3537    always safer to have the mdat size be computed using the position where the moov
3538    actually begins, rather than using the size it is thought the mdat has.
3539
3540    Therefore, I will record where we are just before writing the moov, to serve when
3541    updating the mdat size. */
3542
3543    /* mdatSize += a_dataSize + v_dataSize; *//*TODO allow for multiple chunks*/
3544
3545    /* End of Pierre Lebeaupin 19/12/2007: changing the way the mdat size is computed. */
3546
3547    /* first trak offset is 32+moovSize, second equals 32+moovSize+1st_track_size*/
3548    a_trakOffset += moovSize;
3549    v_trakOffset += moovSize/*+ a_dataSize*/;
3550
3551    if (bInterleaveAV == M4OSA_FALSE)
3552        v_trakOffset += a_dataSize;
3553
3554    /*system time since 1970 */
3555#ifndef _M4MP4W_DONT_USE_TIME_H
3556
3557    time((time_t *)&creationTime);
3558    /*convert into time since 1/1/1904 00h00 (normative)*/
3559    creationTime += 2082841761; /*nb of sec between 1904 and 1970*/
3560
3561#else                                            /*_M4MP4W_DONT_USE_TIME_H*/
3562
3563    creationTime =
3564        0xBBD09100; /* = 7/11/2003 00h00 ; in hexa because of code scrambler limitation with
3565                                           large integers */
3566
3567#endif                                           /*_M4MP4W_DONT_USE_TIME_H*/
3568
3569    mMp4FileDataPtr->duration =
3570        max(a_msTrakDuration, v_msTrakDuration); /*max audio/video*/
3571
3572#ifdef _M4MP4W_MOOV_FIRST
3573    /*open file in write binary mode*/
3574
3575    err = mMp4FileDataPtr->fileWriterFunctions->openWrite(&fileWriterContext,
3576        mMp4FileDataPtr->url, 0x22);
3577    ERR_CHECK(err == M4NO_ERROR, err);
3578
3579    /*ftyp atom*/
3580    if (mMp4FileDataPtr->ftyp.major_brand != 0)
3581    {
3582        M4OSA_UInt32 i;
3583
3584        /* Put customized ftyp box */
3585        CLEANUPonERR(M4MP4W_putBE32(16
3586            + (mMp4FileDataPtr->ftyp.nbCompatibleBrands * 4),
3587            mMp4FileDataPtr->fileWriterFunctions,
3588            mMp4FileDataPtr->fileWriterContext));
3589        CLEANUPonERR(M4MP4W_putBE32(M4MPAC_FTYP_TAG,
3590            mMp4FileDataPtr->fileWriterFunctions,
3591            mMp4FileDataPtr->fileWriterContext));
3592        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->ftyp.major_brand,
3593            mMp4FileDataPtr->fileWriterFunctions,
3594            mMp4FileDataPtr->fileWriterContext));
3595        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->ftyp.minor_version,
3596            mMp4FileDataPtr->fileWriterFunctions,
3597            mMp4FileDataPtr->fileWriterContext));
3598
3599        for ( i = 0; i < mMp4FileDataPtr->ftyp.nbCompatibleBrands; i++ )
3600        {
3601            CLEANUPonERR(
3602                M4MP4W_putBE32(mMp4FileDataPtr->ftyp.compatible_brands[i],
3603                mMp4FileDataPtr->fileWriterFunctions,
3604                mMp4FileDataPtr->fileWriterContext));
3605        }
3606    }
3607    else
3608    {
3609        /* Put default ftyp box */
3610        CLEANUPonERR(M4MP4W_putBlock(Default_ftyp, sizeof(Default_ftyp),
3611            mMp4FileDataPtr->fileWriterFunctions,
3612            mMp4FileDataPtr->fileWriterContext));
3613    }
3614
3615#endif /*_M4MP4W_MOOV_FIRST*/
3616
3617#ifndef _M4MP4W_MOOV_FIRST
3618    /* seek is used to get the current position relative to the start of the file. */
3619    /* ... or rather, seek used to be used for that, but it has been found this functionality
3620    is not reliably, or sometimes not at all, implemented in the various OSALs, so we now avoid
3621    using it. */
3622    /* Notice this new method assumes we're at the end of the file, this will break if ever we
3623    are overwriting a larger file. */
3624
3625    CLEANUPonERR(mMp4FileDataPtr->fileWriterFunctions->getOption(
3626        mMp4FileDataPtr->fileWriterContext,
3627        M4OSA_kFileWriteGetFileSize, (M4OSA_DataOption *) &moovPos));
3628    /* moovPos will be used after writing the moov. */
3629
3630#endif /*_M4MP4W_MOOV_FIRST*/
3631
3632    CLEANUPonERR(M4MP4W_putBE32(moovSize, mMp4FileDataPtr->fileWriterFunctions,
3633        fileWriterContext));
3634    CLEANUPonERR(M4MP4W_putBlock(CommonBlock3, sizeof(CommonBlock3),
3635        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3636    CLEANUPonERR(M4MP4W_putBE32(creationTime,
3637        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3638    CLEANUPonERR(M4MP4W_putBE32(creationTime,
3639        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3640    CLEANUPonERR(M4MP4W_putBlock(CommonBlock4, sizeof(CommonBlock4),
3641        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3642    CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->duration,
3643        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3644    CLEANUPonERR(M4MP4W_putBlock(CommonBlock5, sizeof(CommonBlock5),
3645        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3646
3647    if (bAudio)
3648    {
3649        CLEANUPonERR(M4MP4W_putBE32(a_trakSize,
3650            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3651        CLEANUPonERR(M4MP4W_putBlock(CommonBlock6, sizeof(CommonBlock6),
3652            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3653        CLEANUPonERR(M4MP4W_putBE32(creationTime,
3654            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3655        CLEANUPonERR(M4MP4W_putBE32(creationTime,
3656            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3657        CLEANUPonERR(M4MP4W_putBE32(a_trakId,
3658            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3659        CLEANUPonERR(M4MP4W_putBlock(CommonBlock7, sizeof(CommonBlock7),
3660            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3661        CLEANUPonERR(M4MP4W_putBE32(a_msTrakDuration,
3662            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3663        CLEANUPonERR(M4MP4W_putBlock(CommonBlock7bis, sizeof(CommonBlock7bis),
3664            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3665        CLEANUPonERR(M4MP4W_putBlock(AMRBlock1, sizeof(AMRBlock1),
3666            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3667        CLEANUPonERR(M4MP4W_putBE32(a_mdiaSize,
3668            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3669        CLEANUPonERR(M4MP4W_putBlock(CommonBlock8, sizeof(CommonBlock8),
3670            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3671        CLEANUPonERR(M4MP4W_putBE32(creationTime,
3672            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3673        CLEANUPonERR(M4MP4W_putBE32(creationTime,
3674            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3675        CLEANUPonERR(
3676            M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->CommonData.timescale,
3677            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3678        CLEANUPonERR(M4MP4W_putBE32(a_trakDuration,
3679            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3680        CLEANUPonERR(M4MP4W_putBlock(CommonBlock9, sizeof(CommonBlock9),
3681            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3682        CLEANUPonERR(M4MP4W_putBlock(AMRBlock1_1, sizeof(AMRBlock1_1),
3683            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3684        CLEANUPonERR(M4MP4W_putBE32(a_minfSize,
3685            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3686        CLEANUPonERR(M4MP4W_putBlock(CommonBlock10, sizeof(CommonBlock10),
3687            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3688        CLEANUPonERR(M4MP4W_putBE32(a_stblSize,
3689            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3690        CLEANUPonERR(M4MP4W_putBlock(CommonBlock11, sizeof(CommonBlock11),
3691            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3692        CLEANUPonERR(M4MP4W_putBE32(a_sttsSize,
3693            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3694        CLEANUPonERR(M4MP4W_putBlock(CommonBlock12, sizeof(CommonBlock12),
3695            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3696
3697        CLEANUPonERR(M4MP4W_putBE32(
3698            mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb - 1,
3699            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3700        /*invert the table data to bigendian*/
3701        M4MP4W_table32ToBE(mMp4FileDataPtr->audioTrackPtr->TABLE_STTS,
3702            2 * (mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb
3703            - 1));
3704        CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
3705            *)mMp4FileDataPtr->audioTrackPtr->TABLE_STTS,
3706            ( mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb - 1)
3707            * 8,
3708            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3709
3710        /* stsd */
3711        CLEANUPonERR(M4MP4W_putBE32(a_stsdSize,
3712            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3713        CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionHeader,
3714            sizeof(SampleDescriptionHeader),
3715            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3716        CLEANUPonERR(M4MP4W_putBE32(a_esdSize,
3717            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3718
3719        /* sample desc entry inside stsd */
3720        if (bAAC)
3721        {
3722            CLEANUPonERR(M4MP4W_putBlock(AACBlock1, sizeof(AACBlock1),
3723                mMp4FileDataPtr->fileWriterFunctions,
3724                fileWriterContext)); /*aac*/
3725        }
3726        else if (bEVRC)
3727        {
3728            CLEANUPonERR(M4MP4W_putBlock(EVRC8Block1, sizeof(EVRC8Block1),
3729                mMp4FileDataPtr->fileWriterFunctions,
3730                fileWriterContext)); /*evrc*/
3731        }
3732        else                         /*AMR8*/
3733        {
3734            CLEANUPonERR(M4MP4W_putBlock(AMR8Block1, sizeof(AMR8Block1),
3735                mMp4FileDataPtr->fileWriterFunctions,
3736                fileWriterContext)); /*amr8*/
3737        }
3738        CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryStart,
3739            sizeof(SampleDescriptionEntryStart),
3740            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3741        CLEANUPonERR(M4MP4W_putBlock(AudioSampleDescEntryBoilerplate,
3742            sizeof(AudioSampleDescEntryBoilerplate),
3743            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3744        CLEANUPonERR(
3745            M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->CommonData.timescale
3746            << 16,
3747            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3748
3749        /* DSI inside sample desc entry */
3750        if (bAAC)
3751        {
3752            CLEANUPonERR(M4MP4W_putBE32(a_esdsSize,
3753                mMp4FileDataPtr->fileWriterFunctions,
3754                fileWriterContext)); /*aac*/
3755            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock0,
3756                sizeof(MPEGConfigBlock0), mMp4FileDataPtr->fileWriterFunctions,
3757                fileWriterContext)); /*aac*/
3758            CLEANUPonERR(M4MP4W_putByte(a_ESDescriptorSize,
3759                mMp4FileDataPtr->fileWriterFunctions,
3760                fileWriterContext)); /*aac*/
3761            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock1,
3762                sizeof(MPEGConfigBlock1), mMp4FileDataPtr->fileWriterFunctions,
3763                fileWriterContext)); /*aac*/
3764            CLEANUPonERR(M4MP4W_putByte(a_DCDescriptorSize,
3765                mMp4FileDataPtr->fileWriterFunctions,
3766                fileWriterContext)); /*aac*/
3767            CLEANUPonERR(M4MP4W_putBlock(AACBlock2, sizeof(AACBlock2),
3768                mMp4FileDataPtr->fileWriterFunctions,
3769                fileWriterContext)); /*aac*/
3770            CLEANUPonERR(
3771                M4MP4W_putBE24(mMp4FileDataPtr->audioTrackPtr->avgBitrate * 5,
3772                mMp4FileDataPtr->fileWriterFunctions,
3773                fileWriterContext)); /*aac*/
3774            CLEANUPonERR(
3775                M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->maxBitrate,
3776                mMp4FileDataPtr->fileWriterFunctions,
3777                fileWriterContext)); /*aac*/
3778            CLEANUPonERR(
3779                M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->avgBitrate,
3780                mMp4FileDataPtr->fileWriterFunctions,
3781                fileWriterContext)); /*aac*/
3782            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock2,
3783                sizeof(MPEGConfigBlock2), mMp4FileDataPtr->fileWriterFunctions,
3784                fileWriterContext)); /*aac*/
3785            CLEANUPonERR(M4MP4W_putByte(mMp4FileDataPtr->audioTrackPtr->dsiSize,
3786                mMp4FileDataPtr->fileWriterFunctions,
3787                fileWriterContext)); /*aac*/
3788            CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->DSI,
3789                mMp4FileDataPtr->audioTrackPtr->dsiSize,
3790                mMp4FileDataPtr->fileWriterFunctions,
3791                fileWriterContext)); /*aac*/
3792            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock3,
3793                sizeof(MPEGConfigBlock3), mMp4FileDataPtr->fileWriterFunctions,
3794                fileWriterContext)); /*aac*/
3795        }
3796        else if (bEVRC)
3797        {
3798            M4OSA_UInt8 localDsi[6];
3799            M4OSA_UInt32 localI;
3800
3801            CLEANUPonERR(M4MP4W_putBlock(EVRCBlock3_1, sizeof(EVRCBlock3_1),
3802                mMp4FileDataPtr->fileWriterFunctions,
3803                fileWriterContext)); /*audio*/
3804
3805            /* copy the default block in a local variable*/
3806            for ( localI = 0; localI < 6; localI++ )
3807            {
3808                localDsi[localI] = EVRCBlock3_2[localI];
3809            }
3810            /* computes the number of sample per au */
3811            /* and stores it in the DSI*/
3812            /* assumes a char is enough to store the data*/
3813            localDsi[5] =
3814                (M4OSA_UInt8)(mMp4FileDataPtr->audioTrackPtr->sampleDuration
3815                / 160)/*EVRC 1 frame duration*/;
3816
3817            if (mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL)
3818            {
3819                /* copy vendor name */
3820                for ( localI = 0; localI < 4; localI++ )
3821                {
3822                    localDsi[localI] = (M4OSA_UInt8)(
3823                        mMp4FileDataPtr->audioTrackPtr->DSI[localI]);
3824                }
3825            }
3826            CLEANUPonERR(M4MP4W_putBlock(localDsi, 6,
3827                mMp4FileDataPtr->fileWriterFunctions,
3828                fileWriterContext)); /*audio*/
3829        }
3830        else                         /*AMR8*/
3831        {
3832            M4OSA_UInt8 localDsi[9];
3833            M4OSA_UInt32 localI;
3834
3835            CLEANUPonERR(M4MP4W_putBlock(AMRDSIHeader, sizeof(AMRDSIHeader),
3836                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3837
3838            /* copy the default block in a local variable*/
3839            for ( localI = 0; localI < 9; localI++ )
3840            {
3841                localDsi[localI] = AMRDefaultDSI[localI];
3842            }
3843            /* computes the number of sample per au */
3844            /* and stores it in the DSI*/
3845            /* assumes a char is enough to store the data*/
3846            /* ALERT! The potential of the following line of code to explode in our face
3847            is enormous when anything (sample rate or whatever) will change. This
3848            calculation would be MUCH better handled by the VES or whatever deals with
3849            the encoder more directly. */
3850            localDsi[8] =
3851                (M4OSA_UInt8)(mMp4FileDataPtr->audioTrackPtr->sampleDuration
3852                / 160)/*AMR NB 1 frame duration*/;
3853
3854            if (mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL)
3855            {
3856                /* copy vendor name */
3857                for ( localI = 0; localI < 4; localI++ )
3858                {
3859                    localDsi[localI] = (M4OSA_UInt8)(
3860                        mMp4FileDataPtr->audioTrackPtr->DSI[localI]);
3861                }
3862
3863                /* copy the Mode Set */
3864                for ( localI = 5; localI < 7; localI++ )
3865                {
3866                    localDsi[localI] = (M4OSA_UInt8)(
3867                        mMp4FileDataPtr->audioTrackPtr->DSI[localI]);
3868                }
3869            }
3870            CLEANUPonERR(M4MP4W_putBlock(localDsi, 9,
3871                mMp4FileDataPtr->fileWriterFunctions,
3872                fileWriterContext)); /*audio*/
3873        }
3874
3875        /*end trak*/
3876        CLEANUPonERR(M4MP4W_putBE32(a_stszSize,
3877            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3878        CLEANUPonERR(M4MP4W_putBlock(CommonBlock15, sizeof(CommonBlock15),
3879            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3880        CLEANUPonERR(M4MP4W_putBE32(
3881            mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize,
3882            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3883        CLEANUPonERR(
3884            M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb,
3885            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3886
3887        /*0 value for samplesize means not constant AU size*/
3888        if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize == 0)
3889        {
3890            CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
3891                *)mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ,
3892                mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb * 4,
3893                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3894        }
3895
3896        CLEANUPonERR(M4MP4W_putBE32(a_stscSize,
3897            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3898        CLEANUPonERR(M4MP4W_putBlock(CommonBlock16, sizeof(CommonBlock16),
3899            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3900
3901#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3902
3903        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->currentStsc
3904            + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3905
3906        for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentStsc; i++ )
3907        {
3908            CLEANUPonERR(M4MP4W_putBE32(
3909                ( mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable[i]
3910            >> 12) + 1, mMp4FileDataPtr->fileWriterFunctions,
3911                fileWriterContext));
3912            CLEANUPonERR(M4MP4W_putBE32((mMp4FileDataPtr->audioTrackPtr->
3913                chunkSampleNbTable[i] & 0xFFF),
3914                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3915            CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
3916                fileWriterContext));
3917        }
3918
3919#else
3920
3921        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->currentChunk
3922            + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3923
3924        for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
3925        {
3926            CLEANUPonERR(M4MP4W_putBE32(i + 1,
3927                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3928            CLEANUPonERR(M4MP4W_putBE32(
3929                mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable[i],
3930                mMp4FileDataPtr->fileWriterFunctions,
3931                fileWriterContext));
3932            CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
3933                fileWriterContext));
3934        }
3935
3936#endif
3937
3938        CLEANUPonERR(M4MP4W_putBE32(a_stcoSize,
3939            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3940        CLEANUPonERR(M4MP4W_putBlock(CommonBlock17, sizeof(CommonBlock17),
3941            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3942        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->currentChunk
3943            + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3944
3945#ifdef _M4MP4W_MOOV_FIRST
3946
3947        for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
3948        {
3949            CLEANUPonERR(M4MP4W_putBE32(a_trakOffset,
3950                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3951            a_trakOffset += mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i];
3952
3953            if (( bInterleaveAV == M4OSA_TRUE)
3954                && (mMp4FileDataPtr->videoTrackPtr->currentChunk >= i))
3955            {
3956                a_trakOffset +=
3957                    mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i];
3958            }
3959        }
3960
3961#else
3962
3963        for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
3964        {
3965            CLEANUPonERR(M4MP4W_putBE32(
3966                mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable[i],
3967                mMp4FileDataPtr->fileWriterFunctions,
3968                fileWriterContext));
3969        }
3970
3971#endif                                                                 /*_M4MP4W_MOOV_FIRST*/
3972
3973        CLEANUPonERR(M4MP4W_putBlock(AMRBlock4, sizeof(AMRBlock4),
3974            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3975    }
3976
3977    if (bVideo)
3978    {
3979        /*trak*/
3980        CLEANUPonERR(M4MP4W_putBE32(v_trakSize,
3981            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3982        CLEANUPonERR(M4MP4W_putBlock(CommonBlock6, sizeof(CommonBlock6),
3983            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3984        CLEANUPonERR(M4MP4W_putBE32(creationTime,
3985            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3986        CLEANUPonERR(M4MP4W_putBE32(creationTime,
3987            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3988        CLEANUPonERR(M4MP4W_putBE32(v_trakId,
3989            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3990        CLEANUPonERR(M4MP4W_putBlock(CommonBlock7, sizeof(CommonBlock7),
3991            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3992        CLEANUPonERR(M4MP4W_putBE32(v_msTrakDuration,
3993            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3994        CLEANUPonERR(M4MP4W_putBlock(CommonBlock7bis, sizeof(CommonBlock7bis),
3995            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3996
3997        /* In the track header width and height are 16.16 fixed point values,
3998        so shift left the regular integer value by 16. */
3999        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->width << 16,
4000            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4001        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->height
4002            << 16,
4003            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4004
4005        CLEANUPonERR(M4MP4W_putBE32(v_mdiaSize,
4006            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4007        CLEANUPonERR(M4MP4W_putBlock(CommonBlock8, sizeof(CommonBlock8),
4008            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4009        CLEANUPonERR(M4MP4W_putBE32(creationTime,
4010            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4011        CLEANUPonERR(M4MP4W_putBE32(creationTime,
4012            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4013        CLEANUPonERR(
4014            M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->CommonData.timescale,
4015            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4016        CLEANUPonERR(M4MP4W_putBE32(v_trakDuration,
4017            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4018        CLEANUPonERR(M4MP4W_putBlock(CommonBlock9, sizeof(CommonBlock9),
4019            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4020        CLEANUPonERR(M4MP4W_putBlock(VideoBlock1_1, sizeof(VideoBlock1_1),
4021            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4022        CLEANUPonERR(M4MP4W_putBE32(v_minfSize,
4023            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4024        CLEANUPonERR(M4MP4W_putBlock(CommonBlock10, sizeof(CommonBlock10),
4025            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4026        CLEANUPonERR(M4MP4W_putBE32(v_stblSize,
4027            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4028        CLEANUPonERR(M4MP4W_putBlock(CommonBlock11, sizeof(CommonBlock11),
4029            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4030        CLEANUPonERR(M4MP4W_putBE32(v_sttsSize,
4031            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4032        CLEANUPonERR(M4MP4W_putBlock(CommonBlock12, sizeof(CommonBlock12),
4033            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4034        CLEANUPonERR(M4MP4W_putBE32(
4035            mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb,
4036            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4037#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
4038
4039        for ( i = 0;
4040            i < mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb;
4041            i++ )
4042        {
4043            CLEANUPonERR(M4MP4W_putBE32(M4MP4W_get32_Lo(
4044                &mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[i]),
4045                mMp4FileDataPtr->fileWriterFunctions,
4046                fileWriterContext)); /*video*/
4047            CLEANUPonERR(M4MP4W_putBE32(M4MP4W_get32_Hi(
4048                &mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[i]),
4049                mMp4FileDataPtr->fileWriterFunctions,
4050                fileWriterContext)); /*video*/
4051        }
4052
4053#else
4054
4055        CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
4056            *)mMp4FileDataPtr->videoTrackPtr->TABLE_STTS,
4057            ( mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb) * 8,
4058            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4059
4060#endif
4061
4062        /* stsd */
4063
4064        CLEANUPonERR(M4MP4W_putBE32(v_stsdSize,
4065            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4066        CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionHeader,
4067            sizeof(SampleDescriptionHeader),
4068            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4069        CLEANUPonERR(M4MP4W_putBE32(v_esdSize,
4070            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4071
4072        /* sample desc entry inside stsd */
4073        if (bMP4V)
4074        {
4075            CLEANUPonERR(M4MP4W_putBlock(Mp4vBlock1, sizeof(Mp4vBlock1),
4076                mMp4FileDataPtr->fileWriterFunctions,
4077                fileWriterContext)); /*mp4v*/
4078        }
4079
4080        if (bH263)
4081        {
4082            CLEANUPonERR(M4MP4W_putBlock(H263Block1, sizeof(H263Block1),
4083                mMp4FileDataPtr->fileWriterFunctions,
4084                fileWriterContext)); /*h263*/
4085        }
4086
4087        if (bH264)
4088        {
4089            CLEANUPonERR(M4MP4W_putBlock(H264Block1, sizeof(H264Block1),
4090                mMp4FileDataPtr->fileWriterFunctions,
4091                fileWriterContext)); /*h264*/
4092        }
4093        CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryStart,
4094            sizeof(SampleDescriptionEntryStart),
4095            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4096        CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryVideoBoilerplate1,
4097            sizeof(SampleDescriptionEntryVideoBoilerplate1),
4098            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4099        CLEANUPonERR(M4MP4W_putBE16(mMp4FileDataPtr->videoTrackPtr->width,
4100            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4101        CLEANUPonERR(M4MP4W_putBE16(mMp4FileDataPtr->videoTrackPtr->height,
4102            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4103        CLEANUPonERR(M4MP4W_putBlock(VideoResolutions, sizeof(VideoResolutions),
4104            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*mp4v*/
4105        CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryVideoBoilerplate2,
4106            sizeof(SampleDescriptionEntryVideoBoilerplate2),
4107            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4108
4109        /* DSI inside sample desc entry */
4110        if (bH263)
4111        {
4112            /* The h263 dsi given through the api must be 7 bytes, that is, it shall not include
4113             the optional bitrate box. However, if the bitrate information is set in the stream
4114             handler, a bitrate box is appended here to the dsi */
4115            if (((M4OSA_Int32)mMp4FileDataPtr->videoTrackPtr->avgBitrate) != -1)
4116            {
4117                CLEANUPonERR(M4MP4W_putBlock(H263Block2_bitr,
4118                    sizeof(H263Block2_bitr),
4119                    mMp4FileDataPtr->fileWriterFunctions,
4120                    fileWriterContext)); /* d263 box with bitr atom */
4121
4122                if (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
4123                {
4124                    CLEANUPonERR(M4MP4W_putBlock(H263Block3, sizeof(H263Block3),
4125                        mMp4FileDataPtr->fileWriterFunctions,
4126                        fileWriterContext)); /*h263*/
4127                }
4128                else
4129                {
4130                    CLEANUPonERR(
4131                        M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
4132                        mMp4FileDataPtr->videoTrackPtr->dsiSize,
4133                        mMp4FileDataPtr->fileWriterFunctions,
4134                        fileWriterContext));
4135                }
4136
4137                CLEANUPonERR(M4MP4W_putBlock(H263Block4, sizeof(H263Block4),
4138                    mMp4FileDataPtr->fileWriterFunctions,
4139                    fileWriterContext)); /*h263*/
4140                /* Pierre Lebeaupin 2008/04/29: the two following lines used to be swapped;
4141                I changed to this order in order to conform to 3GPP. */
4142                CLEANUPonERR(
4143                    M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->avgBitrate,
4144                    mMp4FileDataPtr->fileWriterFunctions,
4145                    fileWriterContext)); /*h263*/
4146                CLEANUPonERR(
4147                    M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->maxBitrate,
4148                    mMp4FileDataPtr->fileWriterFunctions,
4149                    fileWriterContext)); /*h263*/
4150            }
4151            else
4152            {
4153                CLEANUPonERR(M4MP4W_putBlock(H263Block2, sizeof(H263Block2),
4154                    mMp4FileDataPtr->fileWriterFunctions,
4155                    fileWriterContext)); /* d263 box */
4156
4157                if (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
4158                {
4159                    CLEANUPonERR(M4MP4W_putBlock(H263Block3, sizeof(H263Block3),
4160                        mMp4FileDataPtr->fileWriterFunctions,
4161                        fileWriterContext)); /*h263*/
4162                }
4163                else
4164                {
4165                    CLEANUPonERR(
4166                        M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
4167                        mMp4FileDataPtr->videoTrackPtr->dsiSize,
4168                        mMp4FileDataPtr->fileWriterFunctions,
4169                        fileWriterContext));
4170                }
4171            }
4172        }
4173
4174        if (bMP4V)
4175        {
4176            M4OSA_UInt32 bufferSizeDB = 5 * mMp4FileDataPtr->videoTrackPtr->
4177                avgBitrate; /*bufferSizeDB set to 5 times the bitrate*/
4178
4179            CLEANUPonERR(M4MP4W_putBE32(v_esdsSize,
4180                mMp4FileDataPtr->fileWriterFunctions,
4181                fileWriterContext)); /*mp4v*/
4182            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock0,
4183                sizeof(MPEGConfigBlock0), mMp4FileDataPtr->fileWriterFunctions,
4184                fileWriterContext)); /*mp4v*/
4185            CLEANUPonERR(M4MP4W_putByte(v_ESDescriptorSize,
4186                mMp4FileDataPtr->fileWriterFunctions,
4187                fileWriterContext)); /*mp4v*/
4188            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock1,
4189                sizeof(MPEGConfigBlock1), mMp4FileDataPtr->fileWriterFunctions,
4190                fileWriterContext)); /*mp4v*/
4191            CLEANUPonERR(M4MP4W_putByte(v_DCDescriptorSize,
4192                mMp4FileDataPtr->fileWriterFunctions,
4193                fileWriterContext)); /*mp4v*/
4194            CLEANUPonERR(M4MP4W_putBlock(Mp4vBlock3, sizeof(Mp4vBlock3),
4195                mMp4FileDataPtr->fileWriterFunctions,
4196                fileWriterContext)); /*mp4v*/
4197            CLEANUPonERR(M4MP4W_putBE24(bufferSizeDB,
4198                mMp4FileDataPtr->fileWriterFunctions,
4199                fileWriterContext)); /*mp4v*/
4200            CLEANUPonERR(
4201                M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->maxBitrate,
4202                mMp4FileDataPtr->fileWriterFunctions,
4203                fileWriterContext)); /*mp4v*/
4204            CLEANUPonERR(
4205                M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->avgBitrate,
4206                mMp4FileDataPtr->fileWriterFunctions,
4207                fileWriterContext)); /*mp4v*/
4208            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock2,
4209                sizeof(MPEGConfigBlock2), mMp4FileDataPtr->fileWriterFunctions,
4210                fileWriterContext)); /*mp4v*/
4211            CLEANUPonERR(M4MP4W_putByte(mMp4FileDataPtr->videoTrackPtr->dsiSize,
4212                mMp4FileDataPtr->fileWriterFunctions,
4213                fileWriterContext)); /*mp4v*/
4214            CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
4215                mMp4FileDataPtr->videoTrackPtr->dsiSize,
4216                mMp4FileDataPtr->fileWriterFunctions,
4217                fileWriterContext)); /*mp4v*/
4218            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock3,
4219                sizeof(MPEGConfigBlock3), mMp4FileDataPtr->fileWriterFunctions,
4220                fileWriterContext)); /*mp4v*/
4221        }
4222
4223        if (bH264)
4224        {
4225            M4OSA_UInt16 ppsLentgh = 0; /* PPS length */
4226            M4OSA_UInt16 spsLentgh = 0; /* SPS length */
4227            M4OSA_UChar *tmpDSI = mMp4FileDataPtr->videoTrackPtr->DSI; /* DSI */
4228            M4OSA_UInt16 NumberOfPPS;
4229            M4OSA_UInt16 lCntPPS;
4230
4231            /* Put the avcC (header + DSI) size */
4232            CLEANUPonERR(M4MP4W_putBE32(v_avcCSize,
4233                mMp4FileDataPtr->fileWriterFunctions,
4234                fileWriterContext)); /*h264*/
4235            /* Put the avcC header */
4236            CLEANUPonERR(M4MP4W_putBlock(H264Block2, sizeof(H264Block2),
4237                mMp4FileDataPtr->fileWriterFunctions,
4238                fileWriterContext)); /*h264*/
4239            /* Put the DSI (SPS + PPS) int the 3gp format*/
4240            /* SPS length in BE */
4241
4242            if ((0x01 != mMp4FileDataPtr->videoTrackPtr->DSI[0]) ||
4243                 (0x42 != mMp4FileDataPtr->videoTrackPtr->DSI[1]))
4244            {
4245                M4OSA_TRACE1_2("!!! M4MP4W_closeWrite ERROR : invalid AVCC 0x%X 0x%X",
4246                    mMp4FileDataPtr->videoTrackPtr->DSI[0],
4247                    mMp4FileDataPtr->videoTrackPtr->DSI[1]);
4248                return M4ERR_PARAMETER;
4249            }
4250            // Do not strip the DSI
4251            CLEANUPonERR( M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
4252                mMp4FileDataPtr->videoTrackPtr->dsiSize,
4253                mMp4FileDataPtr->fileWriterFunctions,
4254                fileWriterContext) );/*h264*/
4255
4256        }
4257
4258        /*end trak*/
4259        CLEANUPonERR(M4MP4W_putBE32(v_stszSize,
4260            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4261        CLEANUPonERR(M4MP4W_putBlock(CommonBlock15, sizeof(CommonBlock15),
4262            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4263        CLEANUPonERR(M4MP4W_putBE32(
4264            mMp4FileDataPtr->videoTrackPtr->CommonData.sampleSize,
4265            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4266        CLEANUPonERR(
4267            M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb,
4268            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4269#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
4270
4271        for ( i = 0; i < mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb;
4272            i++ )
4273        {
4274            CLEANUPonERR(
4275                M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ[i],
4276                mMp4FileDataPtr->fileWriterFunctions,
4277                fileWriterContext)); /*video*/
4278        }
4279
4280#else
4281
4282        CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
4283            *)mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ,
4284            mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb * 4,
4285            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4286
4287#endif
4288
4289        CLEANUPonERR(M4MP4W_putBE32(v_stscSize,
4290            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4291        CLEANUPonERR(M4MP4W_putBlock(CommonBlock16, sizeof(CommonBlock16),
4292            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4293
4294#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
4295
4296        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->currentStsc
4297            + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4298
4299        for ( i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentStsc; i++ )
4300        {
4301            CLEANUPonERR(M4MP4W_putBE32(
4302                ( mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable[i]
4303            >> 12) + 1, mMp4FileDataPtr->fileWriterFunctions,
4304                fileWriterContext));
4305            CLEANUPonERR(M4MP4W_putBE32((mMp4FileDataPtr->videoTrackPtr->
4306                chunkSampleNbTable[i] & 0xFFF),
4307                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4308            CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
4309                fileWriterContext));
4310        }
4311
4312#else
4313
4314        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->currentChunk
4315            + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4316
4317        for (i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk; i++)
4318        {
4319            CLEANUPonERR(M4MP4W_putBE32(i + 1,
4320                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4321            CLEANUPonERR(M4MP4W_putBE32(
4322                mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable[i],
4323                mMp4FileDataPtr->fileWriterFunctions,
4324                fileWriterContext));
4325            CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
4326                fileWriterContext));
4327        }
4328
4329#endif
4330
4331        CLEANUPonERR(M4MP4W_putBE32(v_stcoSize,
4332            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4333        CLEANUPonERR(M4MP4W_putBlock(CommonBlock17, sizeof(CommonBlock17),
4334            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4335        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->currentChunk
4336            + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4337
4338#ifdef _M4MP4W_MOOV_FIRST
4339
4340        for (i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk; i++)
4341        {
4342            if (( bInterleaveAV == M4OSA_TRUE)
4343                && (mMp4FileDataPtr->audioTrackPtr->currentChunk >= i))
4344            {
4345                v_trakOffset +=
4346                    mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i];
4347            }
4348            CLEANUPonERR(M4MP4W_putBE32(v_trakOffset,
4349                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4350            v_trakOffset += mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i];
4351        }
4352
4353#else
4354
4355        for ( i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk; i++ )
4356        {
4357            CLEANUPonERR(M4MP4W_putBE32(
4358                mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable[i],
4359                mMp4FileDataPtr->fileWriterFunctions,
4360                fileWriterContext));
4361        }
4362
4363#endif                                                                 /*_M4MP4W_MOOV_FIRST*/
4364
4365        CLEANUPonERR(M4MP4W_putBE32(v_stssSize,
4366            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4367        CLEANUPonERR(M4MP4W_putBlock(VideoBlock4, sizeof(VideoBlock4),
4368            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4369        CLEANUPonERR(
4370            M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb,
4371            mMp4FileDataPtr->fileWriterFunctions,
4372            fileWriterContext)); /*video*/
4373        CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
4374            *)mMp4FileDataPtr->videoTrackPtr->TABLE_STSS,
4375            mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb * 4,
4376            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4377        CLEANUPonERR(M4MP4W_putBlock(VideoBlock5, sizeof(VideoBlock5),
4378            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4379    }
4380#ifdef _M4MP4W_MOOV_FIRST
4381    /*mdat*/
4382
4383    CLEANUPonERR(M4MP4W_putBE32(mdatSize, mMp4FileDataPtr->fileWriterFunctions,
4384        fileWriterContext));
4385    CLEANUPonERR(M4MP4W_putBlock(CommonBlock2, sizeof(CommonBlock2),
4386        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4387
4388    /*write data, according to the interleave mode (default is not interleaved)*/
4389    if (bInterleaveAV == M4OSA_FALSE)
4390    {
4391        if (bAudio)
4392        {
4393            for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk;
4394                i++ )
4395            {
4396                CLEANUPonERR(
4397                    M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[i],
4398                    mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i],
4399                    mMp4FileDataPtr->fileWriterFunctions,
4400                    fileWriterContext)); /*audio (previously a_dataSize)*/
4401            }
4402        }
4403
4404        if (bVideo)
4405        {
4406            for ( i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk;
4407                i++ )
4408            {
4409                CLEANUPonERR(
4410                    M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[i],
4411                    mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i],
4412                    mMp4FileDataPtr->fileWriterFunctions,
4413                    fileWriterContext)); /*video (previously a_dataSize)*/
4414            }
4415        }
4416    }
4417    else /*in this mode, we have audio and video to interleave*/
4418    {
4419        for ( i = 0; i <= max(mMp4FileDataPtr->audioTrackPtr->currentChunk,
4420            mMp4FileDataPtr->videoTrackPtr->currentChunk); i++ )
4421        {
4422            if (i <= mMp4FileDataPtr->audioTrackPtr->currentChunk)
4423            {
4424                CLEANUPonERR(
4425                    M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[i],
4426                    mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i],
4427                    mMp4FileDataPtr->fileWriterFunctions,
4428                    fileWriterContext)); /*audio (previously a_dataSize)*/
4429            }
4430
4431            if (i <= mMp4FileDataPtr->videoTrackPtr->currentChunk)
4432            {
4433                CLEANUPonERR(
4434                    M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[i],
4435                    mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i],
4436                    mMp4FileDataPtr->fileWriterFunctions,
4437                    fileWriterContext)); /*video (previously a_dataSize)*/
4438            }
4439        }
4440    }
4441
4442#endif /*_M4MP4W_MOOV_FIRST*/
4443
4444    /*skip*/
4445
4446    CLEANUPonERR(M4MP4W_putBlock(BlockSignatureSkipHeader,
4447        sizeof(BlockSignatureSkipHeader), mMp4FileDataPtr->fileWriterFunctions,
4448        fileWriterContext));
4449
4450    /* Write embedded string */
4451    if (mMp4FileDataPtr->embeddedString == M4OSA_NULL)
4452    {
4453        CLEANUPonERR(M4MP4W_putBlock(BlockSignatureSkipDefaultEmbeddedString,
4454            sizeof(BlockSignatureSkipDefaultEmbeddedString),
4455            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4456    }
4457    else
4458    {
4459        CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->embeddedString, 16,
4460            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4461    }
4462
4463    /* Write ves core version */
4464    camcoder_maj = (M4OSA_UChar)(mMp4FileDataPtr->camcoderVersion / 100);
4465    camcoder_min =
4466        (M4OSA_UChar)(( mMp4FileDataPtr->camcoderVersion - 100 * camcoder_maj)
4467        / 10);
4468    camcoder_rev =
4469        (M4OSA_UChar)(mMp4FileDataPtr->camcoderVersion - 100 * camcoder_maj - 10
4470        * camcoder_min);
4471
4472    CLEANUPonERR(M4MP4W_putByte(' ', mMp4FileDataPtr->fileWriterFunctions,
4473        fileWriterContext));
4474    CLEANUPonERR(M4MP4W_putByte((M4OSA_UChar)(camcoder_maj + '0'),
4475        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4476    CLEANUPonERR(M4MP4W_putByte('.', mMp4FileDataPtr->fileWriterFunctions,
4477        fileWriterContext));
4478    CLEANUPonERR(M4MP4W_putByte((M4OSA_UChar)(camcoder_min + '0'),
4479        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4480    CLEANUPonERR(M4MP4W_putByte('.', mMp4FileDataPtr->fileWriterFunctions,
4481        fileWriterContext));
4482    CLEANUPonERR(M4MP4W_putByte((M4OSA_UChar)(camcoder_rev + '0'),
4483        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4484
4485    /* Write integration tag */
4486    CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar *)" -- ", 4,
4487        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4488
4489    if (mMp4FileDataPtr->integrationTag == M4OSA_NULL)
4490    {
4491        CLEANUPonERR(M4MP4W_putBlock(BlockSignatureSkipDefaultIntegrationTag,
4492            sizeof(BlockSignatureSkipDefaultIntegrationTag),
4493            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4494    }
4495    else
4496    {
4497        CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->integrationTag, 60,
4498            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4499    }
4500
4501#ifndef _M4MP4W_MOOV_FIRST
4502    /*overwrite mdat size*/
4503
4504    if (mMp4FileDataPtr->ftyp.major_brand != 0)
4505        mdatPos= 16 + mMp4FileDataPtr->ftyp.nbCompatibleBrands * 4;
4506    else
4507        mdatPos = 24;
4508
4509    moovPos = moovPos - mdatPos;
4510    mdatSize = moovPos;
4511
4512    CLEANUPonERR(mMp4FileDataPtr->fileWriterFunctions->seek(fileWriterContext,
4513        M4OSA_kFileSeekBeginning, &mdatPos)); /*seek after ftyp...*/
4514    CLEANUPonERR(M4MP4W_putBE32(mdatSize, mMp4FileDataPtr->fileWriterFunctions,
4515        fileWriterContext));
4516
4517#endif                                        /*_M4MP4W_MOOV_FIRST*/
4518
4519cleanup:
4520
4521    /**
4522    * Close the file even if an error occured */
4523    if (M4OSA_NULL != mMp4FileDataPtr->fileWriterContext)
4524    {
4525        err2 =
4526            mMp4FileDataPtr->fileWriterFunctions->closeWrite(mMp4FileDataPtr->
4527            fileWriterContext); /**< close the stream anyway */
4528
4529        if (M4NO_ERROR != err2)
4530        {
4531            M4OSA_TRACE1_1(
4532                "M4MP4W_closeWrite: fileWriterFunctions->closeWrite returns 0x%x",
4533                err2);
4534        }
4535        mMp4FileDataPtr->fileWriterContext = M4OSA_NULL;
4536    }
4537
4538#ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
4539    /* Remove safety file if still present (here it is cleanup in case of error and NOT the normal
4540    removal of the safety file to free emergency space for the moov). */
4541
4542    if (M4OSA_TRUE == mMp4FileDataPtr->cleanSafetyFile)
4543    {
4544        M4OSA_Context tempContext;
4545        err3 = mMp4FileDataPtr->fileWriterFunctions->openWrite(&tempContext,
4546            mMp4FileDataPtr->safetyFileUrl,
4547            M4OSA_kFileWrite | M4OSA_kFileCreate);
4548
4549        if (M4NO_ERROR != err2)
4550            err2 = err3;
4551
4552        if (M4NO_ERROR
4553            != err3) /* No sense closing if we couldn't open in the first place. */
4554        {
4555            err3 =
4556                mMp4FileDataPtr->fileWriterFunctions->closeWrite(tempContext);
4557
4558            if (M4NO_ERROR != err2)
4559                err2 = err3;
4560        }
4561        mMp4FileDataPtr->safetyFileUrl = M4OSA_NULL;
4562        mMp4FileDataPtr->cleanSafetyFile = M4OSA_FALSE;
4563    }
4564
4565#endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
4566
4567    /* Delete embedded string */
4568
4569    if (M4OSA_NULL != mMp4FileDataPtr->embeddedString)
4570    {
4571        free(mMp4FileDataPtr->embeddedString);
4572        mMp4FileDataPtr->embeddedString = M4OSA_NULL;
4573    }
4574
4575    /* Delete integration tag */
4576    if (M4OSA_NULL != mMp4FileDataPtr->integrationTag)
4577    {
4578        free(mMp4FileDataPtr->integrationTag);
4579        mMp4FileDataPtr->integrationTag = M4OSA_NULL;
4580    }
4581
4582    /**
4583    * M4MP4W_freeContext() is now a private method, called only from here*/
4584    err3 = M4MP4W_freeContext(context);
4585
4586    if (M4NO_ERROR != err3)
4587    {
4588        M4OSA_TRACE1_1("M4MP4W_closeWrite: M4MP4W_freeContext returns 0x%x",
4589            err3);
4590    }
4591
4592    /**
4593    * Choose which error code to return */
4594    if (M4NO_ERROR != err)
4595    {
4596        /**
4597        * We give priority to main error */
4598        M4OSA_TRACE1_1("M4MP4W_closeWrite: returning err=0x%x", err);
4599        return err;
4600    }
4601    else if (M4NO_ERROR != err2)
4602    {
4603        /**
4604        * Error from closeWrite is returned if there is no main error */
4605        M4OSA_TRACE1_1("M4MP4W_closeWrite: returning err2=0x%x", err2);
4606        return err2;
4607    }
4608    else
4609    {
4610        /**
4611        * Error from M4MP4W_freeContext is returned only if there is no main error and
4612          no close error */
4613        M4OSA_TRACE1_1("M4MP4W_closeWrite: returning err3=0x%x", err3);
4614        return err3;
4615    }
4616}
4617
4618/*******************************************************************************/
4619M4OSA_ERR M4MP4W_getOption( M4OSA_Context context, M4OSA_OptionID option,
4620                           M4OSA_DataOption *valuePtr )
4621/*******************************************************************************/
4622{
4623    M4OSA_ERR err = M4NO_ERROR;
4624
4625    M4SYS_StreamIDValue *streamIDvaluePtr = M4OSA_NULL;
4626    M4MP4W_StreamIDsize *streamIDsizePtr = M4OSA_NULL;
4627    M4MP4W_memAddr *memAddrPtr = M4OSA_NULL;
4628    /*    M4MP4W_WriteCallBack*    callBackPtr = M4OSA_NULL;*/
4629
4630    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
4631    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
4632
4633    ERR_CHECK(( mMp4FileDataPtr->state == M4MP4W_opened)
4634        || (mMp4FileDataPtr->state == M4MP4W_ready), M4ERR_STATE);
4635
4636    switch( option )
4637    {
4638        case (M4MP4W_maxAUperChunk):
4639            return M4ERR_NOT_IMPLEMENTED;
4640
4641        case (M4MP4W_maxChunkSize):
4642
4643            streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4644
4645            switch( streamIDvaluePtr->streamID )
4646            {
4647                case (AudioStreamID):
4648                    if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
4649                        return M4ERR_BAD_STREAM_ID;
4650                    else
4651                        streamIDvaluePtr->value =
4652                        mMp4FileDataPtr->audioTrackPtr->MaxChunkSize;
4653                    break;
4654
4655                case (VideoStreamID):
4656                    if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
4657                        return M4ERR_BAD_STREAM_ID;
4658                    else
4659                        streamIDvaluePtr->value =
4660                        mMp4FileDataPtr->videoTrackPtr->MaxChunkSize;
4661                    break;
4662
4663                case (0): /*all streams*/
4664                    streamIDvaluePtr->value = mMp4FileDataPtr->MaxChunkSize;
4665                    break;
4666
4667                default:
4668                    return M4ERR_BAD_STREAM_ID;
4669        }
4670
4671        break;
4672
4673    case (M4MP4W_maxChunkInter):
4674
4675        streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4676
4677        switch( streamIDvaluePtr->streamID )
4678        {
4679            case (0): /*all streams*/
4680                streamIDvaluePtr->value = (M4OSA_UInt32)mMp4FileDataPtr->
4681                    InterleaveDur; /*time conversion !*/
4682                break;
4683
4684            default:
4685                return M4ERR_BAD_STREAM_ID;
4686        }
4687        break;
4688
4689    case (M4MP4W_embeddedString):
4690        memAddrPtr = (M4MP4W_memAddr *)(*valuePtr);
4691        /*memAddrPtr must have been already allocated by the caller
4692        and memAddrPtr->size initialized with the max possible length in bytes*/
4693        ERR_CHECK(memAddrPtr->size >= 16, M4ERR_PARAMETER);
4694        ERR_CHECK(memAddrPtr->addr != M4OSA_NULL, M4ERR_PARAMETER);
4695        /*memAddrPtr->size is updated with the actual size of the string*/
4696        memAddrPtr->size = 16;
4697        /*if no value was set, return the default string */
4698        if (mMp4FileDataPtr->embeddedString != M4OSA_NULL)
4699            memcpy((void *)memAddrPtr->addr,
4700            (void *)mMp4FileDataPtr->embeddedString, 16);
4701        else
4702            memcpy((void *)memAddrPtr->addr,
4703            (void *)BlockSignatureSkipDefaultEmbeddedString,
4704            16);
4705        break;
4706
4707    case (M4MP4W_integrationTag):
4708        memAddrPtr = (M4MP4W_memAddr *)(*valuePtr);
4709        /*memAddrPtr must have been already allocated by the caller
4710        and memAddrPtr->size initialized with the max possible length in bytes*/
4711        ERR_CHECK(memAddrPtr->size >= 60, M4ERR_PARAMETER);
4712        ERR_CHECK(memAddrPtr->addr != M4OSA_NULL, M4ERR_PARAMETER);
4713        /*memAddrPtr->size is updated with the actual size of the string*/
4714        memAddrPtr->size = 60;
4715        /*if no value was set, return the default string 0 */
4716        if (mMp4FileDataPtr->integrationTag != M4OSA_NULL)
4717            memcpy((void *)memAddrPtr->addr,
4718            (void *)mMp4FileDataPtr->integrationTag, 60);
4719        else
4720            memcpy((void *)memAddrPtr->addr,
4721            (void *)BlockSignatureSkipDefaultIntegrationTag,
4722            60);
4723        break;
4724
4725    case (M4MP4W_CamcoderVersion):
4726
4727        streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4728
4729        switch( streamIDvaluePtr->streamID )
4730        {
4731            case (0): /*all streams*/
4732                streamIDvaluePtr->value = mMp4FileDataPtr->camcoderVersion;
4733                break;
4734
4735            default:
4736                return M4ERR_BAD_STREAM_ID;
4737        }
4738        break;
4739
4740    case (M4MP4W_preWriteCallBack):
4741        return M4ERR_NOT_IMPLEMENTED;
4742        /*callBackPtr = (M4MP4W_WriteCallBack*)(*valuePtr);
4743        *callBackPtr = mMp4FileDataPtr->PreWriteCallBack;
4744        break;*/
4745
4746    case (M4MP4W_postWriteCallBack):
4747        return M4ERR_NOT_IMPLEMENTED;
4748        /*callBackPtr = (M4MP4W_WriteCallBack*)(*valuePtr);
4749        *callBackPtr = mMp4FileDataPtr->PostWriteCallBack;
4750        break;*/
4751
4752    case (M4MP4W_maxAUsize):
4753
4754        streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4755
4756        switch( streamIDvaluePtr->streamID )
4757        {
4758            case (AudioStreamID):
4759                if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
4760                    return M4ERR_BAD_STREAM_ID;
4761                else
4762                    streamIDvaluePtr->value =
4763                    mMp4FileDataPtr->audioTrackPtr->MaxAUSize;
4764                break;
4765
4766            case (VideoStreamID):
4767                if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
4768                    return M4ERR_BAD_STREAM_ID;
4769                else
4770                    streamIDvaluePtr->value =
4771                    mMp4FileDataPtr->videoTrackPtr->MaxAUSize;
4772                break;
4773
4774            case (0): /*all streams*/
4775                streamIDvaluePtr->value = mMp4FileDataPtr->MaxAUSize;
4776                break;
4777
4778            default:
4779                return M4ERR_BAD_STREAM_ID;
4780        }
4781
4782        break;
4783
4784    case (M4MP4W_IOD):
4785        return M4ERR_NOT_IMPLEMENTED;
4786
4787    case (M4MP4W_ESD):
4788        return M4ERR_NOT_IMPLEMENTED;
4789
4790    case (M4MP4W_SDP):
4791        return M4ERR_NOT_IMPLEMENTED;
4792
4793    case (M4MP4W_trackSize):
4794        streamIDsizePtr = (M4MP4W_StreamIDsize *)(*valuePtr);
4795        streamIDsizePtr->width = mMp4FileDataPtr->videoTrackPtr->width;
4796        streamIDsizePtr->height = mMp4FileDataPtr->videoTrackPtr->height;
4797        break;
4798
4799    case (M4MP4W_estimateAudioSize):
4800        streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4801        streamIDvaluePtr->value =
4802            (M4OSA_UInt32)mMp4FileDataPtr->estimateAudioSize;
4803        break;
4804
4805    case (M4MP4W_MOOVfirst):
4806        return M4ERR_NOT_IMPLEMENTED;
4807
4808    case (M4MP4W_V2_MOOF):
4809        return M4ERR_NOT_IMPLEMENTED;
4810
4811    case (M4MP4W_V2_tblCompres):
4812        return M4ERR_NOT_IMPLEMENTED;
4813
4814    default:
4815        return M4ERR_BAD_OPTION_ID;
4816    }
4817
4818    return err;
4819}
4820
4821/*******************************************************************************/
4822M4OSA_ERR M4MP4W_setOption( M4OSA_Context context, M4OSA_OptionID option,
4823                           M4OSA_DataOption value )
4824/*******************************************************************************/
4825{
4826    M4OSA_ERR err = M4NO_ERROR;
4827
4828    M4SYS_StreamIDValue *streamIDvaluePtr = M4OSA_NULL;
4829    M4MP4W_StreamIDsize *streamIDsizePtr = M4OSA_NULL;
4830    M4MP4W_memAddr *memAddrPtr = M4OSA_NULL;
4831    M4SYS_StreamIDmemAddr *streamIDmemAddrPtr;
4832
4833    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
4834    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
4835
4836    /* Verify state */
4837    switch( option )
4838    {
4839        case M4MP4W_maxFileDuration:
4840        case M4MP4W_DSI:
4841            /* this param can be set at the end of a recording */
4842            ERR_CHECK((mMp4FileDataPtr->state != M4MP4W_closed), M4ERR_STATE);
4843            break;
4844
4845        case M4MP4W_setFtypBox:
4846            /* this param can only be set before starting any write */
4847            ERR_CHECK(mMp4FileDataPtr->state == M4MP4W_opened, M4ERR_STATE);
4848            break;
4849
4850        default:
4851            /* in general params can be set at open or ready stage */
4852            ERR_CHECK(( mMp4FileDataPtr->state == M4MP4W_opened)
4853                || (mMp4FileDataPtr->state == M4MP4W_ready), M4ERR_STATE);
4854    }
4855
4856    /* Set option */
4857    switch( option )
4858    {
4859        case (M4MP4W_maxAUperChunk):
4860            return M4ERR_NOT_IMPLEMENTED;
4861
4862        case (M4MP4W_maxChunkSize):
4863
4864            streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
4865
4866            switch( streamIDvaluePtr->streamID )
4867            {
4868                case (AudioStreamID):
4869                    if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
4870                        return
4871                        M4ERR_BAD_STREAM_ID; /*maybe the stream has not been added yet*/
4872                    else
4873                    {
4874                        mMp4FileDataPtr->audioTrackPtr->MaxChunkSize =
4875                            streamIDvaluePtr->value;
4876                    }
4877
4878                    break;
4879
4880                case (VideoStreamID):
4881                    if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
4882                        return
4883                        M4ERR_BAD_STREAM_ID; /*maybe the stream has not been added yet*/
4884                    else
4885                    {
4886                        mMp4FileDataPtr->videoTrackPtr->MaxChunkSize =
4887                            streamIDvaluePtr->value;
4888                    }
4889                    break;
4890
4891                case (0): /*all streams*/
4892
4893                    /*In M4MP4W_opened state, no stream is present yet, so only global value
4894                    needs to be updated.*/
4895                    mMp4FileDataPtr->MaxChunkSize = streamIDvaluePtr->value;
4896
4897                    if (mMp4FileDataPtr->hasAudio == M4OSA_TRUE)
4898                    {
4899                        mMp4FileDataPtr->audioTrackPtr->MaxChunkSize =
4900                            streamIDvaluePtr->value;
4901                    }
4902
4903                    if (mMp4FileDataPtr->hasVideo == M4OSA_TRUE)
4904                    {
4905                        mMp4FileDataPtr->videoTrackPtr->MaxChunkSize =
4906                            streamIDvaluePtr->value;
4907                    }
4908                    break;
4909
4910                default:
4911                    return M4ERR_BAD_STREAM_ID;
4912            }
4913            break;
4914
4915        case (M4MP4W_maxChunkInter):
4916
4917            streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
4918
4919            switch( streamIDvaluePtr->streamID )
4920            {
4921                case (0):                                       /*all streams*/
4922                    mMp4FileDataPtr->InterleaveDur =
4923                        (M4MP4W_Time32)streamIDvaluePtr->
4924                        value; /*time conversion!*/
4925                    break;
4926
4927                default:
4928                    return M4ERR_BAD_STREAM_ID;
4929                    /*not meaningfull to set this parameter on a streamID basis*/
4930            }
4931            break;
4932
4933        case (M4MP4W_maxFileSize):
4934            mMp4FileDataPtr->MaxFileSize = *(M4OSA_UInt32 *)value;
4935            break;
4936
4937        case (M4MP4W_embeddedString):
4938            memAddrPtr = (M4MP4W_memAddr *)value;
4939            /*
4940            * If memAddrPtr->size > 16 bytes, then the string will be truncated.
4941            * If memAddrPtr->size < 16 bytes, then return M4ERR_PARAMETER
4942            */
4943            ERR_CHECK(memAddrPtr->size >= 16, M4ERR_PARAMETER);
4944
4945            if (mMp4FileDataPtr->embeddedString == M4OSA_NULL)
4946            {
4947                mMp4FileDataPtr->embeddedString =
4948                    (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(16, M4MP4_WRITER,
4949                    (M4OSA_Char *)"embeddedString");
4950                ERR_CHECK(mMp4FileDataPtr->embeddedString != M4OSA_NULL,
4951                    M4ERR_ALLOC);
4952            }
4953            /*else, just overwrite the previously set string*/
4954            memcpy((void *)mMp4FileDataPtr->embeddedString,
4955                (void *)memAddrPtr->addr, 16);
4956            break;
4957
4958        case (M4MP4W_integrationTag):
4959            memAddrPtr = (M4MP4W_memAddr *)value;
4960            /*
4961            * If memAddrPtr->size > 60 bytes, then the string will be truncated.
4962            * If memAddrPtr->size < 60 bytes, then pad with 0
4963            */
4964            if (mMp4FileDataPtr->integrationTag == M4OSA_NULL)
4965            {
4966                mMp4FileDataPtr->integrationTag =
4967                    (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(60, M4MP4_WRITER,
4968                    (M4OSA_Char *)"integrationTag");
4969                ERR_CHECK(mMp4FileDataPtr->integrationTag != M4OSA_NULL,
4970                    M4ERR_ALLOC);
4971            }
4972            /*else, just overwrite the previously set string*/
4973            if (memAddrPtr->size < 60)
4974            {
4975                memcpy((void *)mMp4FileDataPtr->integrationTag,
4976                    (void *)BlockSignatureSkipDefaultIntegrationTag,
4977                    60);
4978                memcpy((void *)mMp4FileDataPtr->integrationTag,
4979                    (void *)memAddrPtr->addr, memAddrPtr->size);
4980            }
4981            else
4982            {
4983                memcpy((void *)mMp4FileDataPtr->integrationTag,
4984                    (void *)memAddrPtr->addr, 60);
4985            }
4986            break;
4987
4988        case (M4MP4W_CamcoderVersion):
4989
4990            streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
4991
4992            switch( streamIDvaluePtr->streamID )
4993            {
4994                case (0): /*all streams*/
4995                    mMp4FileDataPtr->camcoderVersion = streamIDvaluePtr->value;
4996                    break;
4997
4998                default:
4999                    return M4ERR_BAD_STREAM_ID;
5000                    /*not meaningfull to set this parameter on a streamID basis*/
5001            }
5002            break;
5003
5004        case (M4MP4W_preWriteCallBack):
5005            return M4ERR_NOT_IMPLEMENTED;
5006            /*mMp4FileDataPtr->PreWriteCallBack = *(M4MP4W_WriteCallBack*)value;
5007            break;*/
5008
5009        case (M4MP4W_postWriteCallBack):
5010            return M4ERR_NOT_IMPLEMENTED;
5011            /*mMp4FileDataPtr->PostWriteCallBack = *(M4MP4W_WriteCallBack*)value;
5012            break;*/
5013
5014        case (M4MP4W_maxAUsize):
5015
5016            streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
5017
5018            switch( streamIDvaluePtr->streamID )
5019            {
5020                case (AudioStreamID):
5021
5022                    /*if (mMp4FileDataPtr->audioTrackPtr == M4OSA_NULL)*/
5023                    if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
5024                        return M4ERR_BAD_STREAM_ID;
5025                    else
5026                        mMp4FileDataPtr->audioTrackPtr->MaxAUSize =
5027                        streamIDvaluePtr->value;
5028                    break;
5029
5030                case (VideoStreamID):
5031
5032                    /*if (mMp4FileDataPtr->videoTrackPtr == M4OSA_NULL)*/
5033                    if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
5034                        return M4ERR_BAD_STREAM_ID;
5035                    else
5036                        mMp4FileDataPtr->videoTrackPtr->MaxAUSize =
5037                        streamIDvaluePtr->value;
5038                    break;
5039
5040                case (0): /*all streams*/
5041
5042                    mMp4FileDataPtr->MaxAUSize = streamIDvaluePtr->value;
5043
5044                    if (mMp4FileDataPtr->hasAudio == M4OSA_TRUE)
5045                        mMp4FileDataPtr->audioTrackPtr->MaxAUSize =
5046                        streamIDvaluePtr->value;
5047
5048                    if (mMp4FileDataPtr->hasVideo == M4OSA_TRUE)
5049                        mMp4FileDataPtr->videoTrackPtr->MaxAUSize =
5050                        streamIDvaluePtr->value;
5051
5052                    break;
5053
5054                default:
5055                    return M4ERR_BAD_STREAM_ID;
5056            }
5057            break;
5058
5059        case (M4MP4W_IOD):
5060            return M4ERR_NOT_IMPLEMENTED;
5061
5062        case (M4MP4W_ESD):
5063            return M4ERR_NOT_IMPLEMENTED;
5064
5065        case (M4MP4W_SDP):
5066            return M4ERR_NOT_IMPLEMENTED;
5067
5068        case (M4MP4W_trackSize):
5069
5070            streamIDsizePtr = (M4MP4W_StreamIDsize *)value;
5071
5072            if ((streamIDsizePtr->streamID != VideoStreamID)
5073                || (mMp4FileDataPtr->hasVideo == M4OSA_FALSE))
5074                return M4ERR_BAD_STREAM_ID;
5075            else
5076            {
5077                mMp4FileDataPtr->videoTrackPtr->width = streamIDsizePtr->width;
5078                mMp4FileDataPtr->videoTrackPtr->height =
5079                    streamIDsizePtr->height;
5080            }
5081            break;
5082
5083        case (M4MP4W_estimateAudioSize):
5084
5085            streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
5086
5087            /*shall not set this option before audio and video streams were added*/
5088            /*nonsense to set this option if not in case audio+video*/
5089            if ((mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
5090                || (mMp4FileDataPtr->hasVideo == M4OSA_FALSE))
5091                return M4ERR_STATE;
5092
5093            mMp4FileDataPtr->estimateAudioSize =
5094                (M4OSA_Bool)streamIDvaluePtr->value;
5095            break;
5096
5097        case (M4MP4W_MOOVfirst):
5098            return M4ERR_NOT_IMPLEMENTED;
5099
5100        case (M4MP4W_V2_MOOF):
5101            return M4ERR_NOT_IMPLEMENTED;
5102
5103        case (M4MP4W_V2_tblCompres):
5104            return M4ERR_NOT_IMPLEMENTED;
5105
5106        case (M4MP4W_maxFileDuration):
5107            mMp4FileDataPtr->MaxFileDuration = *(M4OSA_UInt32 *)value;
5108            break;
5109
5110        case (M4MP4W_setFtypBox):
5111            {
5112                M4OSA_UInt32 size;
5113
5114                ERR_CHECK(( (M4MP4C_FtypBox *)value)->major_brand != 0,
5115                    M4ERR_PARAMETER);
5116
5117                /* Copy structure */
5118                mMp4FileDataPtr->ftyp = *(M4MP4C_FtypBox *)value;
5119
5120                /* Update global position variables with the difference between common and
5121                 user block */
5122                size =
5123                    mMp4FileDataPtr->ftyp.nbCompatibleBrands * sizeof(M4OSA_UInt32);
5124
5125                mMp4FileDataPtr->absoluteCurrentPos = 8/*mdat*/ + 16 + size;
5126                mMp4FileDataPtr->filesize = 218/*mdat+moov+skip*/ + 16 + size;
5127            }
5128            break;
5129
5130        case (M4MP4W_DSI):
5131            {
5132                streamIDmemAddrPtr = (M4SYS_StreamIDmemAddr *)value;
5133
5134                /* Nested switch! Whee! */
5135                switch( streamIDmemAddrPtr->streamID )
5136                {
5137                    case (AudioStreamID):
5138                        return M4ERR_NOT_IMPLEMENTED;
5139
5140                    case (VideoStreamID):
5141
5142                        /* Protect DSI setting : only once allowed on a given stream */
5143
5144                        switch( mMp4FileDataPtr->videoTrackPtr->
5145                            CommonData.trackType )
5146                        {
5147                            case M4SYS_kH263:
5148                                if ((0 != mMp4FileDataPtr->videoTrackPtr->dsiSize)
5149                                    || (M4OSA_NULL
5150                                    != mMp4FileDataPtr->videoTrackPtr->DSI))
5151                                {
5152                                    M4OSA_TRACE1_0(
5153                                        "M4MP4W_setOption: dsi already set !");
5154                                    return M4ERR_STATE;
5155                                }
5156
5157                                if ((0 == streamIDmemAddrPtr->size)
5158                                    || (M4OSA_NULL == streamIDmemAddrPtr->addr))
5159                                {
5160                                    M4OSA_TRACE1_0(
5161                                        "M4MP4W_setOption: Bad H263 dsi!");
5162                                    return M4ERR_PARAMETER;
5163                                }
5164
5165                                /*decoder specific info size is supposed to be always 7
5166                                 bytes long */
5167                                ERR_CHECK(streamIDmemAddrPtr->size == 7,
5168                                    M4ERR_PARAMETER);
5169                                mMp4FileDataPtr->videoTrackPtr->dsiSize =
5170                                    (M4OSA_UInt8)streamIDmemAddrPtr->size;
5171                                mMp4FileDataPtr->videoTrackPtr->DSI = (M4OSA_UChar
5172                                    *)M4OSA_32bitAlignedMalloc(streamIDmemAddrPtr->size,
5173                                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
5174                                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
5175                                    != M4OSA_NULL, M4ERR_ALLOC);
5176                                memcpy(
5177                                    (void *)mMp4FileDataPtr->videoTrackPtr->
5178                                    DSI,
5179                                    (void *)streamIDmemAddrPtr->addr,
5180                                    streamIDmemAddrPtr->size);
5181
5182                                break;
5183
5184                            case M4SYS_kMPEG_4:
5185                                if ((0 != mMp4FileDataPtr->videoTrackPtr->dsiSize)
5186                                    || (M4OSA_NULL
5187                                    != mMp4FileDataPtr->videoTrackPtr->DSI))
5188                                {
5189                                    M4OSA_TRACE1_0(
5190                                        "M4MP4W_setOption: dsi already set !");
5191                                    return M4ERR_STATE;
5192                                }
5193
5194                                if ((0 == streamIDmemAddrPtr->size)
5195                                    || (M4OSA_NULL == streamIDmemAddrPtr->addr))
5196                                {
5197                                    M4OSA_TRACE1_0(
5198                                        "M4MP4W_setOption: Bad MPEG4 dsi!");
5199                                    return M4ERR_PARAMETER;
5200                                }
5201
5202                                /*MP4V specific*/
5203                                ERR_CHECK(streamIDmemAddrPtr->size < 105,
5204                                    M4ERR_PARAMETER);
5205                                mMp4FileDataPtr->videoTrackPtr->dsiSize =
5206                                    (M4OSA_UInt8)streamIDmemAddrPtr->size;
5207                                mMp4FileDataPtr->videoTrackPtr->DSI = (M4OSA_UChar
5208                                    *)M4OSA_32bitAlignedMalloc(streamIDmemAddrPtr->size,
5209                                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
5210                                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
5211                                    != M4OSA_NULL, M4ERR_ALLOC);
5212                                memcpy(
5213                                    (void *)mMp4FileDataPtr->videoTrackPtr->
5214                                    DSI,
5215                                    (void *)streamIDmemAddrPtr->addr,
5216                                    streamIDmemAddrPtr->size);
5217                                mMp4FileDataPtr->filesize +=
5218                                    streamIDmemAddrPtr->size;
5219
5220                                break;
5221
5222                            case M4SYS_kH264:
5223                                if ((0 != mMp4FileDataPtr->videoTrackPtr->dsiSize)
5224                                    || (M4OSA_NULL
5225                                    != mMp4FileDataPtr->videoTrackPtr->DSI))
5226                                {
5227                                    /* + H.264 trimming */
5228                                    if (M4OSA_TRUE == mMp4FileDataPtr->bMULPPSSPS)
5229                                    {
5230                                        free(mMp4FileDataPtr->videoTrackPtr->DSI);
5231
5232                                        // Do not strip the DSI
5233                                        /* Store the DSI size */
5234                                        mMp4FileDataPtr->videoTrackPtr->dsiSize =
5235                                            (M4OSA_UInt8)streamIDmemAddrPtr->size;
5236                                             M4OSA_TRACE1_1("M4MP4W_setOption: in set option DSI size =%d"\
5237                                            ,mMp4FileDataPtr->videoTrackPtr->dsiSize);
5238                                        /* Copy the DSI (SPS + PPS) */
5239                                        mMp4FileDataPtr->videoTrackPtr->DSI =
5240                                            (M4OSA_UChar*)M4OSA_32bitAlignedMalloc(
5241                                            streamIDmemAddrPtr->size, M4MP4_WRITER,
5242                                            (M4OSA_Char *)"videoTrackPtr->DSI");
5243                                        ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI !=
5244                                             M4OSA_NULL, M4ERR_ALLOC);
5245                                        memcpy(
5246                                            (void *)mMp4FileDataPtr->videoTrackPtr->DSI,
5247                                            (void *)streamIDmemAddrPtr->addr,
5248                                            streamIDmemAddrPtr->size);
5249
5250                                        break;
5251                                        /* - H.264 trimming */
5252                                    }
5253                                    else
5254                                    {
5255                                        M4OSA_TRACE1_0(
5256                                            "M4MP4W_setOption: dsi already set !");
5257                                        return M4ERR_STATE;
5258                                    }
5259                                }
5260
5261                                if (( 0 == streamIDmemAddrPtr->size)
5262                                    || (M4OSA_NULL == streamIDmemAddrPtr->addr))
5263                                {
5264                                    M4OSA_TRACE1_0(
5265                                        "M4MP4W_setOption: Bad H264 dsi!");
5266                                    return M4ERR_PARAMETER;
5267                                }
5268
5269                                /* Store the DSI size */
5270                                mMp4FileDataPtr->videoTrackPtr->dsiSize =
5271                                    (M4OSA_UInt8)streamIDmemAddrPtr->size;
5272
5273                                /* Copy the DSI (SPS + PPS) */
5274                                mMp4FileDataPtr->videoTrackPtr->DSI = (M4OSA_UChar
5275                                    *)M4OSA_32bitAlignedMalloc(streamIDmemAddrPtr->size,
5276                                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
5277                                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
5278                                    != M4OSA_NULL, M4ERR_ALLOC);
5279                                memcpy(
5280                                    (void *)mMp4FileDataPtr->videoTrackPtr->
5281                                    DSI,
5282                                    (void *)streamIDmemAddrPtr->addr,
5283                                    streamIDmemAddrPtr->size);
5284                                break;
5285
5286                            default:
5287                                return M4ERR_BAD_STREAM_ID;
5288                        }
5289                    break;
5290
5291                default:
5292                    return M4ERR_BAD_STREAM_ID;
5293                }
5294            }
5295            break;
5296            /* H.264 Trimming  */
5297        case M4MP4W_MUL_PPS_SPS:
5298            mMp4FileDataPtr->bMULPPSSPS = *(M4OSA_Int8 *)value;
5299            /* H.264 Trimming  */
5300            break;
5301
5302        default:
5303            return M4ERR_BAD_OPTION_ID;
5304    }
5305
5306    return err;
5307}
5308
5309/*******************************************************************************/
5310M4OSA_ERR M4MP4W_getState( M4OSA_Context context, M4MP4W_State *state,
5311                          M4SYS_StreamID streamID )
5312/*******************************************************************************/
5313{
5314    M4OSA_ERR err = M4NO_ERROR;
5315
5316    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
5317    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
5318
5319    switch( streamID )
5320    {
5321        case (0):
5322            *state = mMp4FileDataPtr->state;
5323            break;
5324
5325        case (AudioStreamID):
5326            if (mMp4FileDataPtr->hasAudio == M4OSA_TRUE)
5327            {
5328                *state = mMp4FileDataPtr->audioTrackPtr->microState;
5329            }
5330            else
5331            {
5332                return M4ERR_BAD_STREAM_ID;
5333            }
5334            break;
5335
5336        case (VideoStreamID):
5337            if (mMp4FileDataPtr->hasVideo == M4OSA_TRUE)
5338            {
5339                *state = mMp4FileDataPtr->videoTrackPtr->microState;
5340            }
5341            else
5342            {
5343                return M4ERR_BAD_STREAM_ID;
5344            }
5345            break;
5346
5347        default:
5348            return M4ERR_BAD_STREAM_ID;
5349    }
5350
5351    return err;
5352}
5353
5354/*******************************************************************************/
5355M4OSA_ERR M4MP4W_getCurrentFileSize( M4OSA_Context context,
5356                                    M4OSA_UInt32 *pCurrentFileSize )
5357/*******************************************************************************/
5358{
5359    M4OSA_ERR err = M4NO_ERROR;
5360
5361    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
5362    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
5363
5364    ERR_CHECK(pCurrentFileSize != M4OSA_NULL, M4ERR_PARAMETER);
5365    *pCurrentFileSize = mMp4FileDataPtr->filesize;
5366
5367    return err;
5368}
5369
5370#endif /* _M4MP4W_USE_CST_MEMORY_WRITER */
5371