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        if ((M4MP4W_Time32)auPtr->CTS < mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS) {
2490            // Do not report as error, it will abort the entire filewrite. Just skip this frame.
2491            M4OSA_TRACE1_0("Skip frame. Video frame has too old timestamp.");
2492            return M4NO_ERROR;
2493        }
2494
2495        mMp4FileDataPtr->videoTrackPtr->currentPos += auPtr->size;
2496
2497        /* Warning: time conversion cast 64to32! */
2498        delta = (M4MP4W_Time32)auPtr->CTS
2499            - mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS;
2500
2501        /* DEBUG stts entries which are equal to 0 */
2502        M4OSA_TRACE2_1("V_DELTA = %ld\n", delta);
2503
2504#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2505
2506        if (2 *(mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb + 3)
2507            >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks
2508            *M4MP4W_STSZ_ALLOC_SIZE)
2509        {
2510            M4OSA_TRACE1_0("M4MP4W_processAU : video stsz table is full");
2511            return M4WAR_MP4W_OVERSIZE;
2512        }
2513
2514        mMp4FileDataPtr->videoTrackPtr->
2515            TABLE_STSZ[mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb] =
2516            (M4OSA_UInt16)auPtr->size;
2517        mMp4FileDataPtr->filesize += 4;
2518
2519#else
2520
2521        if (4 *mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
2522            >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks
2523            *M4MP4W_STSZ_ALLOC_SIZE)
2524        {
2525            mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks += 1;
2526
2527            mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ =
2528                (M4OSA_UInt32 *)M4MP4W_realloc(
2529                (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ,
2530                ( mMp4FileDataPtr->videoTrackPtr->
2531                nbOfAllocatedStszBlocks
2532                - 1) * M4MP4W_STSZ_ALLOC_SIZE,
2533                mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks
2534                * M4MP4W_STSZ_ALLOC_SIZE);
2535
2536            ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ != M4OSA_NULL,
2537                M4ERR_ALLOC);
2538        }
2539
2540        mMp4FileDataPtr->videoTrackPtr->
2541            TABLE_STSZ[mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb] =
2542            auPtr->size;
2543        mMp4FileDataPtr->filesize += 4;
2544
2545#endif
2546
2547        if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
2548            == 0) /*test if first AU*/
2549        {
2550#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2551
2552            M4MP4W_put32_Lo(&mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0], 1);
2553            M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0], 0);
2554
2555#else
2556
2557            mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0] = 1;
2558            mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] = 0;
2559
2560#endif
2561
2562            mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb = 1;
2563            mMp4FileDataPtr->filesize += 8;
2564        }
2565        else if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
2566            == 1 ) /*test if second AU*/
2567        {
2568#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2569
2570            M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0],
2571                (M4OSA_UInt16)delta);
2572
2573#else
2574
2575            mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] = delta;
2576
2577#endif
2578
2579        }
2580        else
2581        {
2582            /*retrieve last sample delta*/
2583#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2584
2585            lastSampleDur = M4MP4W_get32_Hi(&mMp4FileDataPtr->videoTrackPtr->
2586                TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
2587                CommonData.sttsTableEntryNb - 1]);
2588
2589            if (4 *(mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
2590                + 3) >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks
2591                *M4MP4W_STTS_ALLOC_SIZE)
2592            {
2593                M4OSA_TRACE1_0("M4MP4W_processAU : video stts table is full");
2594                return M4WAR_MP4W_OVERSIZE;
2595            }
2596
2597#else
2598
2599            lastSampleDur = mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
2600                * (mMp4FileDataPtr->videoTrackPtr->
2601                CommonData.sttsTableEntryNb - 1) + 1];
2602
2603            if (8 *mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
2604                >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks
2605                *M4MP4W_STTS_ALLOC_SIZE)
2606            {
2607                mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks += 1;
2608                mMp4FileDataPtr->videoTrackPtr->TABLE_STTS =
2609                    (M4OSA_UInt32 *)M4MP4W_realloc(
2610                    (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
2611                    TABLE_STTS, ( mMp4FileDataPtr->videoTrackPtr->
2612                    nbOfAllocatedSttsBlocks
2613                    - 1) * M4MP4W_STTS_ALLOC_SIZE,
2614                    mMp4FileDataPtr->videoTrackPtr->
2615                    nbOfAllocatedSttsBlocks
2616                    * M4MP4W_STTS_ALLOC_SIZE);
2617                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STTS
2618                    != M4OSA_NULL, M4ERR_ALLOC);
2619            }
2620
2621#endif                                   /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
2622
2623            if (delta != lastSampleDur) /*new entry in the table*/
2624            {
2625#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2626
2627                M4MP4W_put32_Lo(&mMp4FileDataPtr->videoTrackPtr->
2628                    TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
2629                    CommonData.sttsTableEntryNb], 1);
2630                M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->
2631                    TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
2632                    CommonData.sttsTableEntryNb], (M4OSA_UInt16)delta);
2633
2634#else
2635
2636                mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2 *(
2637                    mMp4FileDataPtr->videoTrackPtr->
2638                    CommonData.sttsTableEntryNb)] = 1;
2639                mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
2640                    *(mMp4FileDataPtr->videoTrackPtr->
2641                    CommonData.sttsTableEntryNb)+1] = delta;
2642
2643#endif
2644
2645                mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb +=
2646                    1;
2647                mMp4FileDataPtr->filesize += 8;
2648            }
2649            else
2650            {
2651                /*increase of 1 the number of consecutive AUs with same duration*/
2652#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2653
2654                mMp4FileDataPtr->videoTrackPtr->
2655                    TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
2656                    CommonData.sttsTableEntryNb - 1] += 1;
2657
2658#else
2659
2660                mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2 *(
2661                    mMp4FileDataPtr->videoTrackPtr->
2662                    CommonData.sttsTableEntryNb - 1)] += 1;
2663
2664#endif
2665
2666            }
2667        }
2668
2669        mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb += 1;
2670#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2671
2672        mMp4FileDataPtr->videoTrackPtr->
2673            chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentStsc] +=
2674            1;
2675
2676#else
2677
2678        mMp4FileDataPtr->videoTrackPtr->
2679            chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] +=
2680            1;
2681
2682#endif
2683
2684        if (auPtr->attribute == AU_RAP)
2685        {
2686#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2687
2688            if (4 *(mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb + 3)
2689                >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks
2690                *M4MP4W_STSS_ALLOC_SIZE)
2691            {
2692                M4OSA_TRACE1_0("M4MP4W_processAU : video stss table is full");
2693                return M4WAR_MP4W_OVERSIZE;
2694            }
2695
2696#else
2697
2698            if (4 *mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb
2699                >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks
2700                *M4MP4W_STSS_ALLOC_SIZE)
2701            {
2702                mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks += 1;
2703                mMp4FileDataPtr->videoTrackPtr->TABLE_STSS =
2704                    (M4OSA_UInt32 *)M4MP4W_realloc(
2705                    (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
2706                    TABLE_STSS, ( mMp4FileDataPtr->videoTrackPtr->
2707                    nbOfAllocatedStssBlocks
2708                    - 1) * M4MP4W_STSS_ALLOC_SIZE,
2709                    mMp4FileDataPtr->videoTrackPtr->
2710                    nbOfAllocatedStssBlocks
2711                    * M4MP4W_STSS_ALLOC_SIZE);
2712                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STSS
2713                    != M4OSA_NULL, M4ERR_ALLOC);
2714            }
2715
2716#endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
2717
2718            mMp4FileDataPtr->videoTrackPtr->
2719                TABLE_STSS[mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb] =
2720                mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb;
2721            mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb += 1;
2722            mMp4FileDataPtr->filesize += 4;
2723        }
2724
2725        /* Warning: time conversion cast 64to32! */
2726        mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS =
2727            (M4MP4W_Time32)auPtr->CTS;
2728    }
2729    else
2730        return M4ERR_BAD_STREAM_ID;
2731
2732    /* I moved some state modification to after we know the sample has been written correctly. */
2733    if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_TRUE)
2734        && (streamID == VideoStreamID))
2735    {
2736        mMp4FileDataPtr->audioMsStopTime =
2737            (M4MP4W_Time32)(auPtr->CTS * scale_video);
2738    }
2739
2740    if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_FALSE)
2741        || (streamID == VideoStreamID))
2742    {
2743        /*update fileSize*/
2744        mMp4FileDataPtr->filesize += auPtr->size;
2745    }
2746
2747    if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_TRUE)
2748        && (streamID == VideoStreamID))
2749    {
2750        /*update filesize with estimated audio data that will be added later.    */
2751        /*Warning: Assumption is made that:                                     */
2752        /* - audio samples have constant size (e.g. no sid).                    */
2753        /* - max audio sample size has been set, and is the actual sample size. */
2754
2755        ERR_CHECK(mMp4FileDataPtr->audioMsChunkDur != 0,
2756            M4WAR_MP4W_NOT_EVALUABLE);
2757        mMp4FileDataPtr->filesize -=
2758            (M4OSA_UInt32)(( mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS
2759            * scale_video) * (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        mMp4FileDataPtr->filesize += (M4OSA_UInt32)(( auPtr->CTS * scale_video)
2765            * (0.05/*always 50 AMR samples per second*/
2766            *(M4OSA_Double)mMp4FileDataPtr->audioTrackPtr->MaxAUSize
2767            + 16/*additional data for a new chunk*/
2768            / (M4OSA_Double)mMp4FileDataPtr->audioMsChunkDur));
2769    }
2770
2771    M4OSA_TRACE1_4("processAU : size 0x%x mode %d filesize %lu limit %lu",
2772        auPtr->size, auPtr->attribute, mMp4FileDataPtr->filesize,
2773        mMp4FileDataPtr->MaxFileSize);
2774
2775    return err;
2776}
2777
2778/*******************************************************************************/
2779M4OSA_ERR M4MP4W_closeWrite( M4OSA_Context context )
2780/*******************************************************************************/
2781{
2782    M4OSA_ERR err = M4NO_ERROR;
2783    M4OSA_ERR err2 = M4NO_ERROR, err3 = M4NO_ERROR;
2784
2785    /*Warning: test should be done here to ensure context->pContext is not M4OSA_NULL,
2786     but C is not C++...*/
2787    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
2788
2789    M4OSA_UChar camcoder_maj, camcoder_min, camcoder_rev; /*camcoder version*/
2790    M4OSA_Bool bAudio =
2791        (( mMp4FileDataPtr->hasAudio)
2792        && (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb
2793        != 0)); /*((mMp4FileDataPtr->audioTrackPtr != M4OSA_NULL) &&
2794                    (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb != 0));*/
2795    M4OSA_Bool bVideo =
2796        (( mMp4FileDataPtr->hasVideo)
2797        && (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
2798        != 0)); /*((mMp4FileDataPtr->videoTrackPtr != M4OSA_NULL) &&
2799                    (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb != 0));*/
2800    M4OSA_Bool bH263 = M4OSA_FALSE;
2801    M4OSA_Bool bH264 = M4OSA_FALSE;
2802    M4OSA_Bool bMP4V = M4OSA_FALSE;
2803    M4OSA_Bool bAAC = M4OSA_FALSE;
2804    M4OSA_Bool bEVRC = M4OSA_FALSE;
2805
2806    /*intermediate variables*/
2807    M4OSA_UInt32 A, B, N, AB4N;
2808
2809    /*Trak variables*/
2810    M4OSA_UInt32 a_trakId = AudioStreamID; /*     (audio=1)*/
2811    /* first trak offset is 32+moovSize, second equals 32+moovSize+1st_track_size*/
2812    M4OSA_UInt32 a_trakOffset = 32;
2813    M4OSA_UInt32 a_sttsSize = 24;          /* A (audio=24)*/
2814    M4OSA_UInt32 a_stszSize = 20;          /* B (audio=20)*/
2815    M4OSA_UInt32 a_trakSize = 402;         /*     (audio=402)*/
2816    M4OSA_UInt32 a_mdiaSize = 302;         /*     (audio=302)*/
2817    M4OSA_UInt32 a_minfSize = 229;         /*     (audio=229)*/
2818    M4OSA_UInt32 a_stblSize = 169;         /*     (audio=169)*/
2819    M4OSA_UInt32 a_stsdSize = 69;          /*     (audio=69 )*/
2820    M4OSA_UInt32 a_esdSize = 53;           /*     (audio=53 )*/
2821    M4OSA_UInt32 a_dataSize = 0;           /* temp: At the end, = currentPos*/
2822    M4MP4W_Time32 a_trakDuration = 0;      /* equals lastCTS*/
2823    M4MP4W_Time32 a_msTrakDuration = 0;
2824    M4OSA_UInt32 a_stscSize = 28;          /* 16+12*nbchunksaudio*/
2825    M4OSA_UInt32 a_stcoSize = 20;          /* 16+4*nbchunksaudio*/
2826
2827    M4OSA_UInt32 v_trakId = VideoStreamID; /* (video=2)*/
2828    /* first trak offset is 32+moovSize, second equals 32+moovSize+1st_track_size*/
2829    M4OSA_UInt32 v_trakOffset = 32;
2830    M4OSA_UInt32 v_sttsSize = 0;      /* A (video=16+8J)*/
2831    M4OSA_UInt32 v_stszSize = 0;      /* B (video=20+4K)*/
2832    M4OSA_UInt32 v_trakSize = 0; /* (h263=A+B+4N+426), (mp4v=A+B+dsi+4N+448) */
2833    M4OSA_UInt32 v_mdiaSize = 0; /* (h263=A+B+4N+326), (mp4v=A+B+dsi+4N+348) */
2834    M4OSA_UInt32 v_minfSize = 0; /* (h263=A+B+4N+253), (mp4v=A+B+dsi+4N+275) */
2835    M4OSA_UInt32 v_stblSize = 0; /* (h263=A+B+4N+189), (mp4v=A+B+dsi+4N+211) */
2836    M4OSA_UInt32 v_stsdSize = 0;      /* (h263=117)        , (mp4v=139+dsi    )*/
2837    M4OSA_UInt32 v_esdSize = 0;       /* (h263=101)        , (mp4v=153+dsi    )*/
2838    M4OSA_UInt32 v_dataSize = 0;      /* temp: At the end, = currentPos*/
2839    M4MP4W_Time32 v_trakDuration = 0; /* equals lastCTS*/
2840    M4MP4W_Time32 v_msTrakDuration = 0;
2841    M4OSA_UInt32 v_stscSize = 28;     /* 16+12*nbchunksvideo*/
2842    M4OSA_UInt32 v_stcoSize = 20;     /* 16+4*nbchunksvideo*/
2843
2844    /*video variables*/
2845    M4OSA_UInt32 v_stssSize = 0; /* 4*N+16     STSS*/
2846
2847    /*aac & mp4v temp variable*/
2848    M4OSA_UInt8 dsi = 0;
2849
2850    /*H264 variables*/
2851    M4OSA_UInt32 v_avcCSize = 0; /* dsi+15*/
2852
2853    /*MP4V variables*/
2854    M4OSA_UInt32 v_esdsSize = 0;        /* dsi+37*/
2855    M4OSA_UInt8 v_ESDescriptorSize =
2856        0; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
2857    M4OSA_UInt8 v_DCDescriptorSize = 0; /* dsi+15*/
2858
2859    /*AAC variables*/
2860    M4OSA_UInt32 a_esdsSize = 0;        /* dsi+37*/
2861    M4OSA_UInt8 a_ESDescriptorSize =
2862        0; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
2863    M4OSA_UInt8 a_DCDescriptorSize = 0; /* dsi+15*/
2864
2865    /*General variables*/
2866
2867    /* audio chunk size + video chunk size*/
2868    M4OSA_UInt32 mdatSize = 8;
2869    M4OSA_UInt32 moovSize = 116; /* 116 + 402(audio) +    (A+B+4N+426)(h263) or */
2870    /*                        (A+B+dsi+4N+448)(mp4v)    */
2871    M4OSA_UInt32 creationTime; /* C */
2872
2873    /*flag to set up the chunk interleave strategy*/
2874    M4OSA_Bool bInterleaveAV =
2875        (bAudio && bVideo && (mMp4FileDataPtr->InterleaveDur != 0));
2876
2877    M4OSA_Context fileWriterContext = mMp4FileDataPtr->fileWriterContext;
2878
2879    M4OSA_UInt32 i;
2880
2881    M4OSA_Double scale_audio = 0.0;
2882    M4OSA_Double scale_video = 0.0;
2883    M4MP4W_Time32 delta;
2884
2885#ifndef _M4MP4W_MOOV_FIRST
2886
2887    M4OSA_FilePosition moovPos, mdatPos;
2888
2889#endif /*_M4MP4W_MOOV_FIRST*/
2890
2891    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
2892
2893    /*macro state */
2894    mMp4FileDataPtr->state = M4MP4W_closed;
2895
2896    /*if no data !*/
2897    if ((!bAudio) && (!bVideo))
2898    {
2899        err = M4NO_ERROR; /*would be better to return a warning ?*/
2900        goto cleanup;
2901    }
2902
2903#ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
2904    /* Remove safety file to make room for what needs to be written out here
2905    (chunk flushing and moov). */
2906
2907    if (M4OSA_TRUE == mMp4FileDataPtr->cleanSafetyFile)
2908    {
2909        M4OSA_Context tempContext;
2910        err = mMp4FileDataPtr->fileWriterFunctions->openWrite(&tempContext,
2911            mMp4FileDataPtr->safetyFileUrl,
2912            M4OSA_kFileWrite | M4OSA_kFileCreate);
2913
2914        if (M4NO_ERROR != err)
2915            goto cleanup;
2916        err = mMp4FileDataPtr->fileWriterFunctions->closeWrite(tempContext);
2917
2918        if (M4NO_ERROR != err)
2919            goto cleanup;
2920        mMp4FileDataPtr->safetyFileUrl = M4OSA_NULL;
2921        mMp4FileDataPtr->cleanSafetyFile = M4OSA_FALSE;
2922    }
2923
2924#endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
2925
2926    if (bVideo)
2927    {
2928        if ((M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable)
2929            || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->chunkSizeTable)
2930            || (M4OSA_NULL
2931            == mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable)
2932            || (M4OSA_NULL
2933            == mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable)
2934            || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ)
2935            || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->TABLE_STTS)
2936            || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->TABLE_STSS))
2937        {
2938            mMp4FileDataPtr->fileWriterFunctions->closeWrite(
2939                fileWriterContext); /**< close the stream anyway */
2940            M4MP4W_freeContext(context); /**< Free the context content */
2941            return M4ERR_ALLOC;
2942        }
2943
2944        /*video microstate*/
2945        mMp4FileDataPtr->videoTrackPtr->microState = M4MP4W_closed;
2946
2947        /*current chunk is the last one and gives the total number of video chunks (-1)*/
2948        for ( i = 0; i < mMp4FileDataPtr->videoTrackPtr->currentChunk; i++ )
2949        {
2950            v_dataSize += mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i];
2951        }
2952
2953#ifndef _M4MP4W_MOOV_FIRST
2954#ifndef _M4MP4W_UNBUFFERED_VIDEO
2955        /*flush chunk*/
2956
2957        if (mMp4FileDataPtr->videoTrackPtr->currentPos > 0)
2958        {
2959            err = M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[0],
2960                mMp4FileDataPtr->videoTrackPtr->currentPos,
2961                mMp4FileDataPtr->fileWriterFunctions,
2962                mMp4FileDataPtr->fileWriterContext);
2963
2964            if (M4NO_ERROR != err)
2965                goto cleanup;
2966        }
2967
2968#endif
2969
2970        M4OSA_TRACE1_0("flush video | CLOSE");
2971        M4OSA_TRACE1_3("current chunk = %d  offset = 0x%x size = 0x%08X",
2972            mMp4FileDataPtr->videoTrackPtr->currentChunk,
2973            mMp4FileDataPtr->absoluteCurrentPos,
2974            mMp4FileDataPtr->videoTrackPtr->currentPos);
2975
2976        /*update chunk offset*/
2977        mMp4FileDataPtr->videoTrackPtr->
2978            chunkOffsetTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
2979            mMp4FileDataPtr->absoluteCurrentPos;
2980
2981        /*add chunk size to absoluteCurrentPos*/
2982        mMp4FileDataPtr->absoluteCurrentPos +=
2983            mMp4FileDataPtr->videoTrackPtr->currentPos;
2984#endif /*_M4MP4W_MOOV_FIRST*/
2985
2986        /*update last chunk size, and add this value to v_dataSize*/
2987
2988        mMp4FileDataPtr->videoTrackPtr->
2989            chunkSizeTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
2990            mMp4FileDataPtr->videoTrackPtr->currentPos;
2991        v_dataSize +=
2992            mMp4FileDataPtr->videoTrackPtr->currentPos; /*add last chunk size*/
2993
2994        v_trakDuration = mMp4FileDataPtr->videoTrackPtr->
2995            CommonData.lastCTS; /* equals lastCTS*/
2996
2997        /* bugfix: if a new chunk was just created, cancel it before to close */
2998        if ((mMp4FileDataPtr->videoTrackPtr->currentChunk != 0)
2999            && (mMp4FileDataPtr->videoTrackPtr->currentPos == 0))
3000        {
3001            mMp4FileDataPtr->videoTrackPtr->currentChunk--;
3002        }
3003#ifdef _M4MP4W_UNBUFFERED_VIDEO
3004
3005        if ((mMp4FileDataPtr->videoTrackPtr->
3006            chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->
3007            currentStsc] & 0xFFF) == 0)
3008        {
3009            mMp4FileDataPtr->videoTrackPtr->currentStsc--;
3010        }
3011
3012#endif /*_M4MP4W_UNBUFFERED_VIDEO*/
3013
3014        /* Last sample duration */
3015        /* If we have the file duration we use it, else we duplicate the last AU */
3016
3017        if (mMp4FileDataPtr->MaxFileDuration > 0)
3018        {
3019            /* use max file duration to calculate delta of last AU */
3020            delta = mMp4FileDataPtr->MaxFileDuration
3021                - mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS;
3022            v_trakDuration = mMp4FileDataPtr->MaxFileDuration;
3023
3024            if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb > 1)
3025            {
3026                /* if more than 1 frame, create a new stts entry (else already created) */
3027                mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb++;
3028            }
3029
3030#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3031
3032            M4MP4W_put32_Lo(&mMp4FileDataPtr->videoTrackPtr->
3033                TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
3034                CommonData.sttsTableEntryNb - 1], 1);
3035            M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->
3036                TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
3037                CommonData.sttsTableEntryNb - 1], delta);
3038
3039#else
3040
3041            mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
3042                *(mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
3043                - 1)] = 1;
3044            mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
3045                *(mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
3046                - 1) + 1] = delta;
3047
3048#endif
3049
3050        }
3051        else
3052        {
3053            /* duplicate the delta of the previous frame */
3054            if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb > 1)
3055            {
3056                /* if more than 1 frame, duplicate the stts entry (else already exists) */
3057#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3058
3059                v_trakDuration +=
3060                    M4MP4W_get32_Hi(&mMp4FileDataPtr->videoTrackPtr->
3061                    TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
3062                    CommonData.sttsTableEntryNb - 1]);
3063                mMp4FileDataPtr->videoTrackPtr->
3064                    TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
3065                    CommonData.sttsTableEntryNb - 1] += 1;
3066
3067#else
3068
3069                v_trakDuration += mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
3070                    * (mMp4FileDataPtr->videoTrackPtr->
3071                    CommonData.sttsTableEntryNb - 1) + 1];
3072                mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2 *(
3073                    mMp4FileDataPtr->videoTrackPtr->
3074                    CommonData.sttsTableEntryNb - 1)] += 1;
3075
3076#endif
3077
3078            }
3079            else
3080            {
3081                M4OSA_TRACE1_0("M4MP4W_closeWrite : ! videoTrackPtr,\
3082                     cannot know the duration of the unique AU !");
3083                /* If there is an audio track, we use it as a file duration
3084                (and so, as AU duration...) */
3085                if (mMp4FileDataPtr->audioTrackPtr != M4OSA_NULL)
3086                {
3087                    M4OSA_TRACE1_0(
3088                        "M4MP4W_closeWrite : ! Let's use the audio track duration !");
3089                    mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] =
3090                        (M4OSA_UInt32)(
3091                        mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS
3092                        * (1000.0 / mMp4FileDataPtr->audioTrackPtr->
3093                        CommonData.timescale));
3094                    v_trakDuration =
3095                        mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1];
3096                }
3097                /* Else, we use a MAGICAL value (66 ms) */
3098                else
3099                {
3100                    M4OSA_TRACE1_0(
3101                        "M4MP4W_closeWrite : ! No audio track -> use magical value (66) !"); /*    */
3102                    mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] = 66;
3103                    v_trakDuration = 66;
3104                }
3105            }
3106        }
3107
3108        /* Calculate table sizes */
3109        A = v_sttsSize = 16 + 8 * mMp4FileDataPtr->videoTrackPtr->
3110            CommonData.sttsTableEntryNb; /* A (video=16+8J)*/
3111        B = v_stszSize = 20 + 4 * mMp4FileDataPtr->videoTrackPtr->
3112            CommonData.sampleNb; /* B (video=20+4K)*/
3113        N = mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb;
3114        AB4N = A + B + 4 * N;
3115
3116        scale_video =
3117            1000.0 / mMp4FileDataPtr->videoTrackPtr->CommonData.timescale;
3118        v_msTrakDuration = (M4OSA_UInt32)(v_trakDuration * scale_video);
3119
3120        /*Convert integers in the table from LE into BE*/
3121#ifndef _M4MP4W_OPTIMIZE_FOR_PHONE
3122
3123        M4MP4W_table32ToBE(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ,
3124            mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb);
3125        M4MP4W_table32ToBE(mMp4FileDataPtr->videoTrackPtr->TABLE_STTS,
3126            2 * (mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb));
3127
3128#endif
3129
3130        M4MP4W_table32ToBE(mMp4FileDataPtr->videoTrackPtr->TABLE_STSS,
3131            mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb);
3132
3133        if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
3134            == M4SYS_kH263)
3135        {
3136            bH263 = M4OSA_TRUE;
3137            v_trakSize = AB4N + 426; /* (h263=A+B+4N+426)*/
3138            v_mdiaSize = AB4N + 326; /* (h263=A+B+4N+326)*/
3139            v_minfSize = AB4N + 253; /* (h263=A+B+4N+253)*/
3140            v_stblSize = AB4N + 189; /* (h263=A+B+4N+189)*/
3141            v_stsdSize = 117;        /* (h263=117)*/
3142            v_esdSize = 101;         /* (h263=101)*/
3143
3144            moovSize += AB4N + 426;
3145
3146            if (((M4OSA_Int32)mMp4FileDataPtr->videoTrackPtr->avgBitrate) != -1)
3147            {
3148                /*the optional 'bitr' atom is appended to the dsi,so filesize is 16 bytes bigger*/
3149                v_trakSize += 16;
3150                v_mdiaSize += 16;
3151                v_minfSize += 16;
3152                v_stblSize += 16;
3153                v_stsdSize += 16;
3154                v_esdSize += 16;
3155                moovSize += 16;
3156            }
3157        }
3158        else if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
3159            == M4SYS_kH264)
3160        {
3161            bH264 = M4OSA_TRUE;
3162            /* For H264 there is no default DSI, and its presence is mandatory,
3163            so check the DSI has been set*/
3164            if (0 == mMp4FileDataPtr->videoTrackPtr->dsiSize
3165                || M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
3166            {
3167                M4OSA_TRACE1_0(
3168                    "M4MP4W_closeWrite: error, no H264 DSI has been set!");
3169                err = M4ERR_STATE;
3170                goto cleanup;
3171            }
3172
3173            /*H264 sizes of the atom*/
3174
3175            // Remove the hardcoded DSI values of H264Block2
3176            // TODO: check bMULPPSSPS case
3177            v_avcCSize = sizeof(M4OSA_UInt32) + sizeof(H264Block2) +
3178                mMp4FileDataPtr->videoTrackPtr->dsiSize;
3179
3180            v_trakSize = AB4N + v_avcCSize + 411;
3181            v_mdiaSize = AB4N + v_avcCSize + 311;
3182            v_minfSize = AB4N + v_avcCSize + 238;
3183            v_stblSize = AB4N + v_avcCSize + 174;
3184            v_stsdSize =        v_avcCSize + 102;
3185            v_esdSize  =        v_avcCSize + 86;
3186
3187            moovSize   += AB4N + v_avcCSize + 411;
3188
3189        }
3190        else if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
3191            == M4SYS_kMPEG_4)
3192        {
3193            bMP4V = M4OSA_TRUE;
3194            /* For MPEG4 there is no default DSI, and its presence is mandatory,
3195            so check the DSI has been set*/
3196            if (0 == mMp4FileDataPtr->videoTrackPtr->dsiSize
3197                || M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
3198            {
3199                M4OSA_TRACE1_0(
3200                    "M4MP4W_closeWrite: error, no MPEG4 DSI has been set!");
3201                err = M4ERR_STATE;
3202                goto cleanup;
3203            }
3204
3205            /*MP4V variables*/
3206            dsi = mMp4FileDataPtr->videoTrackPtr->dsiSize;
3207            v_esdsSize = 37 + dsi;         /* dsi+37*/
3208            v_ESDescriptorSize =
3209                23
3210                + dsi; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
3211            v_DCDescriptorSize = 15 + dsi; /* dsi+15*/
3212
3213            v_trakSize = AB4N + dsi + 448; /* (mp4v=A+B+dsi+4N+448)    */
3214            v_mdiaSize = AB4N + dsi + 348; /* (mp4v=A+B+dsi+4N+348)    */
3215            v_minfSize = AB4N + dsi + 275; /* (mp4v=A+B+dsi+4N+275)    */
3216            v_stblSize = AB4N + dsi + 211; /* (mp4v=A+B+dsi+4N+211)    */
3217            v_stsdSize = dsi + 139;        /* (mp4v=139+dsi)*/
3218            v_esdSize = dsi + 123;         /* (mp4v=123+dsi)*/
3219
3220            moovSize += AB4N + dsi + 448;
3221        }
3222
3223        /*video variables*/
3224        v_stssSize = 16 + 4 * N; /* 4*N+16     STSS*/
3225
3226#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3227        /* stsc update */
3228
3229        v_stscSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3230        v_stblSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3231        v_minfSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3232        v_mdiaSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3233        v_trakSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3234        moovSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3235
3236        /* stco update */
3237        v_stcoSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3238        v_stblSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3239        v_minfSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3240        v_mdiaSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3241        v_trakSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3242        moovSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3243
3244#else
3245        /*stsc/stco update*/
3246
3247        v_stscSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3248        v_stcoSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3249        v_stblSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3250        v_minfSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3251        v_mdiaSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3252        v_trakSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3253        moovSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3254
3255#endif
3256
3257        /*update last chunk time*/
3258
3259        mMp4FileDataPtr->videoTrackPtr->
3260            chunkTimeMsTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
3261            v_msTrakDuration;
3262    }
3263
3264    if (bAudio)
3265    {
3266        if ((M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable)
3267            || (M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->chunkSizeTable)
3268            || (M4OSA_NULL
3269            == mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable)
3270            || (M4OSA_NULL
3271            == mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable)
3272            || (M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->TABLE_STTS))
3273        {
3274            mMp4FileDataPtr->fileWriterFunctions->closeWrite(
3275                fileWriterContext); /**< close the stream anyway */
3276            M4MP4W_freeContext(context); /**< Free the context content */
3277            return M4ERR_ALLOC;
3278        }
3279
3280        /*audio microstate*/
3281        mMp4FileDataPtr->audioTrackPtr->microState = M4MP4W_closed;
3282
3283        if (mMp4FileDataPtr->audioTrackPtr->CommonData.trackType == M4SYS_kAAC)
3284        {
3285            bAAC =
3286                M4OSA_TRUE; /*else, audio is implicitely amr in the following*/
3287            dsi = mMp4FileDataPtr->audioTrackPtr->dsiSize; /*variable size*/
3288
3289            a_esdsSize = 37 + dsi;                         /* dsi+37*/
3290            a_ESDescriptorSize =
3291                23
3292                + dsi; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
3293            a_DCDescriptorSize = 15 + dsi;                 /* dsi+15*/
3294
3295            a_esdSize = dsi + 73; /*overwrite a_esdSize with aac value*/
3296            /*add dif. between amr & aac sizes: (- 53 + dsi + 37)*/
3297            a_stsdSize += dsi + 20;
3298            a_stblSize += dsi + 20;
3299            a_minfSize += dsi + 20;
3300            a_mdiaSize += dsi + 20;
3301            a_trakSize += dsi + 20;
3302            moovSize += dsi + 20;
3303        }
3304
3305        if (mMp4FileDataPtr->audioTrackPtr->CommonData.trackType
3306            == M4SYS_kEVRC)
3307        {
3308            bEVRC =
3309                M4OSA_TRUE; /*else, audio is implicitely amr in the following*/
3310
3311            /* evrc dsi is only 6 bytes while amr dsi is 9 bytes,all other blocks are unchanged */
3312            a_esdSize -= 3;
3313            a_stsdSize -= 3;
3314            a_stblSize -= 3;
3315            a_minfSize -= 3;
3316            a_mdiaSize -= 3;
3317            a_trakSize -= 3;
3318            moovSize -= 3;
3319        }
3320
3321        if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize == 0)
3322        {
3323            if (M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ)
3324            {
3325                mMp4FileDataPtr->fileWriterFunctions->closeWrite(
3326                    fileWriterContext); /**< close the stream anyway */
3327                M4MP4W_freeContext(context); /**< Free the context content */
3328                return M4ERR_ALLOC;
3329            }
3330            /*Convert integers in the table from LE into BE*/
3331            M4MP4W_table32ToBE(mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ,
3332                mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb);
3333            a_stszSize +=
3334                4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3335            a_stblSize +=
3336                4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3337            a_minfSize +=
3338                4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3339            a_mdiaSize +=
3340                4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3341            a_trakSize +=
3342                4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3343            moovSize += 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3344        }
3345
3346        moovSize += 402;
3347
3348        /*current chunk is the last one and gives the total number of audio chunks (-1)*/
3349        for ( i = 0; i < mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
3350        {
3351            a_dataSize += mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i];
3352        }
3353
3354#ifndef _M4MP4W_MOOV_FIRST
3355        /*flush chunk*/
3356
3357        if (mMp4FileDataPtr->audioTrackPtr->currentPos > 0)
3358        {
3359            err = M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[0],
3360                mMp4FileDataPtr->audioTrackPtr->currentPos,
3361                mMp4FileDataPtr->fileWriterFunctions,
3362                mMp4FileDataPtr->fileWriterContext);
3363
3364            if (M4NO_ERROR != err)
3365                goto cleanup;
3366        }
3367
3368        M4OSA_TRACE1_0("flush audio | CLOSE");
3369        M4OSA_TRACE1_2("current chunk = %d  offset = 0x%x",
3370            mMp4FileDataPtr->audioTrackPtr->currentChunk,
3371            mMp4FileDataPtr->absoluteCurrentPos);
3372
3373        /*update chunk offset*/
3374        mMp4FileDataPtr->audioTrackPtr->
3375            chunkOffsetTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
3376            mMp4FileDataPtr->absoluteCurrentPos;
3377
3378        /*add chunk size to absoluteCurrentPos*/
3379        mMp4FileDataPtr->absoluteCurrentPos +=
3380            mMp4FileDataPtr->audioTrackPtr->currentPos;
3381
3382#endif /*_M4MP4W_MOOV_FIRST*/
3383
3384        /*update last chunk size, and add this value to a_dataSize*/
3385
3386        mMp4FileDataPtr->audioTrackPtr->
3387            chunkSizeTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
3388            mMp4FileDataPtr->audioTrackPtr->currentPos;
3389        a_dataSize +=
3390            mMp4FileDataPtr->audioTrackPtr->currentPos; /*add last chunk size*/
3391
3392        /* bugfix: if a new chunk was just created, cancel it before to close */
3393        if ((mMp4FileDataPtr->audioTrackPtr->currentChunk != 0)
3394            && (mMp4FileDataPtr->audioTrackPtr->currentPos == 0))
3395        {
3396            mMp4FileDataPtr->audioTrackPtr->currentChunk--;
3397        }
3398#ifdef _M4MP4W_UNBUFFERED_VIDEO
3399
3400        if ((mMp4FileDataPtr->audioTrackPtr->
3401            chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->
3402            currentStsc] & 0xFFF) == 0)
3403        {
3404            mMp4FileDataPtr->audioTrackPtr->currentStsc--;
3405        }
3406
3407#endif                                                          /*_M4MP4W_UNBUFFERED_VIDEO*/
3408
3409        a_trakDuration = mMp4FileDataPtr->audioTrackPtr->
3410            CommonData.lastCTS; /* equals lastCTS*/
3411        /* add last sample dur */
3412
3413        if (mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb != 1)
3414        {
3415#ifdef DUPLICATE_STTS_IN_LAST_AU
3416            /*increase of 1 the number of consecutive AUs with same duration*/
3417
3418            mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2
3419                *(mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb
3420                - 1) - 2] += 1;
3421
3422#endif /*DUPLICATE_STTS_IN_LAST_AU*/
3423
3424            a_trakDuration += mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2
3425                * (mMp4FileDataPtr->audioTrackPtr->
3426                CommonData.sttsTableEntryNb - 1) - 1];
3427        }
3428        else if (0 == mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS)
3429        {
3430            if (mMp4FileDataPtr->audioTrackPtr->CommonData.trackType
3431                == M4SYS_kAMR)
3432            {
3433                if (12200 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3434                {
3435                    a_trakDuration = a_dataSize / 32
3436                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3437                }
3438                else if (10200 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3439                {
3440                    a_trakDuration = a_dataSize / 27
3441                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3442                }
3443                else if (7950 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3444                {
3445                    a_trakDuration = a_dataSize / 21
3446                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3447                }
3448                else if (7400 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3449                {
3450                    a_trakDuration = a_dataSize / 20
3451                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3452                }
3453                else if (6700 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3454                {
3455                    a_trakDuration = a_dataSize / 18
3456                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3457                }
3458                else if (5900 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3459                {
3460                    a_trakDuration = a_dataSize / 16
3461                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3462                }
3463                else if (5150 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3464                {
3465                    a_trakDuration = a_dataSize / 14
3466                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3467                }
3468                else if (4750 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3469                {
3470                    a_trakDuration = a_dataSize / 13
3471                        * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3472                }
3473            }
3474        }
3475
3476        scale_audio =
3477            1000.0 / mMp4FileDataPtr->audioTrackPtr->CommonData.timescale;
3478        a_msTrakDuration = (M4OSA_UInt32)(a_trakDuration * scale_audio);
3479
3480#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3481        /* stsc update */
3482
3483        a_stscSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3484        a_stblSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3485        a_minfSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3486        a_mdiaSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3487        a_trakSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3488        moovSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3489
3490        /* stso update */
3491        a_stcoSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3492        a_stblSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3493        a_minfSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3494        a_mdiaSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3495        a_trakSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3496        moovSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3497
3498#else
3499        /*stsc/stco update*/
3500
3501        a_stscSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3502        a_stcoSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3503        a_stblSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3504        a_minfSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3505        a_mdiaSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3506        a_trakSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3507        moovSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3508
3509#endif
3510
3511        /* compute the new size of stts*/
3512
3513        a_sttsSize = 16 + 8 * (mMp4FileDataPtr->audioTrackPtr->
3514            CommonData.sttsTableEntryNb - 1);
3515
3516        moovSize += a_sttsSize - 24;
3517        a_mdiaSize += a_sttsSize - 24;
3518        a_minfSize += a_sttsSize - 24;
3519        a_stblSize += a_sttsSize - 24;
3520        a_trakSize += a_sttsSize - 24;
3521
3522        /*update last chunk time*/
3523        mMp4FileDataPtr->audioTrackPtr->
3524            chunkTimeMsTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
3525            a_msTrakDuration;
3526    }
3527
3528    /* changing the way the mdat size is computed.
3529    The real purpose of the mdat size is to know the amount to skip to get to the next
3530    atom, which is the moov; the size of media in the mdat is almost secondary. Therefore,
3531    it is of utmost importance that the mdat size "points" to where the moov actually
3532    begins. Now, the moov begins right after the last data we wrote, so how could the sum
3533    of all chunk sizes be different from the total size of what has been written? Well, it
3534    can happen when the writing was unexpectedly stopped (because of lack of disk space,
3535    for instance), in this case a chunk may be partially written (the partial write is not
3536    necessarily erased) but it may not be reflected in the chunk size list (which may
3537    believe it hasn't been written or on the contrary that it has been fully written). In
3538    the case of such a mismatch, there is either unused data in the mdat (not very good,
3539    but tolerable) or when reading the last chunk it will read the beginning of the moov
3540    as part of the chunk (which means the last chunk won't be correctly decoded), both of
3541    which are still better than losing the whole recording. In the long run it'll probably
3542    be attempted to always clean up back to a consistent state, but at any rate it is
3543    always safer to have the mdat size be computed using the position where the moov
3544    actually begins, rather than using the size it is thought the mdat has.
3545
3546    Therefore, I will record where we are just before writing the moov, to serve when
3547    updating the mdat size. */
3548
3549    /* mdatSize += a_dataSize + v_dataSize; *//*TODO allow for multiple chunks*/
3550
3551    /* End of Pierre Lebeaupin 19/12/2007: changing the way the mdat size is computed. */
3552
3553    /* first trak offset is 32+moovSize, second equals 32+moovSize+1st_track_size*/
3554    a_trakOffset += moovSize;
3555    v_trakOffset += moovSize/*+ a_dataSize*/;
3556
3557    if (bInterleaveAV == M4OSA_FALSE)
3558        v_trakOffset += a_dataSize;
3559
3560    /*system time since 1970 */
3561#ifndef _M4MP4W_DONT_USE_TIME_H
3562
3563    time((time_t *)&creationTime);
3564    /*convert into time since 1/1/1904 00h00 (normative)*/
3565    creationTime += 2082841761; /*nb of sec between 1904 and 1970*/
3566
3567#else                                            /*_M4MP4W_DONT_USE_TIME_H*/
3568
3569    creationTime =
3570        0xBBD09100; /* = 7/11/2003 00h00 ; in hexa because of code scrambler limitation with
3571                                           large integers */
3572
3573#endif                                           /*_M4MP4W_DONT_USE_TIME_H*/
3574
3575    mMp4FileDataPtr->duration =
3576        max(a_msTrakDuration, v_msTrakDuration); /*max audio/video*/
3577
3578#ifdef _M4MP4W_MOOV_FIRST
3579    /*open file in write binary mode*/
3580
3581    err = mMp4FileDataPtr->fileWriterFunctions->openWrite(&fileWriterContext,
3582        mMp4FileDataPtr->url, 0x22);
3583    ERR_CHECK(err == M4NO_ERROR, err);
3584
3585    /*ftyp atom*/
3586    if (mMp4FileDataPtr->ftyp.major_brand != 0)
3587    {
3588        M4OSA_UInt32 i;
3589
3590        /* Put customized ftyp box */
3591        CLEANUPonERR(M4MP4W_putBE32(16
3592            + (mMp4FileDataPtr->ftyp.nbCompatibleBrands * 4),
3593            mMp4FileDataPtr->fileWriterFunctions,
3594            mMp4FileDataPtr->fileWriterContext));
3595        CLEANUPonERR(M4MP4W_putBE32(M4MPAC_FTYP_TAG,
3596            mMp4FileDataPtr->fileWriterFunctions,
3597            mMp4FileDataPtr->fileWriterContext));
3598        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->ftyp.major_brand,
3599            mMp4FileDataPtr->fileWriterFunctions,
3600            mMp4FileDataPtr->fileWriterContext));
3601        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->ftyp.minor_version,
3602            mMp4FileDataPtr->fileWriterFunctions,
3603            mMp4FileDataPtr->fileWriterContext));
3604
3605        for ( i = 0; i < mMp4FileDataPtr->ftyp.nbCompatibleBrands; i++ )
3606        {
3607            CLEANUPonERR(
3608                M4MP4W_putBE32(mMp4FileDataPtr->ftyp.compatible_brands[i],
3609                mMp4FileDataPtr->fileWriterFunctions,
3610                mMp4FileDataPtr->fileWriterContext));
3611        }
3612    }
3613    else
3614    {
3615        /* Put default ftyp box */
3616        CLEANUPonERR(M4MP4W_putBlock(Default_ftyp, sizeof(Default_ftyp),
3617            mMp4FileDataPtr->fileWriterFunctions,
3618            mMp4FileDataPtr->fileWriterContext));
3619    }
3620
3621#endif /*_M4MP4W_MOOV_FIRST*/
3622
3623#ifndef _M4MP4W_MOOV_FIRST
3624    /* seek is used to get the current position relative to the start of the file. */
3625    /* ... or rather, seek used to be used for that, but it has been found this functionality
3626    is not reliably, or sometimes not at all, implemented in the various OSALs, so we now avoid
3627    using it. */
3628    /* Notice this new method assumes we're at the end of the file, this will break if ever we
3629    are overwriting a larger file. */
3630
3631    CLEANUPonERR(mMp4FileDataPtr->fileWriterFunctions->getOption(
3632        mMp4FileDataPtr->fileWriterContext,
3633        M4OSA_kFileWriteGetFileSize, (M4OSA_DataOption *) &moovPos));
3634    /* moovPos will be used after writing the moov. */
3635
3636#endif /*_M4MP4W_MOOV_FIRST*/
3637
3638    CLEANUPonERR(M4MP4W_putBE32(moovSize, mMp4FileDataPtr->fileWriterFunctions,
3639        fileWriterContext));
3640    CLEANUPonERR(M4MP4W_putBlock(CommonBlock3, sizeof(CommonBlock3),
3641        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3642    CLEANUPonERR(M4MP4W_putBE32(creationTime,
3643        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3644    CLEANUPonERR(M4MP4W_putBE32(creationTime,
3645        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3646    CLEANUPonERR(M4MP4W_putBlock(CommonBlock4, sizeof(CommonBlock4),
3647        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3648    CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->duration,
3649        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3650    CLEANUPonERR(M4MP4W_putBlock(CommonBlock5, sizeof(CommonBlock5),
3651        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3652
3653    if (bAudio)
3654    {
3655        CLEANUPonERR(M4MP4W_putBE32(a_trakSize,
3656            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3657        CLEANUPonERR(M4MP4W_putBlock(CommonBlock6, sizeof(CommonBlock6),
3658            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3659        CLEANUPonERR(M4MP4W_putBE32(creationTime,
3660            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3661        CLEANUPonERR(M4MP4W_putBE32(creationTime,
3662            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3663        CLEANUPonERR(M4MP4W_putBE32(a_trakId,
3664            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3665        CLEANUPonERR(M4MP4W_putBlock(CommonBlock7, sizeof(CommonBlock7),
3666            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3667        CLEANUPonERR(M4MP4W_putBE32(a_msTrakDuration,
3668            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3669        CLEANUPonERR(M4MP4W_putBlock(CommonBlock7bis, sizeof(CommonBlock7bis),
3670            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3671        CLEANUPonERR(M4MP4W_putBlock(AMRBlock1, sizeof(AMRBlock1),
3672            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3673        CLEANUPonERR(M4MP4W_putBE32(a_mdiaSize,
3674            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3675        CLEANUPonERR(M4MP4W_putBlock(CommonBlock8, sizeof(CommonBlock8),
3676            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3677        CLEANUPonERR(M4MP4W_putBE32(creationTime,
3678            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3679        CLEANUPonERR(M4MP4W_putBE32(creationTime,
3680            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3681        CLEANUPonERR(
3682            M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->CommonData.timescale,
3683            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3684        CLEANUPonERR(M4MP4W_putBE32(a_trakDuration,
3685            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3686        CLEANUPonERR(M4MP4W_putBlock(CommonBlock9, sizeof(CommonBlock9),
3687            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3688        CLEANUPonERR(M4MP4W_putBlock(AMRBlock1_1, sizeof(AMRBlock1_1),
3689            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3690        CLEANUPonERR(M4MP4W_putBE32(a_minfSize,
3691            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3692        CLEANUPonERR(M4MP4W_putBlock(CommonBlock10, sizeof(CommonBlock10),
3693            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3694        CLEANUPonERR(M4MP4W_putBE32(a_stblSize,
3695            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3696        CLEANUPonERR(M4MP4W_putBlock(CommonBlock11, sizeof(CommonBlock11),
3697            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3698        CLEANUPonERR(M4MP4W_putBE32(a_sttsSize,
3699            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3700        CLEANUPonERR(M4MP4W_putBlock(CommonBlock12, sizeof(CommonBlock12),
3701            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3702
3703        CLEANUPonERR(M4MP4W_putBE32(
3704            mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb - 1,
3705            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3706        /*invert the table data to bigendian*/
3707        M4MP4W_table32ToBE(mMp4FileDataPtr->audioTrackPtr->TABLE_STTS,
3708            2 * (mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb
3709            - 1));
3710        CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
3711            *)mMp4FileDataPtr->audioTrackPtr->TABLE_STTS,
3712            ( mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb - 1)
3713            * 8,
3714            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3715
3716        /* stsd */
3717        CLEANUPonERR(M4MP4W_putBE32(a_stsdSize,
3718            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3719        CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionHeader,
3720            sizeof(SampleDescriptionHeader),
3721            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3722        CLEANUPonERR(M4MP4W_putBE32(a_esdSize,
3723            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3724
3725        /* sample desc entry inside stsd */
3726        if (bAAC)
3727        {
3728            CLEANUPonERR(M4MP4W_putBlock(AACBlock1, sizeof(AACBlock1),
3729                mMp4FileDataPtr->fileWriterFunctions,
3730                fileWriterContext)); /*aac*/
3731        }
3732        else if (bEVRC)
3733        {
3734            CLEANUPonERR(M4MP4W_putBlock(EVRC8Block1, sizeof(EVRC8Block1),
3735                mMp4FileDataPtr->fileWriterFunctions,
3736                fileWriterContext)); /*evrc*/
3737        }
3738        else                         /*AMR8*/
3739        {
3740            CLEANUPonERR(M4MP4W_putBlock(AMR8Block1, sizeof(AMR8Block1),
3741                mMp4FileDataPtr->fileWriterFunctions,
3742                fileWriterContext)); /*amr8*/
3743        }
3744        CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryStart,
3745            sizeof(SampleDescriptionEntryStart),
3746            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3747        CLEANUPonERR(M4MP4W_putBlock(AudioSampleDescEntryBoilerplate,
3748            sizeof(AudioSampleDescEntryBoilerplate),
3749            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3750        CLEANUPonERR(
3751            M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->CommonData.timescale
3752            << 16,
3753            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3754
3755        /* DSI inside sample desc entry */
3756        if (bAAC)
3757        {
3758            CLEANUPonERR(M4MP4W_putBE32(a_esdsSize,
3759                mMp4FileDataPtr->fileWriterFunctions,
3760                fileWriterContext)); /*aac*/
3761            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock0,
3762                sizeof(MPEGConfigBlock0), mMp4FileDataPtr->fileWriterFunctions,
3763                fileWriterContext)); /*aac*/
3764            CLEANUPonERR(M4MP4W_putByte(a_ESDescriptorSize,
3765                mMp4FileDataPtr->fileWriterFunctions,
3766                fileWriterContext)); /*aac*/
3767            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock1,
3768                sizeof(MPEGConfigBlock1), mMp4FileDataPtr->fileWriterFunctions,
3769                fileWriterContext)); /*aac*/
3770            CLEANUPonERR(M4MP4W_putByte(a_DCDescriptorSize,
3771                mMp4FileDataPtr->fileWriterFunctions,
3772                fileWriterContext)); /*aac*/
3773            CLEANUPonERR(M4MP4W_putBlock(AACBlock2, sizeof(AACBlock2),
3774                mMp4FileDataPtr->fileWriterFunctions,
3775                fileWriterContext)); /*aac*/
3776            CLEANUPonERR(
3777                M4MP4W_putBE24(mMp4FileDataPtr->audioTrackPtr->avgBitrate * 5,
3778                mMp4FileDataPtr->fileWriterFunctions,
3779                fileWriterContext)); /*aac*/
3780            CLEANUPonERR(
3781                M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->maxBitrate,
3782                mMp4FileDataPtr->fileWriterFunctions,
3783                fileWriterContext)); /*aac*/
3784            CLEANUPonERR(
3785                M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->avgBitrate,
3786                mMp4FileDataPtr->fileWriterFunctions,
3787                fileWriterContext)); /*aac*/
3788            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock2,
3789                sizeof(MPEGConfigBlock2), mMp4FileDataPtr->fileWriterFunctions,
3790                fileWriterContext)); /*aac*/
3791            CLEANUPonERR(M4MP4W_putByte(mMp4FileDataPtr->audioTrackPtr->dsiSize,
3792                mMp4FileDataPtr->fileWriterFunctions,
3793                fileWriterContext)); /*aac*/
3794            CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->DSI,
3795                mMp4FileDataPtr->audioTrackPtr->dsiSize,
3796                mMp4FileDataPtr->fileWriterFunctions,
3797                fileWriterContext)); /*aac*/
3798            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock3,
3799                sizeof(MPEGConfigBlock3), mMp4FileDataPtr->fileWriterFunctions,
3800                fileWriterContext)); /*aac*/
3801        }
3802        else if (bEVRC)
3803        {
3804            M4OSA_UInt8 localDsi[6];
3805            M4OSA_UInt32 localI;
3806
3807            CLEANUPonERR(M4MP4W_putBlock(EVRCBlock3_1, sizeof(EVRCBlock3_1),
3808                mMp4FileDataPtr->fileWriterFunctions,
3809                fileWriterContext)); /*audio*/
3810
3811            /* copy the default block in a local variable*/
3812            for ( localI = 0; localI < 6; localI++ )
3813            {
3814                localDsi[localI] = EVRCBlock3_2[localI];
3815            }
3816            /* computes the number of sample per au */
3817            /* and stores it in the DSI*/
3818            /* assumes a char is enough to store the data*/
3819            localDsi[5] =
3820                (M4OSA_UInt8)(mMp4FileDataPtr->audioTrackPtr->sampleDuration
3821                / 160)/*EVRC 1 frame duration*/;
3822
3823            if (mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL)
3824            {
3825                /* copy vendor name */
3826                for ( localI = 0; localI < 4; localI++ )
3827                {
3828                    localDsi[localI] = (M4OSA_UInt8)(
3829                        mMp4FileDataPtr->audioTrackPtr->DSI[localI]);
3830                }
3831            }
3832            CLEANUPonERR(M4MP4W_putBlock(localDsi, 6,
3833                mMp4FileDataPtr->fileWriterFunctions,
3834                fileWriterContext)); /*audio*/
3835        }
3836        else                         /*AMR8*/
3837        {
3838            M4OSA_UInt8 localDsi[9];
3839            M4OSA_UInt32 localI;
3840
3841            CLEANUPonERR(M4MP4W_putBlock(AMRDSIHeader, sizeof(AMRDSIHeader),
3842                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3843
3844            /* copy the default block in a local variable*/
3845            for ( localI = 0; localI < 9; localI++ )
3846            {
3847                localDsi[localI] = AMRDefaultDSI[localI];
3848            }
3849            /* computes the number of sample per au */
3850            /* and stores it in the DSI*/
3851            /* assumes a char is enough to store the data*/
3852            /* ALERT! The potential of the following line of code to explode in our face
3853            is enormous when anything (sample rate or whatever) will change. This
3854            calculation would be MUCH better handled by the VES or whatever deals with
3855            the encoder more directly. */
3856            localDsi[8] =
3857                (M4OSA_UInt8)(mMp4FileDataPtr->audioTrackPtr->sampleDuration
3858                / 160)/*AMR NB 1 frame duration*/;
3859
3860            if (mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL)
3861            {
3862                /* copy vendor name */
3863                for ( localI = 0; localI < 4; localI++ )
3864                {
3865                    localDsi[localI] = (M4OSA_UInt8)(
3866                        mMp4FileDataPtr->audioTrackPtr->DSI[localI]);
3867                }
3868
3869                /* copy the Mode Set */
3870                for ( localI = 5; localI < 7; localI++ )
3871                {
3872                    localDsi[localI] = (M4OSA_UInt8)(
3873                        mMp4FileDataPtr->audioTrackPtr->DSI[localI]);
3874                }
3875            }
3876            CLEANUPonERR(M4MP4W_putBlock(localDsi, 9,
3877                mMp4FileDataPtr->fileWriterFunctions,
3878                fileWriterContext)); /*audio*/
3879        }
3880
3881        /*end trak*/
3882        CLEANUPonERR(M4MP4W_putBE32(a_stszSize,
3883            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3884        CLEANUPonERR(M4MP4W_putBlock(CommonBlock15, sizeof(CommonBlock15),
3885            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3886        CLEANUPonERR(M4MP4W_putBE32(
3887            mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize,
3888            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3889        CLEANUPonERR(
3890            M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb,
3891            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3892
3893        /*0 value for samplesize means not constant AU size*/
3894        if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize == 0)
3895        {
3896            CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
3897                *)mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ,
3898                mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb * 4,
3899                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3900        }
3901
3902        CLEANUPonERR(M4MP4W_putBE32(a_stscSize,
3903            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3904        CLEANUPonERR(M4MP4W_putBlock(CommonBlock16, sizeof(CommonBlock16),
3905            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3906
3907#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3908
3909        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->currentStsc
3910            + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3911
3912        for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentStsc; i++ )
3913        {
3914            CLEANUPonERR(M4MP4W_putBE32(
3915                ( mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable[i]
3916            >> 12) + 1, mMp4FileDataPtr->fileWriterFunctions,
3917                fileWriterContext));
3918            CLEANUPonERR(M4MP4W_putBE32((mMp4FileDataPtr->audioTrackPtr->
3919                chunkSampleNbTable[i] & 0xFFF),
3920                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3921            CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
3922                fileWriterContext));
3923        }
3924
3925#else
3926
3927        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->currentChunk
3928            + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3929
3930        for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
3931        {
3932            CLEANUPonERR(M4MP4W_putBE32(i + 1,
3933                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3934            CLEANUPonERR(M4MP4W_putBE32(
3935                mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable[i],
3936                mMp4FileDataPtr->fileWriterFunctions,
3937                fileWriterContext));
3938            CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
3939                fileWriterContext));
3940        }
3941
3942#endif
3943
3944        CLEANUPonERR(M4MP4W_putBE32(a_stcoSize,
3945            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3946        CLEANUPonERR(M4MP4W_putBlock(CommonBlock17, sizeof(CommonBlock17),
3947            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3948        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->currentChunk
3949            + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3950
3951#ifdef _M4MP4W_MOOV_FIRST
3952
3953        for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
3954        {
3955            CLEANUPonERR(M4MP4W_putBE32(a_trakOffset,
3956                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3957            a_trakOffset += mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i];
3958
3959            if (( bInterleaveAV == M4OSA_TRUE)
3960                && (mMp4FileDataPtr->videoTrackPtr->currentChunk >= i))
3961            {
3962                a_trakOffset +=
3963                    mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i];
3964            }
3965        }
3966
3967#else
3968
3969        for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
3970        {
3971            CLEANUPonERR(M4MP4W_putBE32(
3972                mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable[i],
3973                mMp4FileDataPtr->fileWriterFunctions,
3974                fileWriterContext));
3975        }
3976
3977#endif                                                                 /*_M4MP4W_MOOV_FIRST*/
3978
3979        CLEANUPonERR(M4MP4W_putBlock(AMRBlock4, sizeof(AMRBlock4),
3980            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3981    }
3982
3983    if (bVideo)
3984    {
3985        /*trak*/
3986        CLEANUPonERR(M4MP4W_putBE32(v_trakSize,
3987            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3988        CLEANUPonERR(M4MP4W_putBlock(CommonBlock6, sizeof(CommonBlock6),
3989            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3990        CLEANUPonERR(M4MP4W_putBE32(creationTime,
3991            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3992        CLEANUPonERR(M4MP4W_putBE32(creationTime,
3993            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3994        CLEANUPonERR(M4MP4W_putBE32(v_trakId,
3995            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3996        CLEANUPonERR(M4MP4W_putBlock(CommonBlock7, sizeof(CommonBlock7),
3997            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3998        CLEANUPonERR(M4MP4W_putBE32(v_msTrakDuration,
3999            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4000        CLEANUPonERR(M4MP4W_putBlock(CommonBlock7bis, sizeof(CommonBlock7bis),
4001            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4002
4003        /* In the track header width and height are 16.16 fixed point values,
4004        so shift left the regular integer value by 16. */
4005        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->width << 16,
4006            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4007        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->height
4008            << 16,
4009            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4010
4011        CLEANUPonERR(M4MP4W_putBE32(v_mdiaSize,
4012            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4013        CLEANUPonERR(M4MP4W_putBlock(CommonBlock8, sizeof(CommonBlock8),
4014            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4015        CLEANUPonERR(M4MP4W_putBE32(creationTime,
4016            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4017        CLEANUPonERR(M4MP4W_putBE32(creationTime,
4018            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4019        CLEANUPonERR(
4020            M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->CommonData.timescale,
4021            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4022        CLEANUPonERR(M4MP4W_putBE32(v_trakDuration,
4023            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4024        CLEANUPonERR(M4MP4W_putBlock(CommonBlock9, sizeof(CommonBlock9),
4025            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4026        CLEANUPonERR(M4MP4W_putBlock(VideoBlock1_1, sizeof(VideoBlock1_1),
4027            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4028        CLEANUPonERR(M4MP4W_putBE32(v_minfSize,
4029            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4030        CLEANUPonERR(M4MP4W_putBlock(CommonBlock10, sizeof(CommonBlock10),
4031            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4032        CLEANUPonERR(M4MP4W_putBE32(v_stblSize,
4033            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4034        CLEANUPonERR(M4MP4W_putBlock(CommonBlock11, sizeof(CommonBlock11),
4035            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4036        CLEANUPonERR(M4MP4W_putBE32(v_sttsSize,
4037            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4038        CLEANUPonERR(M4MP4W_putBlock(CommonBlock12, sizeof(CommonBlock12),
4039            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4040        CLEANUPonERR(M4MP4W_putBE32(
4041            mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb,
4042            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4043#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
4044
4045        for ( i = 0;
4046            i < mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb;
4047            i++ )
4048        {
4049            CLEANUPonERR(M4MP4W_putBE32(M4MP4W_get32_Lo(
4050                &mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[i]),
4051                mMp4FileDataPtr->fileWriterFunctions,
4052                fileWriterContext)); /*video*/
4053            CLEANUPonERR(M4MP4W_putBE32(M4MP4W_get32_Hi(
4054                &mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[i]),
4055                mMp4FileDataPtr->fileWriterFunctions,
4056                fileWriterContext)); /*video*/
4057        }
4058
4059#else
4060
4061        CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
4062            *)mMp4FileDataPtr->videoTrackPtr->TABLE_STTS,
4063            ( mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb) * 8,
4064            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4065
4066#endif
4067
4068        /* stsd */
4069
4070        CLEANUPonERR(M4MP4W_putBE32(v_stsdSize,
4071            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4072        CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionHeader,
4073            sizeof(SampleDescriptionHeader),
4074            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4075        CLEANUPonERR(M4MP4W_putBE32(v_esdSize,
4076            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4077
4078        /* sample desc entry inside stsd */
4079        if (bMP4V)
4080        {
4081            CLEANUPonERR(M4MP4W_putBlock(Mp4vBlock1, sizeof(Mp4vBlock1),
4082                mMp4FileDataPtr->fileWriterFunctions,
4083                fileWriterContext)); /*mp4v*/
4084        }
4085
4086        if (bH263)
4087        {
4088            CLEANUPonERR(M4MP4W_putBlock(H263Block1, sizeof(H263Block1),
4089                mMp4FileDataPtr->fileWriterFunctions,
4090                fileWriterContext)); /*h263*/
4091        }
4092
4093        if (bH264)
4094        {
4095            CLEANUPonERR(M4MP4W_putBlock(H264Block1, sizeof(H264Block1),
4096                mMp4FileDataPtr->fileWriterFunctions,
4097                fileWriterContext)); /*h264*/
4098        }
4099        CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryStart,
4100            sizeof(SampleDescriptionEntryStart),
4101            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4102        CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryVideoBoilerplate1,
4103            sizeof(SampleDescriptionEntryVideoBoilerplate1),
4104            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4105        CLEANUPonERR(M4MP4W_putBE16(mMp4FileDataPtr->videoTrackPtr->width,
4106            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4107        CLEANUPonERR(M4MP4W_putBE16(mMp4FileDataPtr->videoTrackPtr->height,
4108            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4109        CLEANUPonERR(M4MP4W_putBlock(VideoResolutions, sizeof(VideoResolutions),
4110            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*mp4v*/
4111        CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryVideoBoilerplate2,
4112            sizeof(SampleDescriptionEntryVideoBoilerplate2),
4113            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4114
4115        /* DSI inside sample desc entry */
4116        if (bH263)
4117        {
4118            /* The h263 dsi given through the api must be 7 bytes, that is, it shall not include
4119             the optional bitrate box. However, if the bitrate information is set in the stream
4120             handler, a bitrate box is appended here to the dsi */
4121            if (((M4OSA_Int32)mMp4FileDataPtr->videoTrackPtr->avgBitrate) != -1)
4122            {
4123                CLEANUPonERR(M4MP4W_putBlock(H263Block2_bitr,
4124                    sizeof(H263Block2_bitr),
4125                    mMp4FileDataPtr->fileWriterFunctions,
4126                    fileWriterContext)); /* d263 box with bitr atom */
4127
4128                if (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
4129                {
4130                    CLEANUPonERR(M4MP4W_putBlock(H263Block3, sizeof(H263Block3),
4131                        mMp4FileDataPtr->fileWriterFunctions,
4132                        fileWriterContext)); /*h263*/
4133                }
4134                else
4135                {
4136                    CLEANUPonERR(
4137                        M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
4138                        mMp4FileDataPtr->videoTrackPtr->dsiSize,
4139                        mMp4FileDataPtr->fileWriterFunctions,
4140                        fileWriterContext));
4141                }
4142
4143                CLEANUPonERR(M4MP4W_putBlock(H263Block4, sizeof(H263Block4),
4144                    mMp4FileDataPtr->fileWriterFunctions,
4145                    fileWriterContext)); /*h263*/
4146                /* Pierre Lebeaupin 2008/04/29: the two following lines used to be swapped;
4147                I changed to this order in order to conform to 3GPP. */
4148                CLEANUPonERR(
4149                    M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->avgBitrate,
4150                    mMp4FileDataPtr->fileWriterFunctions,
4151                    fileWriterContext)); /*h263*/
4152                CLEANUPonERR(
4153                    M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->maxBitrate,
4154                    mMp4FileDataPtr->fileWriterFunctions,
4155                    fileWriterContext)); /*h263*/
4156            }
4157            else
4158            {
4159                CLEANUPonERR(M4MP4W_putBlock(H263Block2, sizeof(H263Block2),
4160                    mMp4FileDataPtr->fileWriterFunctions,
4161                    fileWriterContext)); /* d263 box */
4162
4163                if (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
4164                {
4165                    CLEANUPonERR(M4MP4W_putBlock(H263Block3, sizeof(H263Block3),
4166                        mMp4FileDataPtr->fileWriterFunctions,
4167                        fileWriterContext)); /*h263*/
4168                }
4169                else
4170                {
4171                    CLEANUPonERR(
4172                        M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
4173                        mMp4FileDataPtr->videoTrackPtr->dsiSize,
4174                        mMp4FileDataPtr->fileWriterFunctions,
4175                        fileWriterContext));
4176                }
4177            }
4178        }
4179
4180        if (bMP4V)
4181        {
4182            M4OSA_UInt32 bufferSizeDB = 5 * mMp4FileDataPtr->videoTrackPtr->
4183                avgBitrate; /*bufferSizeDB set to 5 times the bitrate*/
4184
4185            CLEANUPonERR(M4MP4W_putBE32(v_esdsSize,
4186                mMp4FileDataPtr->fileWriterFunctions,
4187                fileWriterContext)); /*mp4v*/
4188            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock0,
4189                sizeof(MPEGConfigBlock0), mMp4FileDataPtr->fileWriterFunctions,
4190                fileWriterContext)); /*mp4v*/
4191            CLEANUPonERR(M4MP4W_putByte(v_ESDescriptorSize,
4192                mMp4FileDataPtr->fileWriterFunctions,
4193                fileWriterContext)); /*mp4v*/
4194            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock1,
4195                sizeof(MPEGConfigBlock1), mMp4FileDataPtr->fileWriterFunctions,
4196                fileWriterContext)); /*mp4v*/
4197            CLEANUPonERR(M4MP4W_putByte(v_DCDescriptorSize,
4198                mMp4FileDataPtr->fileWriterFunctions,
4199                fileWriterContext)); /*mp4v*/
4200            CLEANUPonERR(M4MP4W_putBlock(Mp4vBlock3, sizeof(Mp4vBlock3),
4201                mMp4FileDataPtr->fileWriterFunctions,
4202                fileWriterContext)); /*mp4v*/
4203            CLEANUPonERR(M4MP4W_putBE24(bufferSizeDB,
4204                mMp4FileDataPtr->fileWriterFunctions,
4205                fileWriterContext)); /*mp4v*/
4206            CLEANUPonERR(
4207                M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->maxBitrate,
4208                mMp4FileDataPtr->fileWriterFunctions,
4209                fileWriterContext)); /*mp4v*/
4210            CLEANUPonERR(
4211                M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->avgBitrate,
4212                mMp4FileDataPtr->fileWriterFunctions,
4213                fileWriterContext)); /*mp4v*/
4214            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock2,
4215                sizeof(MPEGConfigBlock2), mMp4FileDataPtr->fileWriterFunctions,
4216                fileWriterContext)); /*mp4v*/
4217            CLEANUPonERR(M4MP4W_putByte(mMp4FileDataPtr->videoTrackPtr->dsiSize,
4218                mMp4FileDataPtr->fileWriterFunctions,
4219                fileWriterContext)); /*mp4v*/
4220            CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
4221                mMp4FileDataPtr->videoTrackPtr->dsiSize,
4222                mMp4FileDataPtr->fileWriterFunctions,
4223                fileWriterContext)); /*mp4v*/
4224            CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock3,
4225                sizeof(MPEGConfigBlock3), mMp4FileDataPtr->fileWriterFunctions,
4226                fileWriterContext)); /*mp4v*/
4227        }
4228
4229        if (bH264)
4230        {
4231            M4OSA_UInt16 ppsLentgh = 0; /* PPS length */
4232            M4OSA_UInt16 spsLentgh = 0; /* SPS length */
4233            M4OSA_UChar *tmpDSI = mMp4FileDataPtr->videoTrackPtr->DSI; /* DSI */
4234            M4OSA_UInt16 NumberOfPPS;
4235            M4OSA_UInt16 lCntPPS;
4236
4237            /* Put the avcC (header + DSI) size */
4238            CLEANUPonERR(M4MP4W_putBE32(v_avcCSize,
4239                mMp4FileDataPtr->fileWriterFunctions,
4240                fileWriterContext)); /*h264*/
4241            /* Put the avcC header */
4242            CLEANUPonERR(M4MP4W_putBlock(H264Block2, sizeof(H264Block2),
4243                mMp4FileDataPtr->fileWriterFunctions,
4244                fileWriterContext)); /*h264*/
4245            /* Put the DSI (SPS + PPS) int the 3gp format*/
4246            /* SPS length in BE */
4247
4248            if ((0x01 != mMp4FileDataPtr->videoTrackPtr->DSI[0]) ||
4249                 (0x42 != mMp4FileDataPtr->videoTrackPtr->DSI[1]))
4250            {
4251                M4OSA_TRACE1_2("!!! M4MP4W_closeWrite ERROR : invalid AVCC 0x%X 0x%X",
4252                    mMp4FileDataPtr->videoTrackPtr->DSI[0],
4253                    mMp4FileDataPtr->videoTrackPtr->DSI[1]);
4254                return M4ERR_PARAMETER;
4255            }
4256            // Do not strip the DSI
4257            CLEANUPonERR( M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
4258                mMp4FileDataPtr->videoTrackPtr->dsiSize,
4259                mMp4FileDataPtr->fileWriterFunctions,
4260                fileWriterContext) );/*h264*/
4261
4262        }
4263
4264        /*end trak*/
4265        CLEANUPonERR(M4MP4W_putBE32(v_stszSize,
4266            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4267        CLEANUPonERR(M4MP4W_putBlock(CommonBlock15, sizeof(CommonBlock15),
4268            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4269        CLEANUPonERR(M4MP4W_putBE32(
4270            mMp4FileDataPtr->videoTrackPtr->CommonData.sampleSize,
4271            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4272        CLEANUPonERR(
4273            M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb,
4274            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4275#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
4276
4277        for ( i = 0; i < mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb;
4278            i++ )
4279        {
4280            CLEANUPonERR(
4281                M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ[i],
4282                mMp4FileDataPtr->fileWriterFunctions,
4283                fileWriterContext)); /*video*/
4284        }
4285
4286#else
4287
4288        CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
4289            *)mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ,
4290            mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb * 4,
4291            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4292
4293#endif
4294
4295        CLEANUPonERR(M4MP4W_putBE32(v_stscSize,
4296            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4297        CLEANUPonERR(M4MP4W_putBlock(CommonBlock16, sizeof(CommonBlock16),
4298            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4299
4300#ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
4301
4302        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->currentStsc
4303            + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4304
4305        for ( i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentStsc; i++ )
4306        {
4307            CLEANUPonERR(M4MP4W_putBE32(
4308                ( mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable[i]
4309            >> 12) + 1, mMp4FileDataPtr->fileWriterFunctions,
4310                fileWriterContext));
4311            CLEANUPonERR(M4MP4W_putBE32((mMp4FileDataPtr->videoTrackPtr->
4312                chunkSampleNbTable[i] & 0xFFF),
4313                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4314            CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
4315                fileWriterContext));
4316        }
4317
4318#else
4319
4320        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->currentChunk
4321            + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4322
4323        for (i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk; i++)
4324        {
4325            CLEANUPonERR(M4MP4W_putBE32(i + 1,
4326                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4327            CLEANUPonERR(M4MP4W_putBE32(
4328                mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable[i],
4329                mMp4FileDataPtr->fileWriterFunctions,
4330                fileWriterContext));
4331            CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
4332                fileWriterContext));
4333        }
4334
4335#endif
4336
4337        CLEANUPonERR(M4MP4W_putBE32(v_stcoSize,
4338            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4339        CLEANUPonERR(M4MP4W_putBlock(CommonBlock17, sizeof(CommonBlock17),
4340            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4341        CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->currentChunk
4342            + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4343
4344#ifdef _M4MP4W_MOOV_FIRST
4345
4346        for (i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk; i++)
4347        {
4348            if (( bInterleaveAV == M4OSA_TRUE)
4349                && (mMp4FileDataPtr->audioTrackPtr->currentChunk >= i))
4350            {
4351                v_trakOffset +=
4352                    mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i];
4353            }
4354            CLEANUPonERR(M4MP4W_putBE32(v_trakOffset,
4355                mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4356            v_trakOffset += mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i];
4357        }
4358
4359#else
4360
4361        for ( i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk; i++ )
4362        {
4363            CLEANUPonERR(M4MP4W_putBE32(
4364                mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable[i],
4365                mMp4FileDataPtr->fileWriterFunctions,
4366                fileWriterContext));
4367        }
4368
4369#endif                                                                 /*_M4MP4W_MOOV_FIRST*/
4370
4371        CLEANUPonERR(M4MP4W_putBE32(v_stssSize,
4372            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4373        CLEANUPonERR(M4MP4W_putBlock(VideoBlock4, sizeof(VideoBlock4),
4374            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4375        CLEANUPonERR(
4376            M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb,
4377            mMp4FileDataPtr->fileWriterFunctions,
4378            fileWriterContext)); /*video*/
4379        CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
4380            *)mMp4FileDataPtr->videoTrackPtr->TABLE_STSS,
4381            mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb * 4,
4382            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4383        CLEANUPonERR(M4MP4W_putBlock(VideoBlock5, sizeof(VideoBlock5),
4384            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4385    }
4386#ifdef _M4MP4W_MOOV_FIRST
4387    /*mdat*/
4388
4389    CLEANUPonERR(M4MP4W_putBE32(mdatSize, mMp4FileDataPtr->fileWriterFunctions,
4390        fileWriterContext));
4391    CLEANUPonERR(M4MP4W_putBlock(CommonBlock2, sizeof(CommonBlock2),
4392        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4393
4394    /*write data, according to the interleave mode (default is not interleaved)*/
4395    if (bInterleaveAV == M4OSA_FALSE)
4396    {
4397        if (bAudio)
4398        {
4399            for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk;
4400                i++ )
4401            {
4402                CLEANUPonERR(
4403                    M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[i],
4404                    mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i],
4405                    mMp4FileDataPtr->fileWriterFunctions,
4406                    fileWriterContext)); /*audio (previously a_dataSize)*/
4407            }
4408        }
4409
4410        if (bVideo)
4411        {
4412            for ( i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk;
4413                i++ )
4414            {
4415                CLEANUPonERR(
4416                    M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[i],
4417                    mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i],
4418                    mMp4FileDataPtr->fileWriterFunctions,
4419                    fileWriterContext)); /*video (previously a_dataSize)*/
4420            }
4421        }
4422    }
4423    else /*in this mode, we have audio and video to interleave*/
4424    {
4425        for ( i = 0; i <= max(mMp4FileDataPtr->audioTrackPtr->currentChunk,
4426            mMp4FileDataPtr->videoTrackPtr->currentChunk); i++ )
4427        {
4428            if (i <= mMp4FileDataPtr->audioTrackPtr->currentChunk)
4429            {
4430                CLEANUPonERR(
4431                    M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[i],
4432                    mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i],
4433                    mMp4FileDataPtr->fileWriterFunctions,
4434                    fileWriterContext)); /*audio (previously a_dataSize)*/
4435            }
4436
4437            if (i <= mMp4FileDataPtr->videoTrackPtr->currentChunk)
4438            {
4439                CLEANUPonERR(
4440                    M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[i],
4441                    mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i],
4442                    mMp4FileDataPtr->fileWriterFunctions,
4443                    fileWriterContext)); /*video (previously a_dataSize)*/
4444            }
4445        }
4446    }
4447
4448#endif /*_M4MP4W_MOOV_FIRST*/
4449
4450    /*skip*/
4451
4452    CLEANUPonERR(M4MP4W_putBlock(BlockSignatureSkipHeader,
4453        sizeof(BlockSignatureSkipHeader), mMp4FileDataPtr->fileWriterFunctions,
4454        fileWriterContext));
4455
4456    /* Write embedded string */
4457    if (mMp4FileDataPtr->embeddedString == M4OSA_NULL)
4458    {
4459        CLEANUPonERR(M4MP4W_putBlock(BlockSignatureSkipDefaultEmbeddedString,
4460            sizeof(BlockSignatureSkipDefaultEmbeddedString),
4461            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4462    }
4463    else
4464    {
4465        CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->embeddedString, 16,
4466            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4467    }
4468
4469    /* Write ves core version */
4470    camcoder_maj = (M4OSA_UChar)(mMp4FileDataPtr->camcoderVersion / 100);
4471    camcoder_min =
4472        (M4OSA_UChar)(( mMp4FileDataPtr->camcoderVersion - 100 * camcoder_maj)
4473        / 10);
4474    camcoder_rev =
4475        (M4OSA_UChar)(mMp4FileDataPtr->camcoderVersion - 100 * camcoder_maj - 10
4476        * camcoder_min);
4477
4478    CLEANUPonERR(M4MP4W_putByte(' ', mMp4FileDataPtr->fileWriterFunctions,
4479        fileWriterContext));
4480    CLEANUPonERR(M4MP4W_putByte((M4OSA_UChar)(camcoder_maj + '0'),
4481        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4482    CLEANUPonERR(M4MP4W_putByte('.', mMp4FileDataPtr->fileWriterFunctions,
4483        fileWriterContext));
4484    CLEANUPonERR(M4MP4W_putByte((M4OSA_UChar)(camcoder_min + '0'),
4485        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4486    CLEANUPonERR(M4MP4W_putByte('.', mMp4FileDataPtr->fileWriterFunctions,
4487        fileWriterContext));
4488    CLEANUPonERR(M4MP4W_putByte((M4OSA_UChar)(camcoder_rev + '0'),
4489        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4490
4491    /* Write integration tag */
4492    CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar *)" -- ", 4,
4493        mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4494
4495    if (mMp4FileDataPtr->integrationTag == M4OSA_NULL)
4496    {
4497        CLEANUPonERR(M4MP4W_putBlock(BlockSignatureSkipDefaultIntegrationTag,
4498            sizeof(BlockSignatureSkipDefaultIntegrationTag),
4499            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4500    }
4501    else
4502    {
4503        CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->integrationTag, 60,
4504            mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4505    }
4506
4507#ifndef _M4MP4W_MOOV_FIRST
4508    /*overwrite mdat size*/
4509
4510    if (mMp4FileDataPtr->ftyp.major_brand != 0)
4511        mdatPos= 16 + mMp4FileDataPtr->ftyp.nbCompatibleBrands * 4;
4512    else
4513        mdatPos = 24;
4514
4515    moovPos = moovPos - mdatPos;
4516    mdatSize = moovPos;
4517
4518    CLEANUPonERR(mMp4FileDataPtr->fileWriterFunctions->seek(fileWriterContext,
4519        M4OSA_kFileSeekBeginning, &mdatPos)); /*seek after ftyp...*/
4520    CLEANUPonERR(M4MP4W_putBE32(mdatSize, mMp4FileDataPtr->fileWriterFunctions,
4521        fileWriterContext));
4522
4523#endif                                        /*_M4MP4W_MOOV_FIRST*/
4524
4525cleanup:
4526
4527    /**
4528    * Close the file even if an error occured */
4529    if (M4OSA_NULL != mMp4FileDataPtr->fileWriterContext)
4530    {
4531        err2 =
4532            mMp4FileDataPtr->fileWriterFunctions->closeWrite(mMp4FileDataPtr->
4533            fileWriterContext); /**< close the stream anyway */
4534
4535        if (M4NO_ERROR != err2)
4536        {
4537            M4OSA_TRACE1_1(
4538                "M4MP4W_closeWrite: fileWriterFunctions->closeWrite returns 0x%x",
4539                err2);
4540        }
4541        mMp4FileDataPtr->fileWriterContext = M4OSA_NULL;
4542    }
4543
4544#ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
4545    /* Remove safety file if still present (here it is cleanup in case of error and NOT the normal
4546    removal of the safety file to free emergency space for the moov). */
4547
4548    if (M4OSA_TRUE == mMp4FileDataPtr->cleanSafetyFile)
4549    {
4550        M4OSA_Context tempContext;
4551        err3 = mMp4FileDataPtr->fileWriterFunctions->openWrite(&tempContext,
4552            mMp4FileDataPtr->safetyFileUrl,
4553            M4OSA_kFileWrite | M4OSA_kFileCreate);
4554
4555        if (M4NO_ERROR != err2)
4556            err2 = err3;
4557
4558        if (M4NO_ERROR
4559            != err3) /* No sense closing if we couldn't open in the first place. */
4560        {
4561            err3 =
4562                mMp4FileDataPtr->fileWriterFunctions->closeWrite(tempContext);
4563
4564            if (M4NO_ERROR != err2)
4565                err2 = err3;
4566        }
4567        mMp4FileDataPtr->safetyFileUrl = M4OSA_NULL;
4568        mMp4FileDataPtr->cleanSafetyFile = M4OSA_FALSE;
4569    }
4570
4571#endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
4572
4573    /* Delete embedded string */
4574
4575    if (M4OSA_NULL != mMp4FileDataPtr->embeddedString)
4576    {
4577        free(mMp4FileDataPtr->embeddedString);
4578        mMp4FileDataPtr->embeddedString = M4OSA_NULL;
4579    }
4580
4581    /* Delete integration tag */
4582    if (M4OSA_NULL != mMp4FileDataPtr->integrationTag)
4583    {
4584        free(mMp4FileDataPtr->integrationTag);
4585        mMp4FileDataPtr->integrationTag = M4OSA_NULL;
4586    }
4587
4588    /**
4589    * M4MP4W_freeContext() is now a private method, called only from here*/
4590    err3 = M4MP4W_freeContext(context);
4591
4592    if (M4NO_ERROR != err3)
4593    {
4594        M4OSA_TRACE1_1("M4MP4W_closeWrite: M4MP4W_freeContext returns 0x%x",
4595            err3);
4596    }
4597
4598    /**
4599    * Choose which error code to return */
4600    if (M4NO_ERROR != err)
4601    {
4602        /**
4603        * We give priority to main error */
4604        M4OSA_TRACE1_1("M4MP4W_closeWrite: returning err=0x%x", err);
4605        return err;
4606    }
4607    else if (M4NO_ERROR != err2)
4608    {
4609        /**
4610        * Error from closeWrite is returned if there is no main error */
4611        M4OSA_TRACE1_1("M4MP4W_closeWrite: returning err2=0x%x", err2);
4612        return err2;
4613    }
4614    else
4615    {
4616        /**
4617        * Error from M4MP4W_freeContext is returned only if there is no main error and
4618          no close error */
4619        M4OSA_TRACE1_1("M4MP4W_closeWrite: returning err3=0x%x", err3);
4620        return err3;
4621    }
4622}
4623
4624/*******************************************************************************/
4625M4OSA_ERR M4MP4W_getOption( M4OSA_Context context, M4OSA_OptionID option,
4626                           M4OSA_DataOption *valuePtr )
4627/*******************************************************************************/
4628{
4629    M4OSA_ERR err = M4NO_ERROR;
4630
4631    M4SYS_StreamIDValue *streamIDvaluePtr = M4OSA_NULL;
4632    M4MP4W_StreamIDsize *streamIDsizePtr = M4OSA_NULL;
4633    M4MP4W_memAddr *memAddrPtr = M4OSA_NULL;
4634    /*    M4MP4W_WriteCallBack*    callBackPtr = M4OSA_NULL;*/
4635
4636    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
4637    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
4638
4639    ERR_CHECK(( mMp4FileDataPtr->state == M4MP4W_opened)
4640        || (mMp4FileDataPtr->state == M4MP4W_ready), M4ERR_STATE);
4641
4642    switch( option )
4643    {
4644        case (M4MP4W_maxAUperChunk):
4645            return M4ERR_NOT_IMPLEMENTED;
4646
4647        case (M4MP4W_maxChunkSize):
4648
4649            streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4650
4651            switch( streamIDvaluePtr->streamID )
4652            {
4653                case (AudioStreamID):
4654                    if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
4655                        return M4ERR_BAD_STREAM_ID;
4656                    else
4657                        streamIDvaluePtr->value =
4658                        mMp4FileDataPtr->audioTrackPtr->MaxChunkSize;
4659                    break;
4660
4661                case (VideoStreamID):
4662                    if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
4663                        return M4ERR_BAD_STREAM_ID;
4664                    else
4665                        streamIDvaluePtr->value =
4666                        mMp4FileDataPtr->videoTrackPtr->MaxChunkSize;
4667                    break;
4668
4669                case (0): /*all streams*/
4670                    streamIDvaluePtr->value = mMp4FileDataPtr->MaxChunkSize;
4671                    break;
4672
4673                default:
4674                    return M4ERR_BAD_STREAM_ID;
4675        }
4676
4677        break;
4678
4679    case (M4MP4W_maxChunkInter):
4680
4681        streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4682
4683        switch( streamIDvaluePtr->streamID )
4684        {
4685            case (0): /*all streams*/
4686                streamIDvaluePtr->value = (M4OSA_UInt32)mMp4FileDataPtr->
4687                    InterleaveDur; /*time conversion !*/
4688                break;
4689
4690            default:
4691                return M4ERR_BAD_STREAM_ID;
4692        }
4693        break;
4694
4695    case (M4MP4W_embeddedString):
4696        memAddrPtr = (M4MP4W_memAddr *)(*valuePtr);
4697        /*memAddrPtr must have been already allocated by the caller
4698        and memAddrPtr->size initialized with the max possible length in bytes*/
4699        ERR_CHECK(memAddrPtr->size >= 16, M4ERR_PARAMETER);
4700        ERR_CHECK(memAddrPtr->addr != M4OSA_NULL, M4ERR_PARAMETER);
4701        /*memAddrPtr->size is updated with the actual size of the string*/
4702        memAddrPtr->size = 16;
4703        /*if no value was set, return the default string */
4704        if (mMp4FileDataPtr->embeddedString != M4OSA_NULL)
4705            memcpy((void *)memAddrPtr->addr,
4706            (void *)mMp4FileDataPtr->embeddedString, 16);
4707        else
4708            memcpy((void *)memAddrPtr->addr,
4709            (void *)BlockSignatureSkipDefaultEmbeddedString,
4710            16);
4711        break;
4712
4713    case (M4MP4W_integrationTag):
4714        memAddrPtr = (M4MP4W_memAddr *)(*valuePtr);
4715        /*memAddrPtr must have been already allocated by the caller
4716        and memAddrPtr->size initialized with the max possible length in bytes*/
4717        ERR_CHECK(memAddrPtr->size >= 60, M4ERR_PARAMETER);
4718        ERR_CHECK(memAddrPtr->addr != M4OSA_NULL, M4ERR_PARAMETER);
4719        /*memAddrPtr->size is updated with the actual size of the string*/
4720        memAddrPtr->size = 60;
4721        /*if no value was set, return the default string 0 */
4722        if (mMp4FileDataPtr->integrationTag != M4OSA_NULL)
4723            memcpy((void *)memAddrPtr->addr,
4724            (void *)mMp4FileDataPtr->integrationTag, 60);
4725        else
4726            memcpy((void *)memAddrPtr->addr,
4727            (void *)BlockSignatureSkipDefaultIntegrationTag,
4728            60);
4729        break;
4730
4731    case (M4MP4W_CamcoderVersion):
4732
4733        streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4734
4735        switch( streamIDvaluePtr->streamID )
4736        {
4737            case (0): /*all streams*/
4738                streamIDvaluePtr->value = mMp4FileDataPtr->camcoderVersion;
4739                break;
4740
4741            default:
4742                return M4ERR_BAD_STREAM_ID;
4743        }
4744        break;
4745
4746    case (M4MP4W_preWriteCallBack):
4747        return M4ERR_NOT_IMPLEMENTED;
4748        /*callBackPtr = (M4MP4W_WriteCallBack*)(*valuePtr);
4749        *callBackPtr = mMp4FileDataPtr->PreWriteCallBack;
4750        break;*/
4751
4752    case (M4MP4W_postWriteCallBack):
4753        return M4ERR_NOT_IMPLEMENTED;
4754        /*callBackPtr = (M4MP4W_WriteCallBack*)(*valuePtr);
4755        *callBackPtr = mMp4FileDataPtr->PostWriteCallBack;
4756        break;*/
4757
4758    case (M4MP4W_maxAUsize):
4759
4760        streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4761
4762        switch( streamIDvaluePtr->streamID )
4763        {
4764            case (AudioStreamID):
4765                if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
4766                    return M4ERR_BAD_STREAM_ID;
4767                else
4768                    streamIDvaluePtr->value =
4769                    mMp4FileDataPtr->audioTrackPtr->MaxAUSize;
4770                break;
4771
4772            case (VideoStreamID):
4773                if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
4774                    return M4ERR_BAD_STREAM_ID;
4775                else
4776                    streamIDvaluePtr->value =
4777                    mMp4FileDataPtr->videoTrackPtr->MaxAUSize;
4778                break;
4779
4780            case (0): /*all streams*/
4781                streamIDvaluePtr->value = mMp4FileDataPtr->MaxAUSize;
4782                break;
4783
4784            default:
4785                return M4ERR_BAD_STREAM_ID;
4786        }
4787
4788        break;
4789
4790    case (M4MP4W_IOD):
4791        return M4ERR_NOT_IMPLEMENTED;
4792
4793    case (M4MP4W_ESD):
4794        return M4ERR_NOT_IMPLEMENTED;
4795
4796    case (M4MP4W_SDP):
4797        return M4ERR_NOT_IMPLEMENTED;
4798
4799    case (M4MP4W_trackSize):
4800        streamIDsizePtr = (M4MP4W_StreamIDsize *)(*valuePtr);
4801        streamIDsizePtr->width = mMp4FileDataPtr->videoTrackPtr->width;
4802        streamIDsizePtr->height = mMp4FileDataPtr->videoTrackPtr->height;
4803        break;
4804
4805    case (M4MP4W_estimateAudioSize):
4806        streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4807        streamIDvaluePtr->value =
4808            (M4OSA_UInt32)mMp4FileDataPtr->estimateAudioSize;
4809        break;
4810
4811    case (M4MP4W_MOOVfirst):
4812        return M4ERR_NOT_IMPLEMENTED;
4813
4814    case (M4MP4W_V2_MOOF):
4815        return M4ERR_NOT_IMPLEMENTED;
4816
4817    case (M4MP4W_V2_tblCompres):
4818        return M4ERR_NOT_IMPLEMENTED;
4819
4820    default:
4821        return M4ERR_BAD_OPTION_ID;
4822    }
4823
4824    return err;
4825}
4826
4827/*******************************************************************************/
4828M4OSA_ERR M4MP4W_setOption( M4OSA_Context context, M4OSA_OptionID option,
4829                           M4OSA_DataOption value )
4830/*******************************************************************************/
4831{
4832    M4OSA_ERR err = M4NO_ERROR;
4833
4834    M4SYS_StreamIDValue *streamIDvaluePtr = M4OSA_NULL;
4835    M4MP4W_StreamIDsize *streamIDsizePtr = M4OSA_NULL;
4836    M4MP4W_memAddr *memAddrPtr = M4OSA_NULL;
4837    M4SYS_StreamIDmemAddr *streamIDmemAddrPtr;
4838
4839    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
4840    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
4841
4842    /* Verify state */
4843    switch( option )
4844    {
4845        case M4MP4W_maxFileDuration:
4846        case M4MP4W_DSI:
4847            /* this param can be set at the end of a recording */
4848            ERR_CHECK((mMp4FileDataPtr->state != M4MP4W_closed), M4ERR_STATE);
4849            break;
4850
4851        case M4MP4W_setFtypBox:
4852            /* this param can only be set before starting any write */
4853            ERR_CHECK(mMp4FileDataPtr->state == M4MP4W_opened, M4ERR_STATE);
4854            break;
4855
4856        default:
4857            /* in general params can be set at open or ready stage */
4858            ERR_CHECK(( mMp4FileDataPtr->state == M4MP4W_opened)
4859                || (mMp4FileDataPtr->state == M4MP4W_ready), M4ERR_STATE);
4860    }
4861
4862    /* Set option */
4863    switch( option )
4864    {
4865        case (M4MP4W_maxAUperChunk):
4866            return M4ERR_NOT_IMPLEMENTED;
4867
4868        case (M4MP4W_maxChunkSize):
4869
4870            streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
4871
4872            switch( streamIDvaluePtr->streamID )
4873            {
4874                case (AudioStreamID):
4875                    if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
4876                        return
4877                        M4ERR_BAD_STREAM_ID; /*maybe the stream has not been added yet*/
4878                    else
4879                    {
4880                        mMp4FileDataPtr->audioTrackPtr->MaxChunkSize =
4881                            streamIDvaluePtr->value;
4882                    }
4883
4884                    break;
4885
4886                case (VideoStreamID):
4887                    if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
4888                        return
4889                        M4ERR_BAD_STREAM_ID; /*maybe the stream has not been added yet*/
4890                    else
4891                    {
4892                        mMp4FileDataPtr->videoTrackPtr->MaxChunkSize =
4893                            streamIDvaluePtr->value;
4894                    }
4895                    break;
4896
4897                case (0): /*all streams*/
4898
4899                    /*In M4MP4W_opened state, no stream is present yet, so only global value
4900                    needs to be updated.*/
4901                    mMp4FileDataPtr->MaxChunkSize = streamIDvaluePtr->value;
4902
4903                    if (mMp4FileDataPtr->hasAudio == M4OSA_TRUE)
4904                    {
4905                        mMp4FileDataPtr->audioTrackPtr->MaxChunkSize =
4906                            streamIDvaluePtr->value;
4907                    }
4908
4909                    if (mMp4FileDataPtr->hasVideo == M4OSA_TRUE)
4910                    {
4911                        mMp4FileDataPtr->videoTrackPtr->MaxChunkSize =
4912                            streamIDvaluePtr->value;
4913                    }
4914                    break;
4915
4916                default:
4917                    return M4ERR_BAD_STREAM_ID;
4918            }
4919            break;
4920
4921        case (M4MP4W_maxChunkInter):
4922
4923            streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
4924
4925            switch( streamIDvaluePtr->streamID )
4926            {
4927                case (0):                                       /*all streams*/
4928                    mMp4FileDataPtr->InterleaveDur =
4929                        (M4MP4W_Time32)streamIDvaluePtr->
4930                        value; /*time conversion!*/
4931                    break;
4932
4933                default:
4934                    return M4ERR_BAD_STREAM_ID;
4935                    /*not meaningfull to set this parameter on a streamID basis*/
4936            }
4937            break;
4938
4939        case (M4MP4W_maxFileSize):
4940            mMp4FileDataPtr->MaxFileSize = *(M4OSA_UInt32 *)value;
4941            break;
4942
4943        case (M4MP4W_embeddedString):
4944            memAddrPtr = (M4MP4W_memAddr *)value;
4945            /*
4946            * If memAddrPtr->size > 16 bytes, then the string will be truncated.
4947            * If memAddrPtr->size < 16 bytes, then return M4ERR_PARAMETER
4948            */
4949            ERR_CHECK(memAddrPtr->size >= 16, M4ERR_PARAMETER);
4950
4951            if (mMp4FileDataPtr->embeddedString == M4OSA_NULL)
4952            {
4953                mMp4FileDataPtr->embeddedString =
4954                    (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(16, M4MP4_WRITER,
4955                    (M4OSA_Char *)"embeddedString");
4956                ERR_CHECK(mMp4FileDataPtr->embeddedString != M4OSA_NULL,
4957                    M4ERR_ALLOC);
4958            }
4959            /*else, just overwrite the previously set string*/
4960            memcpy((void *)mMp4FileDataPtr->embeddedString,
4961                (void *)memAddrPtr->addr, 16);
4962            break;
4963
4964        case (M4MP4W_integrationTag):
4965            memAddrPtr = (M4MP4W_memAddr *)value;
4966            /*
4967            * If memAddrPtr->size > 60 bytes, then the string will be truncated.
4968            * If memAddrPtr->size < 60 bytes, then pad with 0
4969            */
4970            if (mMp4FileDataPtr->integrationTag == M4OSA_NULL)
4971            {
4972                mMp4FileDataPtr->integrationTag =
4973                    (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(60, M4MP4_WRITER,
4974                    (M4OSA_Char *)"integrationTag");
4975                ERR_CHECK(mMp4FileDataPtr->integrationTag != M4OSA_NULL,
4976                    M4ERR_ALLOC);
4977            }
4978            /*else, just overwrite the previously set string*/
4979            if (memAddrPtr->size < 60)
4980            {
4981                memcpy((void *)mMp4FileDataPtr->integrationTag,
4982                    (void *)BlockSignatureSkipDefaultIntegrationTag,
4983                    60);
4984                memcpy((void *)mMp4FileDataPtr->integrationTag,
4985                    (void *)memAddrPtr->addr, memAddrPtr->size);
4986            }
4987            else
4988            {
4989                memcpy((void *)mMp4FileDataPtr->integrationTag,
4990                    (void *)memAddrPtr->addr, 60);
4991            }
4992            break;
4993
4994        case (M4MP4W_CamcoderVersion):
4995
4996            streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
4997
4998            switch( streamIDvaluePtr->streamID )
4999            {
5000                case (0): /*all streams*/
5001                    mMp4FileDataPtr->camcoderVersion = streamIDvaluePtr->value;
5002                    break;
5003
5004                default:
5005                    return M4ERR_BAD_STREAM_ID;
5006                    /*not meaningfull to set this parameter on a streamID basis*/
5007            }
5008            break;
5009
5010        case (M4MP4W_preWriteCallBack):
5011            return M4ERR_NOT_IMPLEMENTED;
5012            /*mMp4FileDataPtr->PreWriteCallBack = *(M4MP4W_WriteCallBack*)value;
5013            break;*/
5014
5015        case (M4MP4W_postWriteCallBack):
5016            return M4ERR_NOT_IMPLEMENTED;
5017            /*mMp4FileDataPtr->PostWriteCallBack = *(M4MP4W_WriteCallBack*)value;
5018            break;*/
5019
5020        case (M4MP4W_maxAUsize):
5021
5022            streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
5023
5024            switch( streamIDvaluePtr->streamID )
5025            {
5026                case (AudioStreamID):
5027
5028                    /*if (mMp4FileDataPtr->audioTrackPtr == M4OSA_NULL)*/
5029                    if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
5030                        return M4ERR_BAD_STREAM_ID;
5031                    else
5032                        mMp4FileDataPtr->audioTrackPtr->MaxAUSize =
5033                        streamIDvaluePtr->value;
5034                    break;
5035
5036                case (VideoStreamID):
5037
5038                    /*if (mMp4FileDataPtr->videoTrackPtr == M4OSA_NULL)*/
5039                    if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
5040                        return M4ERR_BAD_STREAM_ID;
5041                    else
5042                        mMp4FileDataPtr->videoTrackPtr->MaxAUSize =
5043                        streamIDvaluePtr->value;
5044                    break;
5045
5046                case (0): /*all streams*/
5047
5048                    mMp4FileDataPtr->MaxAUSize = streamIDvaluePtr->value;
5049
5050                    if (mMp4FileDataPtr->hasAudio == M4OSA_TRUE)
5051                        mMp4FileDataPtr->audioTrackPtr->MaxAUSize =
5052                        streamIDvaluePtr->value;
5053
5054                    if (mMp4FileDataPtr->hasVideo == M4OSA_TRUE)
5055                        mMp4FileDataPtr->videoTrackPtr->MaxAUSize =
5056                        streamIDvaluePtr->value;
5057
5058                    break;
5059
5060                default:
5061                    return M4ERR_BAD_STREAM_ID;
5062            }
5063            break;
5064
5065        case (M4MP4W_IOD):
5066            return M4ERR_NOT_IMPLEMENTED;
5067
5068        case (M4MP4W_ESD):
5069            return M4ERR_NOT_IMPLEMENTED;
5070
5071        case (M4MP4W_SDP):
5072            return M4ERR_NOT_IMPLEMENTED;
5073
5074        case (M4MP4W_trackSize):
5075
5076            streamIDsizePtr = (M4MP4W_StreamIDsize *)value;
5077
5078            if ((streamIDsizePtr->streamID != VideoStreamID)
5079                || (mMp4FileDataPtr->hasVideo == M4OSA_FALSE))
5080                return M4ERR_BAD_STREAM_ID;
5081            else
5082            {
5083                mMp4FileDataPtr->videoTrackPtr->width = streamIDsizePtr->width;
5084                mMp4FileDataPtr->videoTrackPtr->height =
5085                    streamIDsizePtr->height;
5086            }
5087            break;
5088
5089        case (M4MP4W_estimateAudioSize):
5090
5091            streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
5092
5093            /*shall not set this option before audio and video streams were added*/
5094            /*nonsense to set this option if not in case audio+video*/
5095            if ((mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
5096                || (mMp4FileDataPtr->hasVideo == M4OSA_FALSE))
5097                return M4ERR_STATE;
5098
5099            mMp4FileDataPtr->estimateAudioSize =
5100                (M4OSA_Bool)streamIDvaluePtr->value;
5101            break;
5102
5103        case (M4MP4W_MOOVfirst):
5104            return M4ERR_NOT_IMPLEMENTED;
5105
5106        case (M4MP4W_V2_MOOF):
5107            return M4ERR_NOT_IMPLEMENTED;
5108
5109        case (M4MP4W_V2_tblCompres):
5110            return M4ERR_NOT_IMPLEMENTED;
5111
5112        case (M4MP4W_maxFileDuration):
5113            mMp4FileDataPtr->MaxFileDuration = *(M4OSA_UInt32 *)value;
5114            break;
5115
5116        case (M4MP4W_setFtypBox):
5117            {
5118                M4OSA_UInt32 size;
5119
5120                ERR_CHECK(( (M4MP4C_FtypBox *)value)->major_brand != 0,
5121                    M4ERR_PARAMETER);
5122
5123                /* Copy structure */
5124                mMp4FileDataPtr->ftyp = *(M4MP4C_FtypBox *)value;
5125
5126                /* Update global position variables with the difference between common and
5127                 user block */
5128                size =
5129                    mMp4FileDataPtr->ftyp.nbCompatibleBrands * sizeof(M4OSA_UInt32);
5130
5131                mMp4FileDataPtr->absoluteCurrentPos = 8/*mdat*/ + 16 + size;
5132                mMp4FileDataPtr->filesize = 218/*mdat+moov+skip*/ + 16 + size;
5133            }
5134            break;
5135
5136        case (M4MP4W_DSI):
5137            {
5138                streamIDmemAddrPtr = (M4SYS_StreamIDmemAddr *)value;
5139
5140                /* Nested switch! Whee! */
5141                switch( streamIDmemAddrPtr->streamID )
5142                {
5143                    case (AudioStreamID):
5144                        return M4ERR_NOT_IMPLEMENTED;
5145
5146                    case (VideoStreamID):
5147
5148                        /* Protect DSI setting : only once allowed on a given stream */
5149
5150                        switch( mMp4FileDataPtr->videoTrackPtr->
5151                            CommonData.trackType )
5152                        {
5153                            case M4SYS_kH263:
5154                                if ((0 != mMp4FileDataPtr->videoTrackPtr->dsiSize)
5155                                    || (M4OSA_NULL
5156                                    != mMp4FileDataPtr->videoTrackPtr->DSI))
5157                                {
5158                                    M4OSA_TRACE1_0(
5159                                        "M4MP4W_setOption: dsi already set !");
5160                                    return M4ERR_STATE;
5161                                }
5162
5163                                if ((0 == streamIDmemAddrPtr->size)
5164                                    || (M4OSA_NULL == streamIDmemAddrPtr->addr))
5165                                {
5166                                    M4OSA_TRACE1_0(
5167                                        "M4MP4W_setOption: Bad H263 dsi!");
5168                                    return M4ERR_PARAMETER;
5169                                }
5170
5171                                /*decoder specific info size is supposed to be always 7
5172                                 bytes long */
5173                                ERR_CHECK(streamIDmemAddrPtr->size == 7,
5174                                    M4ERR_PARAMETER);
5175                                mMp4FileDataPtr->videoTrackPtr->dsiSize =
5176                                    (M4OSA_UInt8)streamIDmemAddrPtr->size;
5177                                mMp4FileDataPtr->videoTrackPtr->DSI = (M4OSA_UChar
5178                                    *)M4OSA_32bitAlignedMalloc(streamIDmemAddrPtr->size,
5179                                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
5180                                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
5181                                    != M4OSA_NULL, M4ERR_ALLOC);
5182                                memcpy(
5183                                    (void *)mMp4FileDataPtr->videoTrackPtr->
5184                                    DSI,
5185                                    (void *)streamIDmemAddrPtr->addr,
5186                                    streamIDmemAddrPtr->size);
5187
5188                                break;
5189
5190                            case M4SYS_kMPEG_4:
5191                                if ((0 != mMp4FileDataPtr->videoTrackPtr->dsiSize)
5192                                    || (M4OSA_NULL
5193                                    != mMp4FileDataPtr->videoTrackPtr->DSI))
5194                                {
5195                                    M4OSA_TRACE1_0(
5196                                        "M4MP4W_setOption: dsi already set !");
5197                                    return M4ERR_STATE;
5198                                }
5199
5200                                if ((0 == streamIDmemAddrPtr->size)
5201                                    || (M4OSA_NULL == streamIDmemAddrPtr->addr))
5202                                {
5203                                    M4OSA_TRACE1_0(
5204                                        "M4MP4W_setOption: Bad MPEG4 dsi!");
5205                                    return M4ERR_PARAMETER;
5206                                }
5207
5208                                /*MP4V specific*/
5209                                ERR_CHECK(streamIDmemAddrPtr->size < 105,
5210                                    M4ERR_PARAMETER);
5211                                mMp4FileDataPtr->videoTrackPtr->dsiSize =
5212                                    (M4OSA_UInt8)streamIDmemAddrPtr->size;
5213                                mMp4FileDataPtr->videoTrackPtr->DSI = (M4OSA_UChar
5214                                    *)M4OSA_32bitAlignedMalloc(streamIDmemAddrPtr->size,
5215                                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
5216                                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
5217                                    != M4OSA_NULL, M4ERR_ALLOC);
5218                                memcpy(
5219                                    (void *)mMp4FileDataPtr->videoTrackPtr->
5220                                    DSI,
5221                                    (void *)streamIDmemAddrPtr->addr,
5222                                    streamIDmemAddrPtr->size);
5223                                mMp4FileDataPtr->filesize +=
5224                                    streamIDmemAddrPtr->size;
5225
5226                                break;
5227
5228                            case M4SYS_kH264:
5229                                if ((0 != mMp4FileDataPtr->videoTrackPtr->dsiSize)
5230                                    || (M4OSA_NULL
5231                                    != mMp4FileDataPtr->videoTrackPtr->DSI))
5232                                {
5233                                    /* + H.264 trimming */
5234                                    if (M4OSA_TRUE == mMp4FileDataPtr->bMULPPSSPS)
5235                                    {
5236                                        free(mMp4FileDataPtr->videoTrackPtr->DSI);
5237
5238                                        // Do not strip the DSI
5239                                        /* Store the DSI size */
5240                                        mMp4FileDataPtr->videoTrackPtr->dsiSize =
5241                                            (M4OSA_UInt8)streamIDmemAddrPtr->size;
5242                                             M4OSA_TRACE1_1("M4MP4W_setOption: in set option DSI size =%d"\
5243                                            ,mMp4FileDataPtr->videoTrackPtr->dsiSize);
5244                                        /* Copy the DSI (SPS + PPS) */
5245                                        mMp4FileDataPtr->videoTrackPtr->DSI =
5246                                            (M4OSA_UChar*)M4OSA_32bitAlignedMalloc(
5247                                            streamIDmemAddrPtr->size, M4MP4_WRITER,
5248                                            (M4OSA_Char *)"videoTrackPtr->DSI");
5249                                        ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI !=
5250                                             M4OSA_NULL, M4ERR_ALLOC);
5251                                        memcpy(
5252                                            (void *)mMp4FileDataPtr->videoTrackPtr->DSI,
5253                                            (void *)streamIDmemAddrPtr->addr,
5254                                            streamIDmemAddrPtr->size);
5255
5256                                        break;
5257                                        /* - H.264 trimming */
5258                                    }
5259                                    else
5260                                    {
5261                                        M4OSA_TRACE1_0(
5262                                            "M4MP4W_setOption: dsi already set !");
5263                                        return M4ERR_STATE;
5264                                    }
5265                                }
5266
5267                                if (( 0 == streamIDmemAddrPtr->size)
5268                                    || (M4OSA_NULL == streamIDmemAddrPtr->addr))
5269                                {
5270                                    M4OSA_TRACE1_0(
5271                                        "M4MP4W_setOption: Bad H264 dsi!");
5272                                    return M4ERR_PARAMETER;
5273                                }
5274
5275                                /* Store the DSI size */
5276                                mMp4FileDataPtr->videoTrackPtr->dsiSize =
5277                                    (M4OSA_UInt8)streamIDmemAddrPtr->size;
5278
5279                                /* Copy the DSI (SPS + PPS) */
5280                                mMp4FileDataPtr->videoTrackPtr->DSI = (M4OSA_UChar
5281                                    *)M4OSA_32bitAlignedMalloc(streamIDmemAddrPtr->size,
5282                                    M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
5283                                ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
5284                                    != M4OSA_NULL, M4ERR_ALLOC);
5285                                memcpy(
5286                                    (void *)mMp4FileDataPtr->videoTrackPtr->
5287                                    DSI,
5288                                    (void *)streamIDmemAddrPtr->addr,
5289                                    streamIDmemAddrPtr->size);
5290                                break;
5291
5292                            default:
5293                                return M4ERR_BAD_STREAM_ID;
5294                        }
5295                    break;
5296
5297                default:
5298                    return M4ERR_BAD_STREAM_ID;
5299                }
5300            }
5301            break;
5302            /* H.264 Trimming  */
5303        case M4MP4W_MUL_PPS_SPS:
5304            mMp4FileDataPtr->bMULPPSSPS = *(M4OSA_Int8 *)value;
5305            /* H.264 Trimming  */
5306            break;
5307
5308        default:
5309            return M4ERR_BAD_OPTION_ID;
5310    }
5311
5312    return err;
5313}
5314
5315/*******************************************************************************/
5316M4OSA_ERR M4MP4W_getState( M4OSA_Context context, M4MP4W_State *state,
5317                          M4SYS_StreamID streamID )
5318/*******************************************************************************/
5319{
5320    M4OSA_ERR err = M4NO_ERROR;
5321
5322    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
5323    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
5324
5325    switch( streamID )
5326    {
5327        case (0):
5328            *state = mMp4FileDataPtr->state;
5329            break;
5330
5331        case (AudioStreamID):
5332            if (mMp4FileDataPtr->hasAudio == M4OSA_TRUE)
5333            {
5334                *state = mMp4FileDataPtr->audioTrackPtr->microState;
5335            }
5336            else
5337            {
5338                return M4ERR_BAD_STREAM_ID;
5339            }
5340            break;
5341
5342        case (VideoStreamID):
5343            if (mMp4FileDataPtr->hasVideo == M4OSA_TRUE)
5344            {
5345                *state = mMp4FileDataPtr->videoTrackPtr->microState;
5346            }
5347            else
5348            {
5349                return M4ERR_BAD_STREAM_ID;
5350            }
5351            break;
5352
5353        default:
5354            return M4ERR_BAD_STREAM_ID;
5355    }
5356
5357    return err;
5358}
5359
5360/*******************************************************************************/
5361M4OSA_ERR M4MP4W_getCurrentFileSize( M4OSA_Context context,
5362                                    M4OSA_UInt32 *pCurrentFileSize )
5363/*******************************************************************************/
5364{
5365    M4OSA_ERR err = M4NO_ERROR;
5366
5367    M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
5368    ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
5369
5370    ERR_CHECK(pCurrentFileSize != M4OSA_NULL, M4ERR_PARAMETER);
5371    *pCurrentFileSize = mMp4FileDataPtr->filesize;
5372
5373    return err;
5374}
5375
5376#endif /* _M4MP4W_USE_CST_MEMORY_WRITER */
5377