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