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