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