1 /* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
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
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18 /*
19 The PVA_FF_Mpeg4File Class fp the class that will construct and maintain all the
20 mecessary data structures to be able to render a valid MP4 file to disk.
21 Format.
22 */
23
24
25 #define IMPLEMENT_Mpeg4File
26
27 #ifndef OSCL_STRING_UTILS_H_INCLUDED
28 #include "oscl_string_utils.h"
29 #endif
30
31 #include "mpeg4file.h"
32 #include "a_atomdefs.h"
33 #include "atomutils.h"
34
35 #include "pv_gau.h"
36 #include "oscl_byte_order.h"
37 #include "oscl_bin_stream.h"
38
39 #include "pv_mp4ffcomposer_config.h"
40
41 const uint8 aAMRNBZeroSetMask[9] =
42 {
43 0xfe, 0xfe, 0xfc, 0xfc,
44 0xf0, 0xfe, 0xf0, 0xf0,
45 0xfe
46 };
47 //IETF AMR WB Speech Frame Sizes (including zero byte padding but not including TOC)
48 //FT 0 (6.6 Kbps) - 17 bytes = 136 bits
49 //FT 1 (8.85 Kbps) - 23 bytes = 184 bits
50 //FT 2 (12.65 Kbps) - 32 bytes = 256 bits
51 //FT 3 (14.25 Kbps) - 36 bytes = 288 bits
52 //FT 4 (15.85 Kbps) - 40 bytes = 320 bits
53 //FT 5 (18.25 Kbps) - 46 bytes = 368 bits
54 //FT 6 (19.85 Kbps) - 50 bytes = 400 bits
55 //FT 7 (23.05 Kbps) - 58 bytes = 464 bits
56 //FT 8 (23.85 Kbps) - 60 bytes = 480 bits
57 //FT 9 (SID) - 5 bytes = 40 bits
58 //FT 10-13 - Reserved
59 //FT 14 (Lost frame) and FT 15 (NO DATA) - 0 bytes = 0 bits
60
61 //IETF AMR WB IF1 Speech Frame Sizes (just Class A, B & C speech bits, does not include FT or any other headers)
62 //FT 0 (6.6 Kbps) - 132 bits; num-bits-padded = 4
63 //FT 1 (8.85 Kbps) - 177 bits; num-bits-padded = 7
64 //FT 2 (12.65 Kbps) - 253 bits; num-bits-padded = 3
65 //FT 3 (14.25 Kbps) - 285 bits; num-bits-padded = 3
66 //FT 4 (15.85 Kbps) - 317 bits; num-bits-padded = 3
67 //FT 5 (18.25 Kbps) - 365 bits; num-bits-padded = 3
68 //FT 6 (19.85 Kbps) - 397 bits; num-bits-padded = 3
69 //FT 7 (23.05 Kbps) - 461 bits; num-bits-padded = 3
70 //FT 8 (23.85 Kbps) - 477 bits; num-bits-padded = 3
71 //FT 9 (SID) - 5 bytes = 40 bits; num-bits-padded = 0
72 //FT 10-13 - Reserved
73 //FT 14 (Lost frame) and FT 15 (NO DATA) - 0 bytes = 0 bits; num-bits-padded = 0
74
75 // Difference between IF1 bits and IETF storage bits is padded with zeros to byte align the frame
76 const uint8 aAMRWBZeroSetMask[9] =
77 {
78 0xf0, 0x80, 0xf8, 0xf8,
79 0xf8, 0xf8, 0xf8, 0xf8,
80 0xf8
81 };
82
83 typedef Oscl_Vector<PVA_FF_MediaDataAtom*, OsclMemAllocator> PVA_FF_MediaDataAtomVecType;
84 typedef Oscl_Vector<PVA_FF_MovieFragmentAtom*, OsclMemAllocator> PVA_FF_MovieFragmentAtomVecType;
85 typedef Oscl_Vector<PVA_FF_InterLeaveBuffer*, OsclMemAllocator> PVA_FF_InterLeaveBufferVecType;
86
87 //common to both AMR and AMR-WB
88 const uint32 AMRModeSetMask[16] =
89 {
90 0x0001, 0x0002, 0x0004, 0x0008,
91 0x0010, 0x0020, 0x0040, 0x0080,
92 0x0100, 0x0200, 0x0400, 0x0800,
93 0x1000, 0x2000, 0x4000, 0x8000
94 };
95
96 // Constructor
PVA_FF_Mpeg4File(int32 mediaType)97 PVA_FF_Mpeg4File::PVA_FF_Mpeg4File(int32 mediaType)
98 {
99 OSCL_UNUSED_ARG(mediaType);
100 _success = true;
101
102 _tempFilePostfix = _STRLIT("");
103
104 _tempOutputPath = _STRLIT("");
105
106 _oUserDataPopulated = true;
107 _pmovieAtom = NULL;
108 _pmediaDataAtomVec = NULL;
109 _puserDataAtom = NULL;
110 _pFileTypeAtom = NULL;
111 _pCurrentMoofAtom = NULL;
112 _pCurrentMediaDataAtom = NULL;
113 iCacheSize = 0;
114 _oIsFileOpen = false;
115 _pInterLeaveBufferVec = NULL;
116 _oInterLeaveEnabled = false;
117 _aFs = NULL;
118 }
119
120 // Destructor
~PVA_FF_Mpeg4File()121 PVA_FF_Mpeg4File::~PVA_FF_Mpeg4File()
122 {
123
124 {
125 if (_oUserDataPopulated == false)
126 {
127 populateUserDataAtom();
128 }
129 }
130
131 // Clean up atoms
132 if (_pmovieAtom != NULL)
133 {
134 PV_MP4_FF_DELETE(NULL, PVA_FF_MovieAtom, _pmovieAtom);
135 }
136
137 int32 i;
138
139 // Delete all the atoms in the media data vec
140 if (_pmediaDataAtomVec != NULL)
141 {
142 int32 size = _pmediaDataAtomVec->size();
143 for (i = 0; i < size; i++)
144 {
145 PV_MP4_FF_DELETE(NULL, PVA_FF_MediaDataAtom, (*_pmediaDataAtomVec)[i]);
146 }
147
148 // Delete the vectors themselves
149 PV_MP4_FF_TEMPLATED_DELETE(NULL, PVA_FF_MediaDataAtomVecType, Oscl_Vector, _pmediaDataAtomVec);
150 }
151
152
153 if ((_oInterLeaveEnabled) && (NULL != _pInterLeaveBufferVec))
154 {
155 // delete all interleave buffers
156 int32 size = _pInterLeaveBufferVec->size();
157 for (i = 0; i < size; i++)
158 {
159 PV_MP4_FF_DELETE(NULL, PVA_FF_MediaDataAtom, (*_pInterLeaveBufferVec)[i]);
160 }
161
162 // Delete the vectors themselves
163 PV_MP4_FF_TEMPLATED_DELETE(NULL, PVA_FF_InterLeaveBufferVecType, Oscl_Vector, _pInterLeaveBufferVec);
164 }
165
166 // in movie fragment mode delete MOOF and MFRA atoms
167 if (_oMovieFragmentEnabled == true)
168 {
169 PV_MP4_FF_DELETE(NULL, PVA_FF_MovieFragmentAtom, _pCurrentMoofAtom);
170 PV_MP4_FF_DELETE(NULL, PVA_FF_MediaDataAtom, _pCurrentMediaDataAtom);
171
172 PV_MP4_FF_DELETE(NULL, PVA_FF_MovieFragmentRandomAccessAtom, _pMfraAtom);
173 }
174
175 // Delete user data if present
176 if (_puserDataAtom != NULL)
177 {
178 PV_MP4_FF_DELETE(NULL, PVA_FF_UserDataAtom, _puserDataAtom);
179 }
180
181 if (_pFileTypeAtom != NULL)
182 {
183 PV_MP4_FF_DELETE(NULL, PVA_FF_FileTypeAtom, _pFileTypeAtom);
184 }
185 if (_aFs)
186 {
187 PVA_FF_AtomUtils::closeFileSession(OSCL_STATIC_CAST(Oscl_FileServer*, _aFs));
188 }
189 }
190
SetCacheSize(uint32 aCacheSize)191 void PVA_FF_Mpeg4File::SetCacheSize(uint32 aCacheSize)
192 {
193 iCacheSize = aCacheSize;
194 }
195 bool
init(int32 mediaType,void * osclFileServerSession,uint32 fileAuthoringFlags)196 PVA_FF_Mpeg4File::init(int32 mediaType,
197 void *osclFileServerSession,
198 uint32 fileAuthoringFlags)
199 {
200 OSCL_UNUSED_ARG(mediaType);
201 _modifiable = true; // Allow addition of media samples
202 _firstFrameInLayer0 = true;
203 _firstFrameInLayer1 = true;
204 _fileWriteFailed = false;
205
206 _o3GPPTrack = true;
207 _oWMFTrack = false;
208 _oPVMMTrack = false;
209 _oMPEGTrack = false;
210
211 _oFileRenderCalled = false;
212 _oUserDataPopulated = false;
213 _oFtypPopulated = false;
214
215 _baseOffset = 0;
216 _oInterLeaveEnabled = false;
217 _oMovieAtomUpfront = false;
218
219 _oAuthorASSETINFOAtoms = false;
220 _oChunkStart = false;
221
222 // Movie Fragments flags initialised
223 _oMovieFragmentEnabled = false;
224 _oComposeMoofAtom = false;
225 _movieFragmentDuration = DEFAULT_MOVIE_FRAGMENT_DURATION_IN_MS;
226 _pCurrentMoofAtom = NULL;
227 _pCurrentMediaDataAtom = NULL;
228 _currentMoofOffset = 0;
229 _sequenceNumber = 0;
230
231
232 _aFs = osclFileServerSession;
233
234 _nextAvailableODID = 1;
235 _tempFileIndex = 'a';
236
237 _pmediaDataAtomVec = NULL;
238 _pmovieAtom = NULL;
239
240 _puserDataAtom = NULL;
241 _pFileTypeAtom = NULL;
242
243 _initialUserDataSize = 0;
244 _oDirectRenderEnabled = false;
245
246 _oSetTitleDone = false;
247 _oSetAuthorDone = false;
248 _oSetCopyrightDone = false;
249 _oSetDescriptionDone = false;
250 _oSetRatingDone = false;
251 _oSetCreationDateDone = false;
252 _oSetPerformerDone = false;
253 _oSetRatingDone = false;
254 _oSetGenreDone = false;
255 _oSetClassificationDone = false;
256 _oSetLocationInfoDone = false;
257 _oSetAlbumDone = false;
258 _oSetRecordingYearDone = false;
259
260
261 _totalTempFileRemoval = false;
262 _oUserDataUpFront = true;
263 _oIsFileOpen = false;
264 _oFirstSampleEditMode = false;
265
266 _fileAuthoringFlags = fileAuthoringFlags;
267
268 if (fileAuthoringFlags & PVMP4FF_SET_MEDIA_INTERLEAVE_MODE)
269 {
270 _oInterLeaveEnabled = true;
271 }
272
273 if (fileAuthoringFlags & PVMP4FF_SET_META_DATA_UPFRONT_MODE)
274 {
275 _oMovieAtomUpfront = true;
276 }
277
278 if ((fileAuthoringFlags & PVMP4FF_3GPP_DOWNLOAD_MODE) ==
279 (PVMP4FF_3GPP_DOWNLOAD_MODE))
280 {
281 //Not possible to remove temp files, without output file name being set
282 if (_outputFileNameSet == false)
283 {
284 return false;
285 }
286 _oInterLeaveEnabled = true;
287 _totalTempFileRemoval = true;
288 _oUserDataUpFront = false;
289 }
290
291 if (fileAuthoringFlags & PVMP4FF_SET_FIRST_SAMPLE_EDIT_MODE)
292 {
293 /* Supported only if interleaving is enabled */
294 if (!_oInterLeaveEnabled)
295 {
296 return false;
297 }
298 _oFirstSampleEditMode = true;
299 }
300
301 // Movie fragment mode
302 if ((fileAuthoringFlags & PVMP4FF_MOVIE_FRAGMENT_MODE) == PVMP4FF_MOVIE_FRAGMENT_MODE)
303 {
304 if (!_oInterLeaveEnabled)
305 {
306 return false;
307 }
308 _oMovieFragmentEnabled = true;
309 _totalTempFileRemoval = true;
310 _oUserDataUpFront = false;
311 }
312
313 // Create user data atom
314 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_UserDataAtom, (), _puserDataAtom);
315
316 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_FileTypeAtom, (), _pFileTypeAtom);
317
318 // Create the moov atom
319 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MovieAtom, (fileAuthoringFlags), _pmovieAtom);
320
321 // Movie fragment atom vectors initialised
322 if (_oMovieFragmentEnabled)
323 {
324 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MovieFragmentRandomAccessAtom, (), _pMfraAtom);
325 }
326
327 // IODS uses the first ODID, hence the increment here.
328 _nextAvailableODID++;
329
330 // Create miscellaneous vector of atoms
331 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtomVecType, (), _pmediaDataAtomVec);
332
333 _pparent = NULL;
334
335 /*
336 * In interleave mode, create only ONE media atom, to store
337 * all the media samples.
338 */
339 if (_oInterLeaveEnabled)
340 {
341 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_InterLeaveBufferVecType, (), _pInterLeaveBufferVec);
342 PVA_FF_MediaDataAtom *mda = NULL;
343 if (!_totalTempFileRemoval)
344 {
345 // Create PVA_FF_MediaDataAtom
346 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_tempOutputPath,
347 _tempFilePostfix,
348 _tempFileIndex,
349 MEDIA_DATA_ON_DISK,
350 _aFs, iCacheSize),
351 mda);
352
353 _tempFileIndex++;
354 }
355 else
356 {
357 if (_oFileOpenedOutsideAFFLib)
358 {
359 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_outputFileHandle, _aFs, iCacheSize), mda);
360 }
361 else
362 {
363 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_outputFileName, _aFs, iCacheSize), mda);
364 }
365 }
366
367 if (mda->_targetFileWriteError)
368 {
369 PV_MP4_FF_DELETE(NULL, PVA_FF_MediaDataAtom, mda);
370 mda = NULL;
371 return false;
372 }
373 addMediaDataAtom(mda);
374
375 _interLeaveDuration = DEFAULT_INTERLEAVE_INTERVAL;
376 }
377 {
378 _pmovieAtom->createAssetInfoAtoms();
379 }
380 recomputeSize();
381
382 return true;
383 }
384
385 bool
setOutputFileName(PVA_FF_UNICODE_STRING_PARAM outputFileName)386 PVA_FF_Mpeg4File::setOutputFileName(PVA_FF_UNICODE_STRING_PARAM outputFileName)
387 {
388 _targetFileName = (_STRLIT(""));
389 _oPartialTempFileRemoval = false;
390 _outputFileName = _STRLIT("");
391 _outputFileNameSet = false;
392 _outputFileHandle = NULL;
393 _targetFileHandle = NULL;
394 _oFileOpenedOutsideAFFLib = false;
395
396 if (outputFileName.get_size() > 0)
397 {
398 _outputFileName += outputFileName;
399 _outputFileNameSet = true;
400
401 if (!_oPartialTempFileRemoval)
402 {
403 _targetFileName += outputFileName;
404 _oPartialTempFileRemoval = true;
405 }
406 return true;
407 }
408 return false;
409 }
410
411 bool
setOutputFileHandle(MP4_AUTHOR_FF_FILE_HANDLE outputFileHandle)412 PVA_FF_Mpeg4File::setOutputFileHandle(MP4_AUTHOR_FF_FILE_HANDLE outputFileHandle)
413 {
414 _targetFileName = (_STRLIT(""));
415 _oPartialTempFileRemoval = false;
416 _outputFileName = _STRLIT("");
417 _outputFileNameSet = false;
418 _outputFileHandle = NULL;
419 _targetFileHandle = NULL;
420 _oFileOpenedOutsideAFFLib = false;
421
422 if (outputFileHandle != NULL)
423 {
424 _outputFileHandle = outputFileHandle;
425 _outputFileNameSet = true;
426
427 if (!_oPartialTempFileRemoval)
428 {
429 _targetFileHandle = outputFileHandle;
430 _oPartialTempFileRemoval = true;
431 }
432 _oFileOpenedOutsideAFFLib = true;
433 return true;
434 }
435 return false;
436 }
437
438 uint32
addTrack(int32 mediaType,int32 codecType,bool oDirectRender,uint8 profile,uint8 profileComp,uint8 level)439 PVA_FF_Mpeg4File::addTrack(int32 mediaType,
440 int32 codecType,
441 bool oDirectRender,
442 uint8 profile,
443 uint8 profileComp,
444 uint8 level)
445 {
446 uint32 TrackID = 0;
447 PVA_FF_TrackAtom *pmediatrack = NULL;
448 _codecType = codecType;
449 PVA_FF_MediaDataAtom *mda = NULL;
450 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = NULL;
451
452 if (!_oInterLeaveEnabled)
453 {
454 if (oDirectRender)
455 {
456 if (!_oDirectRenderEnabled)
457 {
458 if ((_oPartialTempFileRemoval) &&
459 (_totalTempFileRemoval == false))
460 {
461 _oDirectRenderEnabled = true;
462
463 if (_oFileOpenedOutsideAFFLib)
464 {
465 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_targetFileHandle, _aFs, iCacheSize), mda);
466 }
467 else
468 {
469 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_targetFileName, _aFs, iCacheSize), mda);
470 }
471 }
472 else
473 {
474 //Target File name not set
475 return (INVALID_TRACK_ID);
476 }
477 }
478 else
479 {
480 //Multiple Tracks cannot be directly rendered
481 return (INVALID_TRACK_ID);
482 }
483 }
484 else
485 {
486 //create new track - media will be stored in temp file
487 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_tempOutputPath,
488 _tempFilePostfix,
489 _tempFileIndex,
490 MEDIA_DATA_ON_DISK,
491 _aFs, iCacheSize), mda);
492
493 _tempFileIndex++;
494 }
495 addMediaDataAtom(mda);
496 }
497 else
498 {
499 mda = getMediaDataAtomForTrack(0);
500 }
501
502 if ((uint32) mediaType == MEDIA_TYPE_AUDIO)
503 {
504 // Create default audio track and add it to moov atom
505 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_TrackAtom, (MEDIA_TYPE_AUDIO,
506 _pmovieAtom->getMutableMovieHeaderAtom().findNextTrackID(),
507 _fileAuthoringFlags,
508 codecType,
509 1, profile, profileComp, level),
510 pmediatrack);
511
512 if (mda)
513 mda->setTrackReferencePtr(pmediatrack);
514 _pmovieAtom->addTrackAtom(pmediatrack);
515
516 // add audio interleave buffer for track
517 if (_oInterLeaveEnabled)
518 {
519 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_InterLeaveBuffer, (MEDIA_TYPE_AUDIO,
520 codecType,
521 pmediatrack->getTrackID()),
522 pInterLeaveBuffer);
523
524 addInterLeaveBuffer(pInterLeaveBuffer);
525 }
526
527 // Returns the index of the reference in the table to which this was
528 // just added (with a 1-based index NOT a zero-based index)
529
530 TrackID = pmediatrack->getTrackID();
531
532 if ((codecType == CODEC_TYPE_AMR_AUDIO) ||
533 (codecType == CODEC_TYPE_AMR_WB_AUDIO))
534 {
535 _o3GPPTrack = true;
536 }
537 if (codecType == CODEC_TYPE_AAC_AUDIO)
538 {
539 _o3GPPTrack = true;
540 _oMPEGTrack = true;
541 }
542 }
543
544 if ((uint32) mediaType == MEDIA_TYPE_VISUAL)
545 {
546 if ((codecType == CODEC_TYPE_BASELINE_H263_VIDEO) ||
547 (codecType == CODEC_TYPE_AVC_VIDEO))
548 {
549 _o3GPPTrack = true;
550 }
551 else if (codecType == CODEC_TYPE_MPEG4_VIDEO)
552 {
553 _o3GPPTrack = true;
554 _oMPEGTrack = true;
555 }
556
557 // Create default video track and add it to moov atom
558 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_TrackAtom, (MEDIA_TYPE_VISUAL,
559 _pmovieAtom->getMutableMovieHeaderAtom().findNextTrackID(),
560 _fileAuthoringFlags,
561 codecType,
562 1, profile, profileComp, level),
563 pmediatrack);
564
565 // add video interleave buffer for track
566
567 if (_oInterLeaveEnabled)
568 {
569 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_InterLeaveBuffer, (MEDIA_TYPE_VISUAL,
570 codecType,
571 pmediatrack->getTrackID()),
572 pInterLeaveBuffer);
573
574 addInterLeaveBuffer(pInterLeaveBuffer);
575 }
576
577 if (mda)
578 mda->setTrackReferencePtr(pmediatrack);
579 _pmovieAtom->addTrackAtom(pmediatrack);
580
581 // Returns the index of the reference in the table to which this was
582 // just added (with a 1-based index NOT a zero-based index)
583 TrackID = pmediatrack->getTrackID();
584 }
585
586 if ((uint32) mediaType == MEDIA_TYPE_TEXT)//added for the support of timed text track
587 {
588 if (codecType == CODEC_TYPE_TIMED_TEXT)
589 {
590 _o3GPPTrack = true;
591 }
592 // Create default video track and add it to moov atom
593 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_TrackAtom, (MEDIA_TYPE_TEXT,
594 _pmovieAtom->getMutableMovieHeaderAtom().findNextTrackID(),
595 _fileAuthoringFlags,
596 codecType,
597 1,
598 profile, profileComp, level),
599 pmediatrack);
600
601 // add text interleave buffer for track
602 if (_oInterLeaveEnabled)
603 {
604 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_InterLeaveBuffer, (MEDIA_TYPE_TEXT,
605 codecType,
606 pmediatrack->getTrackID()),
607 pInterLeaveBuffer);
608
609 addInterLeaveBuffer(pInterLeaveBuffer);
610 }
611
612 mda->setTrackReferencePtr(pmediatrack);
613 _pmovieAtom->addTrackAtom(pmediatrack);
614
615 // Returns the index of the reference in the table to which this was
616 // just added (with a 1-based index NOT a zero-based index)
617 TrackID = pmediatrack->getTrackID();
618 }
619 recomputeSize();
620 return (TrackID);
621 }
622
623 void
addTrackReference(uint32 currtrackID,int32 reftrackID)624 PVA_FF_Mpeg4File::addTrackReference(uint32 currtrackID, int32 reftrackID)
625 {
626 PVA_FF_TrackAtom *pCurrTrack = _pmovieAtom->getMediaTrack(currtrackID);
627 pCurrTrack->addTrackReference(reftrackID);
628 return;
629 }
630
631 void
setTargetBitrate(uint32 trackID,uint32 avgBitRate,uint32 maxBitRate,uint32 bufferSizeDB)632 PVA_FF_Mpeg4File::setTargetBitrate(uint32 trackID, uint32 avgBitRate, uint32 maxBitRate, uint32 bufferSizeDB)
633 {
634 _pmovieAtom->setTargetBitrate(trackID, avgBitRate, maxBitRate, bufferSizeDB);
635 return;
636 }
637
638 void
setTimeScale(uint32 trackID,uint32 rate)639 PVA_FF_Mpeg4File::setTimeScale(uint32 trackID, uint32 rate)
640 {
641 // Set the sample rate for the specific video track
642 _pmovieAtom->setTimeScale(trackID, rate);
643 return;
644 }
645
646 //this will work same as the addsampletotrack but this
647 //will be called only for timed text file format
addTextSampleToTrack(uint32 trackID,Oscl_Vector<OsclMemoryFragment,OsclMemAllocator> & fragmentList,uint32 ts,uint8 flags,int32 index,uint8 * textsamplemodifier)648 bool PVA_FF_Mpeg4File::addTextSampleToTrack(uint32 trackID,
649 Oscl_Vector <OsclMemoryFragment, OsclMemAllocator>& fragmentList,
650 uint32 ts, uint8 flags, int32 index, uint8* textsamplemodifier)
651 {
652 OSCL_UNUSED_ARG(textsamplemodifier);
653 PVA_FF_TrackAtom *mediaTrack;
654 uint32 mediaType;
655 int32 codecType;
656 bool retVal = true;
657
658 mediaTrack = _pmovieAtom->getMediaTrack(trackID);
659 mediaType = mediaTrack->getMediaType();
660 codecType = _pmovieAtom->getCodecType(trackID);
661
662 // Create media sample buffer and size field
663 uint32 size = 0;
664 // temporary variables
665 uint32 ii = 0;
666 OsclBinIStreamBigEndian stream;
667
668 if (!fragmentList.empty())
669 {
670 if (mediaType == MEDIA_TYPE_TEXT)//CALCULATES SIZE OF TIMED TEXT SAMPLE
671 {
672 for (ii = 0; ii < fragmentList.size(); ii++)
673 {
674 size += fragmentList[ii].len;
675 }
676 }
677 }
678
679 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID);
680 if (mediaType == MEDIA_TYPE_TEXT)
681 {
682 if (_modifiable)
683 {
684 // The layer in the flags byte indicates which video track to add to
685 // int32 trackNum = (int32)(flags & 0x70) >> 4;
686
687 if (mediaTrack)
688 {
689 // Add to mdat PVA_FF_Atom for the specified track
690 if (codecType == CODEC_TYPE_TIMED_TEXT)
691 {
692 if (_oInterLeaveEnabled)
693 {
694 if (!addTextMediaSampleInterleave(trackID, fragmentList, size, ts, flags, index))
695 {
696 return false;
697 }
698 }
699 else
700 {
701 if (!mdatAtom->addRawSample((fragmentList), (size), mediaType, codecType))
702 {
703 retVal = false;
704 }
705 _pmovieAtom->addTextSampleToTrack(trackID, fragmentList, size, ts, flags, index);
706 }
707 }
708 }
709 else
710 {
711 return false;
712 }
713 }
714 else
715 {
716 return false;
717 }
718 }
719
720 return (retVal);
721 }
722
723 // Movie fragment Mode : APIs to set and get duration of each MOOF atom
724 void
setMovieFragmentDuration(uint32 duration)725 PVA_FF_Mpeg4File::setMovieFragmentDuration(uint32 duration)
726 {
727 _movieFragmentDuration = duration;
728 return;
729 }
730
731
732
733 uint32
getMovieFragmentDuration()734 PVA_FF_Mpeg4File::getMovieFragmentDuration()
735 {
736 return _movieFragmentDuration;
737 }
738
739
740 bool
addSampleToTrack(uint32 trackID,Oscl_Vector<OsclMemoryFragment,OsclMemAllocator> & fragmentList,uint32 ts,uint8 flags)741 PVA_FF_Mpeg4File::addSampleToTrack(uint32 trackID,
742 Oscl_Vector <OsclMemoryFragment, OsclMemAllocator>& fragmentList, // vector which contains either NALs or a sample
743 uint32 ts, uint8 flags)
744 {
745 PVA_FF_TrackAtom *mediaTrack;
746 uint32 mediaType;
747 int32 codecType;
748 bool retVal = true;
749 //int32 flags;
750
751 mediaTrack = _pmovieAtom->getMediaTrack(trackID);
752 mediaType = mediaTrack->getMediaType();
753 codecType = _pmovieAtom->getCodecType(trackID);
754
755 // Create media sample buffer and size field
756 uint32 size = 0;
757 // temporary variables
758 uint32 ii = 0;
759 OsclBinIStreamBigEndian stream;
760 OsclMemoryFragment fragment;
761 if (!fragmentList.empty())
762 {
763 // calculate size of AVC sample
764 if (mediaType == MEDIA_TYPE_VISUAL && codecType == CODEC_TYPE_AVC_VIDEO)
765 {
766 // compose AVC sample
767 for (uint32 ii = 0; ii < fragmentList.size(); ii++)
768 {
769 size += (fragmentList[ii].len + 4); // length + '2' size of NAL unit length field
770 }
771 }
772 // all memory fragments in the vector combines into one sample
773 else
774 {
775 for (ii = 0; ii < fragmentList.size(); ii++)
776 {
777 size += fragmentList[ii].len;
778 }
779 }
780 }
781
782 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID);
783 if (mediaType == MEDIA_TYPE_AUDIO)
784 {
785 if (_modifiable)
786 {
787 if (mediaTrack != NULL)
788 {
789 if ((mediaTrack->getCodecType() == CODEC_TYPE_AMR_AUDIO) ||
790 (mediaTrack->getCodecType() == CODEC_TYPE_AMR_WB_AUDIO))
791 {
792 if (size >= 1)
793 {
794 PVA_FF_TrackAtom *track = _pmovieAtom->getMediaTrack(trackID);
795 if (track != NULL)
796 {
797 // FT is in the first byte that comes off the encoder
798 flags = *((uint8*)(fragmentList.front().ptr));
799 uint32 mode_set = 0;
800 if (flags < 16)
801 {
802 mode_set = AMRModeSetMask[(flags&0x0f)];
803 }
804 if (flags < 9)
805 {
806 // JUST TO ENSURE THAT THE PADDED BITS ARE ZERO
807 fragment = fragmentList.back();
808 if (mediaTrack->getCodecType() == CODEC_TYPE_AMR_AUDIO)
809 {
810 ((uint8*)fragment.ptr)[ fragment.len - 1] &= aAMRNBZeroSetMask[(flags&0x0f)];
811 }
812 else if (mediaTrack->getCodecType() == CODEC_TYPE_AMR_WB_AUDIO)
813 {
814 ((uint8*)fragment.ptr)[ fragment.len - 1] &= aAMRWBZeroSetMask[(flags&0x0f)];
815 }
816
817 }
818 if (_oInterLeaveEnabled)
819 {
820 if (!addMediaSampleInterleave(trackID, fragmentList, size, ts, flags))
821 {
822 return false;
823 }
824 }
825 else
826 {
827 // Add to mdat PVA_FF_Atom for the specified track
828 if (!mdatAtom->addRawSample(fragmentList, size, mediaType, codecType))
829 {
830 retVal = false;
831 }
832 // Add to moov atom (in turn adds to tracks)
833 _pmovieAtom->addSampleToTrack(trackID, fragmentList, size,
834 ts, flags);
835 }
836 }
837 }
838 else
839 {
840 return false;
841 }
842 }
843 else if (mediaTrack->getCodecType() == CODEC_TYPE_AAC_AUDIO)
844 {
845 if (size > 0)
846 {
847 if (_oInterLeaveEnabled)
848 {
849 if (!addMediaSampleInterleave(trackID, fragmentList, size, ts, flags))
850 {
851 return false;
852 }
853 }
854 else
855 {
856
857 // Add to mdat PVA_FF_Atom for the specified track
858
859 if (!mdatAtom->addRawSample((fragmentList), (size), mediaType, codecType))
860 {
861 retVal = false;
862 }
863
864 flags = 0;
865
866 // Add to moov atom (in turn adds to tracks)
867 _pmovieAtom->addSampleToTrack(trackID, fragmentList, size,
868 ts, flags);
869 }
870 }
871 }
872 }
873 else
874 {
875 return false;
876 }
877 }
878 else
879 {
880 return false;
881 }
882 }
883
884 if (mediaType == MEDIA_TYPE_VISUAL)
885 {
886 // For the first frame in each layer, pull off the VOL header. For the base layer
887 // (layer=0), this fp the first 28 bytes. For the enhancememnt(temporal) layer
888 // (layer=1), this fp the first 17 bytes (compact version with no repeate headers).
889 //
890 // Note that this fp making the assumption that the first frame of each layer will
891 // contain this VOL header information. In the current encoder (version 1.0), this
892 // fp true.
893 //
894 // Eventually strip the VOL headers from the first samples of each layer so that
895 // there fp no redundancy w.r.t. the VOL headers in the MP4 file. Currently the
896 // VOL headers are remaining in the first frame data
897
898 // uint8 layer = (uint8)((flags & 0x70) >> 4);
899
900
901 if (codecType == CODEC_TYPE_BASELINE_H263_VIDEO)
902 {
903 if (_firstFrameInLayer0)
904 {
905 _firstFrameInLayer0 = false;
906 }
907 }
908
909 if (_modifiable)
910 {
911 // The layer in the flags byte indicates which video track to add to
912 // int32 trackNum = (int32)(flags & 0x70) >> 4;
913
914 if (mediaTrack)
915 {
916 // Add to mdat PVA_FF_Atom for the specified track
917 if ((codecType == CODEC_TYPE_MPEG4_VIDEO) ||
918 (codecType == CODEC_TYPE_BASELINE_H263_VIDEO) ||
919 (codecType == CODEC_TYPE_AVC_VIDEO))
920 {
921 if (_oInterLeaveEnabled)
922 {
923 if (!addMediaSampleInterleave(trackID, fragmentList, size, ts, flags))
924 {
925 return false;
926 }
927 }
928 else
929 {
930
931 if (!mdatAtom->addRawSample((fragmentList), (size), mediaType, codecType))
932 {
933 retVal = false;
934 }
935 _pmovieAtom->addSampleToTrack(trackID, fragmentList, size, ts, flags);
936 }
937 }
938 }
939 else
940 {
941 return false;
942 }
943 }
944 else
945 {
946 return false;
947 }
948 }
949
950 return (retVal);
951 }
952
953 // The following methods are used to set the user data
954 void
setVersion(PVA_FF_UNICODE_STRING_PARAM version,uint16 langCode)955 PVA_FF_Mpeg4File::setVersion(PVA_FF_UNICODE_STRING_PARAM version, uint16 langCode)
956 {
957 OSCL_UNUSED_ARG(version);
958 OSCL_UNUSED_ARG(langCode);
959 }
960
961 void
setTitle(PVA_FF_UNICODE_STRING_PARAM title,uint16 langCode)962 PVA_FF_Mpeg4File::setTitle(PVA_FF_UNICODE_STRING_PARAM title, uint16 langCode)
963 {
964 if (!_oSetTitleDone)
965 {
966 _oSetTitleDone = true;
967 _title = title;
968 if (_pmovieAtom != NULL)
969 {
970 _pmovieAtom->setTitleInfo(title, langCode);
971 }
972 }
973 }
974
975 void
setAuthor(PVA_FF_UNICODE_STRING_PARAM author,uint16 langCode)976 PVA_FF_Mpeg4File::setAuthor(PVA_FF_UNICODE_STRING_PARAM author, uint16 langCode)
977 {
978 if (!_oSetAuthorDone)
979 {
980 _oSetAuthorDone = true;
981 _author = author;
982 if (_pmovieAtom != NULL)
983 {
984 _pmovieAtom->setAuthorInfo(author, langCode);
985 }
986 }
987 }
988
989 void
setCopyright(PVA_FF_UNICODE_STRING_PARAM copyright,uint16 langCode)990 PVA_FF_Mpeg4File::setCopyright(PVA_FF_UNICODE_STRING_PARAM copyright, uint16 langCode)
991 {
992 if (!_oSetCopyrightDone)
993 {
994 _oSetCopyrightDone = true;
995 _copyright = copyright;
996 if (_pmovieAtom != NULL)
997 {
998 _pmovieAtom->setCopyRightInfo(copyright, langCode);
999 }
1000 }
1001 }
1002
1003 void
setDescription(PVA_FF_UNICODE_STRING_PARAM description,uint16 langCode)1004 PVA_FF_Mpeg4File::setDescription(PVA_FF_UNICODE_STRING_PARAM description, uint16 langCode)
1005 {
1006 if (!_oSetDescriptionDone)
1007 {
1008 _oSetDescriptionDone = true;
1009 _description = description;
1010 if (_pmovieAtom != NULL)
1011 {
1012 _pmovieAtom->setDescription(description, langCode);
1013 }
1014 }
1015 }
1016
1017 void
setRating(PVA_FF_UNICODE_STRING_PARAM ratingInfo,uint16 langCode,uint32 ratingEntity,uint32 ratingCriteria)1018 PVA_FF_Mpeg4File::setRating(PVA_FF_UNICODE_STRING_PARAM ratingInfo,
1019 uint16 langCode,
1020 uint32 ratingEntity,
1021 uint32 ratingCriteria)
1022 {
1023 OSCL_UNUSED_ARG(langCode);
1024
1025 if (!_oSetRatingDone)
1026 {
1027 _oSetRatingDone = true;
1028 _ratingInfo = ratingInfo;
1029 _ratingEntity = ratingEntity;
1030 _ratingCriteria = ratingCriteria;
1031 if (_pmovieAtom != NULL)
1032 {
1033 _pmovieAtom->setRatingInfo(ratingInfo, ratingEntity, ratingCriteria, langCode);
1034 }
1035
1036 }
1037 }
1038
1039 void
setPerformer(PVA_FF_UNICODE_STRING_PARAM performer,uint16 langCode)1040 PVA_FF_Mpeg4File::setPerformer(PVA_FF_UNICODE_STRING_PARAM performer, uint16 langCode)
1041 {
1042 OSCL_UNUSED_ARG(langCode);
1043
1044 if (!_oSetPerformerDone)
1045 {
1046 _oSetPerformerDone = true;
1047 _performer = performer;
1048
1049 if (_pmovieAtom != NULL)
1050 {
1051 _pmovieAtom->setPerformerInfo(performer, langCode);
1052 }
1053
1054 }
1055 }
1056
1057 void
setGenre(PVA_FF_UNICODE_STRING_PARAM genre,uint16 langCode)1058 PVA_FF_Mpeg4File::setGenre(PVA_FF_UNICODE_STRING_PARAM genre, uint16 langCode)
1059 {
1060 OSCL_UNUSED_ARG(langCode);
1061
1062 if (!_oSetGenreDone)
1063 {
1064 _oSetGenreDone = true;
1065 _genre = genre;
1066
1067 if (_pmovieAtom != NULL)
1068 {
1069 _pmovieAtom->setGenreInfo(genre, langCode);
1070 }
1071
1072 }
1073 }
1074
1075 void
setClassification(PVA_FF_UNICODE_STRING_PARAM classificationInfo,uint32 classificationEntity,uint16 classificationTable,uint16 langCode)1076 PVA_FF_Mpeg4File::setClassification(PVA_FF_UNICODE_STRING_PARAM classificationInfo,
1077 uint32 classificationEntity, uint16 classificationTable,
1078 uint16 langCode)
1079 {
1080 OSCL_UNUSED_ARG(langCode);
1081
1082 if (!_oSetClassificationDone)
1083 {
1084 _oSetClassificationDone = true;
1085 _classificationInfo = classificationInfo;
1086 _classificationEntity = classificationEntity;
1087 _classificationTable = classificationTable;
1088
1089 if (_pmovieAtom != NULL)
1090 {
1091 _pmovieAtom->setClassificationInfo(classificationInfo, classificationEntity, classificationTable, langCode);
1092 }
1093 }
1094 }
1095
1096 void
setKeyWord(uint8 keyWordSize,PVA_FF_UNICODE_HEAP_STRING keyWordInfo,uint16 langCode)1097 PVA_FF_Mpeg4File::setKeyWord(uint8 keyWordSize, PVA_FF_UNICODE_HEAP_STRING keyWordInfo, uint16 langCode)
1098 {
1099 OSCL_UNUSED_ARG(langCode);
1100
1101 _keyWordSize = keyWordSize;
1102 _keyWordInfo = keyWordInfo;
1103
1104 if (_pmovieAtom != NULL)
1105 {
1106 _pmovieAtom->setKeyWordsInfo(keyWordSize, keyWordInfo, langCode);
1107 }
1108 }
1109
1110 void
setLocationInfo(PvmfAssetInfo3GPPLocationStruct * ptr_loc_struct)1111 PVA_FF_Mpeg4File::setLocationInfo(PvmfAssetInfo3GPPLocationStruct *ptr_loc_struct)
1112 {
1113 if (!_oSetLocationInfoDone)
1114 {
1115 _oSetLocationInfoDone = true;
1116 _locationName = ptr_loc_struct->_location_name;
1117 _locationInfoAstrBody = ptr_loc_struct->_astronomical_body;
1118 _locationInfoAddNotes = ptr_loc_struct->_additional_notes;
1119 _locationInfoRole = ptr_loc_struct->_role;
1120 _locationInfoLongitude = ptr_loc_struct->_longitude;
1121 _locationInfoAltitude = ptr_loc_struct->_altitude;
1122 _locationInfoLatitude = ptr_loc_struct->_latitude;
1123
1124 if (_pmovieAtom != NULL)
1125 {
1126 _pmovieAtom->setLocationInfo(ptr_loc_struct);
1127 }
1128 }
1129 }
1130
1131 void
setAlbumInfo(PVA_FF_UNICODE_STRING_PARAM albumInfo,uint16 langCode)1132 PVA_FF_Mpeg4File::setAlbumInfo(PVA_FF_UNICODE_STRING_PARAM albumInfo, uint16 langCode)
1133 {
1134 if (!_oSetAlbumDone)
1135 {
1136 _oSetAlbumDone = true;
1137 _albumInfo = albumInfo;
1138
1139 if (_pmovieAtom != NULL)
1140 {
1141 _pmovieAtom->setAlbumInfo(albumInfo, langCode);
1142 }
1143
1144 }
1145 }
1146
1147 void
setAlbumTrackNumber(uint8 trackNumber)1148 PVA_FF_Mpeg4File::setAlbumTrackNumber(uint8 trackNumber)
1149 {
1150 if (_pmovieAtom != NULL)
1151 {
1152 _pmovieAtom->setAlbumTrackNumber(trackNumber);
1153 }
1154 }
1155
1156 void
setRecordingYear(uint16 recordingYear)1157 PVA_FF_Mpeg4File::setRecordingYear(uint16 recordingYear)
1158 {
1159 if (!_oSetRecordingYearDone)
1160 {
1161 _oSetRecordingYearDone = true;
1162 _recordingYear = recordingYear;
1163
1164 if (_pmovieAtom != NULL)
1165 {
1166 _pmovieAtom->setRecordingYearInfo(recordingYear);
1167 }
1168
1169 }
1170 }
1171
1172 void
setCreationDate(PVA_FF_UNICODE_STRING_PARAM creationDate)1173 PVA_FF_Mpeg4File::setCreationDate(PVA_FF_UNICODE_STRING_PARAM creationDate)
1174 {
1175 if (!_oSetCreationDateDone)
1176 {
1177 _oSetCreationDateDone = true;
1178 _creationDate = creationDate;
1179 }
1180 }
1181
1182 void
setVideoParams(uint32 trackID,float frate,uint16 interval,uint32 frame_width,uint32 frame_height)1183 PVA_FF_Mpeg4File::setVideoParams(uint32 trackID,
1184 float frate,
1185 uint16 interval,
1186 uint32 frame_width,
1187 uint32 frame_height)
1188 {
1189 OSCL_UNUSED_ARG(frate);
1190 OSCL_UNUSED_ARG(interval);
1191 PVA_FF_TrackAtom *trackAtom;
1192 trackAtom = _pmovieAtom->getMediaTrack(trackID);
1193
1194 if (trackAtom != NULL)
1195 trackAtom->setVideoParams(frame_width, frame_height);
1196
1197 return;
1198 }
1199
1200 void
setH263ProfileLevel(uint32 trackID,uint8 profile,uint8 level)1201 PVA_FF_Mpeg4File::setH263ProfileLevel(uint32 trackID,
1202 uint8 profile,
1203 uint8 level)
1204 {
1205 PVA_FF_TrackAtom *trackAtom;
1206 trackAtom = _pmovieAtom->getMediaTrack(trackID);
1207 trackAtom->setH263ProfileLevel(profile, level);
1208 return;
1209 }
1210
1211 // Methods to get and set the sample rate (i.e. timescales) for the streams and
1212 // the overall Mpeg-4 presentation
1213 void
setPresentationTimescale(uint32 timescale)1214 PVA_FF_Mpeg4File::setPresentationTimescale(uint32 timescale)
1215 { // Set the overall timescale of the Mpeg-4 presentation
1216 _pmovieAtom->setTimeScale(timescale);
1217 }
1218
1219 void
addMediaDataAtom(PVA_FF_MediaDataAtom * atom)1220 PVA_FF_Mpeg4File::addMediaDataAtom(PVA_FF_MediaDataAtom* atom)
1221 {
1222 if (_modifiable)
1223 {
1224 _pmediaDataAtomVec->push_back(atom);
1225 }
1226 }
1227
1228 //for timed text only
1229 void
setTextDecoderSpecificInfo(PVA_FF_TextSampleDescInfo * header,int32 trackID)1230 PVA_FF_Mpeg4File::setTextDecoderSpecificInfo(PVA_FF_TextSampleDescInfo *header, int32 trackID)
1231 {
1232 PVA_FF_TextSampleDescInfo *pinfo = NULL;
1233 pinfo = header;
1234 _pmovieAtom->addTextDecoderSpecificInfo(pinfo, trackID);
1235 return;
1236 }
1237
1238
1239 void
setDecoderSpecificInfo(uint8 * header,int32 size,int32 trackID)1240 PVA_FF_Mpeg4File::setDecoderSpecificInfo(uint8 * header, int32 size, int32 trackID)
1241 {
1242 PVA_FF_DecoderSpecificInfo *pinfo = NULL;
1243 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_DecoderSpecificInfo, (header, (uint32)size), pinfo);
1244 _pmovieAtom->addDecoderSpecificInfo(pinfo, trackID);
1245 PVA_FF_TrackAtom *track = _pmovieAtom->getMediaTrack(trackID);
1246 if (track->getMediaType() == MEDIA_TYPE_VISUAL)
1247 {
1248 if (track->getCodecType() == CODEC_TYPE_AVC_VIDEO)
1249 {
1250 PV_MP4_FF_DELETE(NULL, PVA_FF_DecoderSpecificInfo, pinfo);
1251 }
1252 }
1253 }
1254
1255 void
recomputeSize()1256 PVA_FF_Mpeg4File::recomputeSize()
1257 {
1258 uint32 i;
1259 uint32 size = getMovieAtom().getSize();
1260
1261 for (i = 0; i < getMediaDataAtomVec().size(); i++)
1262 {
1263 size += getMediaDataAtomVec()[i]->getSize();
1264 }
1265 _size = size;
1266 }
1267
1268 // Rendering the PVA_FF_Mpeg4File in proper format (bitlengths, etc.) to an ostream
1269 bool
renderToFileStream(MP4_AUTHOR_FF_FILE_IO_WRAP * fp)1270 PVA_FF_Mpeg4File::renderToFileStream(MP4_AUTHOR_FF_FILE_IO_WRAP *fp)
1271 {
1272 uint32 metaDataSize = 0;
1273 /*
1274 * Setting the major brand in ftyp atom
1275 */
1276 if (!_oFtypPopulated)
1277 {
1278 if (_o3GPPTrack)
1279 {
1280 setMajorBrand(BRAND_3GPP4);
1281 setMajorBrandVersion(VERSION_3GPP4);
1282 }
1283 else if (_oMPEGTrack)
1284 {
1285 setMajorBrand(BRAND_MPEG4);
1286 setMajorBrandVersion(VERSION_MPEG4);
1287 }
1288 else if (_oPVMMTrack)
1289 {
1290 setMajorBrand(PVMM_BRAND);
1291 setMajorBrandVersion(PVMM_VERSION);
1292 }
1293
1294 /*
1295 * Add compatible brands
1296 */
1297 if (_o3GPPTrack)
1298 {
1299 addCompatibleBrand(BRAND_3GPP4);
1300 }
1301 if (_oPVMMTrack)
1302 {
1303 addCompatibleBrand(PVMM_BRAND);
1304 }
1305 if (_oMPEGTrack)
1306 {
1307 addCompatibleBrand(BRAND_MPEG4);
1308 }
1309 addCompatibleBrand(BRAND_3GPP5);
1310 }
1311
1312 if( _oSetCreationDateDone )
1313 {
1314 uint32 time = convertCreationTime(_creationDate);
1315
1316 _pmovieAtom->getMutableMovieHeaderAtom().setCreationTime(time);
1317 _pmovieAtom->getMutableMovieHeaderAtom().setModificationTime(time);
1318 }
1319
1320 if ((_o3GPPTrack == true) || (_oPVMMTrack == true) || (_oMPEGTrack == true))
1321 {
1322 _pFileTypeAtom->renderToFileStream(fp);
1323
1324 metaDataSize += _pFileTypeAtom->getSize();
1325 }
1326 {
1327 if (!_oDirectRenderEnabled)
1328 {
1329 populateUserDataAtom();
1330 }
1331 }
1332 if (!_fileAuthoringFlags)
1333 {
1334 if (_oUserDataUpFront)
1335 {
1336 {
1337 if (!_puserDataAtom->renderToFileStream(fp))
1338 {
1339 return false;
1340 }
1341 metaDataSize += _puserDataAtom->getSize();
1342 }
1343 }
1344 }
1345 if ((_oDirectRenderEnabled) || (_totalTempFileRemoval))
1346 {
1347 PVA_FF_AtomUtils::seekFromStart(fp, _directRenderFileOffset);
1348 }
1349
1350 _oFileRenderCalled = true;
1351
1352 uint32 chunkFileOffset = 0;
1353
1354 int32 i;
1355 uint32 size = _pmediaDataAtomVec->size();
1356
1357 _pmovieAtom->prepareToRender();
1358
1359 if (_oMovieAtomUpfront)
1360 {
1361 metaDataSize += _pmovieAtom->getSize();
1362
1363 chunkFileOffset = DEFAULT_ATOM_SIZE + metaDataSize;
1364
1365 // Update all chunk offsets
1366 for (i = size - 1; i >= 0; i--)
1367 {
1368 PVA_FF_MediaDataAtom *mdat = (*_pmediaDataAtomVec)[i];
1369
1370 if (!(mdat->IsTargetRender()))
1371 {
1372 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec =
1373 (*_pmediaDataAtomVec)[i]->getTrackReferencePtrVec();
1374
1375 if (trefVec != NULL)
1376 {
1377 for (uint32 trefVecIndex = 0;
1378 trefVecIndex < trefVec->size();
1379 trefVecIndex++)
1380 {
1381 (*trefVec)[trefVecIndex]->updateAtomFileOffsets(chunkFileOffset);
1382 }
1383 }
1384 chunkFileOffset += mdat->getMediaDataSize();
1385 }
1386 else
1387 {
1388 // not supported - no direct render with media interleaving
1389 return false;
1390 }
1391 }
1392
1393 // Render the movie atom to the file stream
1394 if (!_pmovieAtom->renderToFileStream(fp))
1395 {
1396 return false;
1397 }
1398 }
1399
1400
1401 // Render all mediaData atoms to the file stream
1402 for (i = size - 1; i >= 0; i--)
1403 {
1404 bool oRenderMdat = true;
1405 if (oRenderMdat)
1406 {
1407 if (!((*_pmediaDataAtomVec)[i]->IsTargetRender()))
1408 {
1409 if (!((*_pmediaDataAtomVec)[i]->renderToFileStream(fp)))
1410 {
1411 _fileWriteFailed = true;
1412 return false;
1413 }
1414 if ((*_pmediaDataAtomVec)[i]->_targetFileWriteError == true)
1415 {
1416 _fileWriteFailed = true;
1417 return false;
1418 }
1419
1420 if (!_oMovieAtomUpfront)
1421 {
1422 chunkFileOffset =
1423 (*_pmediaDataAtomVec)[i]->getFileOffsetForChunkStart();
1424 if (chunkFileOffset != 0)
1425 {
1426 // Only true when fp a PVA_FF_MediaDataAtom
1427
1428 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec =
1429 (*_pmediaDataAtomVec)[i]->getTrackReferencePtrVec();
1430
1431
1432 if (trefVec != NULL)
1433 {
1434 for (uint32 trefVecIndex = 0;
1435 trefVecIndex < trefVec->size();
1436 trefVecIndex++)
1437 {
1438 (*trefVec)[trefVecIndex]->updateAtomFileOffsets(chunkFileOffset);
1439 }
1440 }
1441 }
1442 }
1443 }
1444 else
1445 {
1446 if (!_oMovieAtomUpfront)
1447 {
1448 chunkFileOffset =
1449 (*_pmediaDataAtomVec)[i]->getFileOffsetForChunkStart();
1450
1451 if (chunkFileOffset != 0)
1452 {
1453 // Only true when fp a PVA_FF_MediaDataAtom
1454
1455 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec = (*_pmediaDataAtomVec)[i]->getTrackReferencePtrVec();
1456 if (trefVec != NULL)
1457 {
1458 for (uint32 trefVecIndex = 0;
1459 trefVecIndex < trefVec->size();
1460 trefVecIndex++)
1461 {
1462 (*trefVec)[trefVecIndex]->updateAtomFileOffsets(chunkFileOffset);
1463 }
1464 }
1465 }
1466 }
1467 }
1468 }
1469 }
1470 if (!_fileAuthoringFlags)
1471 {
1472 if (!_oUserDataUpFront)
1473 {
1474 {
1475 if (!_puserDataAtom->renderToFileStream(fp))
1476 {
1477 return false;
1478 }
1479 }
1480 }
1481 }
1482 //Important: This needs to be done AFTER the user data has been rendered to file
1483 if (!_oMovieAtomUpfront)
1484 {
1485 // Render the movie atom to the file stream
1486 if (!_pmovieAtom->renderToFileStream(fp))
1487 {
1488 return false;
1489 }
1490 }
1491
1492 _tempFileIndex = 'a';
1493
1494 return true;
1495 }
1496
1497 // Rendering the MP4 file to disk
1498 bool
renderToFile(PVA_FF_UNICODE_STRING_PARAM filename)1499 PVA_FF_Mpeg4File::renderToFile(PVA_FF_UNICODE_STRING_PARAM filename)
1500 {
1501 MP4_AUTHOR_FF_FILE_IO_WRAP fp;
1502 fp._filePtr = NULL;
1503 fp._osclFileServerSession = NULL;
1504 bool status = true;
1505
1506 if (!(_oMovieFragmentEnabled && _oComposeMoofAtom))
1507 {
1508
1509 _modifiable = false; // Only allow addition of samples BEFORE rendering to disk
1510 // After render to disk - cannot add more data
1511
1512
1513 //make sure to flush the interleave buffers, be it to temp files
1514 //or to target files
1515 uint32 k = 0;
1516
1517 for (k = 0; status && k < _pmediaDataAtomVec->size(); k++)
1518 {
1519 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec =
1520 (*_pmediaDataAtomVec)[k]->getTrackReferencePtrVec();
1521
1522 if (trefVec != NULL)
1523 {
1524 for (uint32 trefVecIndex = 0;
1525 status && trefVecIndex < trefVec->size();
1526 trefVecIndex++)
1527 {
1528 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex];
1529 uint32 trackID = pTrack->getTrackID();
1530
1531 if (_oInterLeaveEnabled)
1532 {
1533 if (!flushInterLeaveBuffer(trackID))
1534 {
1535 status = false;
1536 }
1537 }
1538
1539 }
1540 }
1541 }
1542
1543 bool targetRender = false;
1544 _directRenderFileOffset = 0;
1545
1546 if ((_oDirectRenderEnabled) || (_totalTempFileRemoval))
1547 {
1548 for (uint32 k = 0; k < _pmediaDataAtomVec->size(); k++)
1549 {
1550 bool tempVal = ((*_pmediaDataAtomVec)[k]->IsTargetRender());
1551
1552 if (tempVal)
1553 {
1554 if (targetRender)
1555 {
1556 //Only one track is allowed to be rendered directly onto the target
1557 //file
1558 status = false;
1559 }
1560 else
1561 {
1562 targetRender = true;
1563
1564 if (!((*_pmediaDataAtomVec)[k]->closeTargetFile()))
1565 {
1566 status = false;
1567 }
1568
1569 fp._filePtr = ((*_pmediaDataAtomVec)[k]->getTargetFilePtr());
1570 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs);
1571 _directRenderFileOffset =
1572 ((*_pmediaDataAtomVec)[k]->getTotalDataRenderedToTargetFileInDirectRenderMode());
1573 }
1574 }
1575 }
1576 }
1577 else
1578 {
1579 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs);
1580 PVA_FF_AtomUtils::openFile(&fp, filename, Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY);
1581 _oIsFileOpen = true;
1582 }
1583
1584 if (fp._filePtr == NULL)
1585 {
1586 status = false;
1587 }
1588
1589 if (!renderToFileStream(&fp))
1590 {
1591 status = false;
1592 }
1593
1594 if (_oIsFileOpen)
1595 {
1596 PVA_FF_AtomUtils::closeFile(&fp);
1597 _oIsFileOpen = false;
1598 }
1599
1600 if (_fileWriteFailed)
1601 {
1602 status = false;
1603 }
1604 }
1605 else
1606 {
1607 // flush interleave buffers into last TRUN
1608 for (uint32 k = 0; k < _pmediaDataAtomVec->size(); k++)
1609 {
1610 if ((*_pmediaDataAtomVec)[k]->IsTargetRender())
1611 {
1612 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec =
1613 (*_pmediaDataAtomVec)[k]->getTrackReferencePtrVec();
1614
1615 if (trefVec != NULL)
1616 {
1617 for (uint32 trefVecIndex = 0; status && trefVecIndex < trefVec->size(); trefVecIndex++)
1618 {
1619 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex];
1620 uint32 trackID = pTrack->getTrackID();
1621
1622 if (_oInterLeaveEnabled)
1623 {
1624 if (!flushInterLeaveBuffer(trackID))
1625 {
1626 status = false;
1627 }
1628 }
1629 }
1630 }
1631 }
1632 }
1633
1634 fp._filePtr = _targetFileHandle;
1635 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs);
1636
1637 // write movie fragment duration in movie extends atom
1638 _pmovieAtom->writeMovieFragmentDuration(&fp);
1639
1640 if (!renderMovieFragments())
1641 {
1642 status = false;
1643 }
1644
1645 fp._filePtr = _targetFileHandle;
1646 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs);
1647 _pMfraAtom->renderToFileStream(&fp);
1648 _pmovieAtom->writeMaxSampleSize(&fp);
1649 if (_oIsFileOpen)
1650 {
1651 PVA_FF_AtomUtils::closeFile(&fp);
1652 _oIsFileOpen = false;
1653 }
1654 }
1655
1656 return status;
1657 }
1658
1659
1660 // Access function to set the postfix string for PVA_FF_MediaDataAtom objects
1661 // Set the post fix string for the temporary file in order to support multiple instances,
1662 // the goal fp to create temporary files with different names
1663 void
SetTempFilePostFix(PVA_FF_UNICODE_STRING_PARAM postFix)1664 PVA_FF_Mpeg4File::SetTempFilePostFix(PVA_FF_UNICODE_STRING_PARAM postFix)
1665 {
1666 _tempFilePostfix = (_STRLIT(""));
1667 _tempFilePostfix += postFix;
1668 }
1669
1670 // Access function to set the output path string for PVA_FF_MediaDataAtom objects
1671 // Set the output path string for the temporary files in order to generate them at the same location
1672 // as the final mp4 file.
1673 void
SetTempOutputPath(PVA_FF_UNICODE_STRING_PARAM outputPath)1674 PVA_FF_Mpeg4File::SetTempOutputPath(PVA_FF_UNICODE_STRING_PARAM outputPath)
1675 {
1676 _tempOutputPath = (_STRLIT(""));
1677 _tempOutputPath += outputPath;
1678 }
1679
1680 PVA_FF_MediaDataAtom*
getMediaDataAtomForTrack(uint32 trackID)1681 PVA_FF_Mpeg4File::getMediaDataAtomForTrack(uint32 trackID)
1682 {
1683 if (_oInterLeaveEnabled)
1684 {
1685 if (_pmediaDataAtomVec != NULL)
1686 {
1687 if (_pmediaDataAtomVec->size() > MIN_NUM_MEDIA_TRACKS)
1688 {
1689 int32 index = MIN_NUM_MEDIA_TRACKS;
1690 return (*_pmediaDataAtomVec)[index];
1691 }
1692 }
1693 }
1694 else
1695 {
1696 for (uint32 k = 0; k < _pmediaDataAtomVec->size(); k++)
1697 {
1698 PVA_FF_TrackAtom *pTrack = (PVA_FF_TrackAtom *)((*_pmediaDataAtomVec)[k]->getTrackReferencePtr());
1699 uint32 tID = pTrack->getTrackID();
1700
1701 if (tID == trackID)
1702 {
1703 return (*_pmediaDataAtomVec)[k];
1704 }
1705 }
1706 }
1707 return (NULL);
1708 }
1709
1710 bool
addMultipleAccessUnitsToTrack(uint32 trackID,GAU * pgau)1711 PVA_FF_Mpeg4File::addMultipleAccessUnitsToTrack(uint32 trackID, GAU *pgau)
1712 {
1713 PVA_FF_TrackAtom *mediaTrack;
1714 uint32 mediaType;
1715 bool retVal = true;
1716
1717 mediaTrack = _pmovieAtom->getMediaTrack(trackID);
1718
1719 if (mediaTrack == NULL)
1720 {
1721 return false;
1722 }
1723
1724 mediaType = mediaTrack->getMediaType();
1725
1726 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID);
1727
1728 if (mdatAtom == NULL)
1729 {
1730 return false;
1731 }
1732
1733 if (mediaType == MEDIA_TYPE_AUDIO)
1734 {
1735 if (_modifiable)
1736 {
1737 if ((mediaTrack->getCodecType() == CODEC_TYPE_AMR_AUDIO) ||
1738 (mediaTrack->getCodecType() == CODEC_TYPE_AMR_WB_AUDIO))
1739 {
1740 int32 index = 0;
1741
1742 uint8 *frag_ptr = (uint8 *)pgau->buf.fragments[index].ptr;
1743 int32 frag_len = pgau->buf.fragments[index].len;
1744
1745 for (uint32 k = 0; k < pgau->numMediaSamples; k++)
1746 {
1747 uint8 frame_type = (uint8)pgau->info[k].sample_info;
1748
1749 frame_type = (uint8)(frame_type << 3);
1750 frame_type |= 0x04;
1751
1752 // Add to mdat PVA_FF_Atom for the specified track
1753 if (!mdatAtom->addRawSample(&frame_type, 1))
1754 {
1755 retVal = false;
1756 }
1757
1758 int32 frame_size = pgau->info[k].len;
1759
1760 while (frame_size)
1761 {
1762 if (frag_len >= frame_size)
1763 {
1764 // Add to mdat PVA_FF_Atom for the specified track
1765 if (!mdatAtom->addRawSample(frag_ptr,
1766 frame_size))
1767 {
1768 retVal = false;
1769 }
1770
1771 frag_ptr += frame_size;
1772 frag_len -= frame_size;
1773 frame_size = 0;
1774 }
1775 else
1776 {
1777 // Add to mdat PVA_FF_Atom for the specified track
1778 if (!mdatAtom->addRawSample(frag_ptr,
1779 frag_len))
1780 {
1781 retVal = false;
1782 }
1783
1784 frame_size -= frag_len;
1785
1786 index++;
1787
1788 if (index == pgau->buf.num_fragments)
1789 {
1790 return false;
1791 }
1792
1793 frag_ptr = (uint8 *)pgau->buf.fragments[index].ptr;
1794 frag_len = pgau->buf.fragments[index].len;
1795 }
1796 }
1797 // Add to moov atom (in turn adds to tracks)
1798 _pmovieAtom->addSampleToTrack(trackID, NULL,
1799 (pgau->info[k].len + 1),
1800 pgau->info[k].ts,
1801 (uint8)pgau->info[k].sample_info);
1802 }
1803 }
1804 else
1805 {
1806 for (int32 k = 0; k < pgau->buf.num_fragments; k++)
1807 {
1808 // Add to mdat PVA_FF_Atom for the specified track
1809 if (!mdatAtom->addRawSample(pgau->buf.fragments[k].ptr,
1810 pgau->buf.fragments[k].len))
1811 {
1812 retVal = false;
1813 }
1814 }
1815
1816 for (uint32 j = 0; j < pgau->numMediaSamples; j++)
1817 {
1818 // Add to moov atom (in turn adds to tracks)
1819 _pmovieAtom->addSampleToTrack(trackID, NULL,
1820 pgau->info[j].len,
1821 pgau->info[j].ts,
1822 (uint8)pgau->info[j].sample_info);
1823 }
1824 }
1825 }
1826 }
1827 else if (mediaType == MEDIA_TYPE_VISUAL)
1828 {
1829 if (_modifiable)
1830 {
1831 for (int32 k = 0; k < pgau->buf.num_fragments; k++)
1832 {
1833 // Add to mdat PVA_FF_Atom for the specified track
1834 if (!mdatAtom->addRawSample(pgau->buf.fragments[k].ptr,
1835 pgau->buf.fragments[k].len))
1836 {
1837 retVal = false;
1838 }
1839 }
1840
1841 for (uint32 j = 0; j < pgau->numMediaSamples; j++)
1842 {
1843 // Add to moov atom (in turn adds to tracks)
1844 _pmovieAtom->addSampleToTrack(trackID, NULL,
1845 pgau->info[j].len,
1846 pgau->info[j].ts,
1847 (uint8)pgau->info[j].sample_info);
1848 }
1849 }
1850 }
1851 else
1852 {
1853 return false;
1854 }
1855
1856 return (retVal);
1857 }
1858
1859 bool
renderTruncatedFile(PVA_FF_UNICODE_STRING_PARAM filename)1860 PVA_FF_Mpeg4File::renderTruncatedFile(PVA_FF_UNICODE_STRING_PARAM filename)
1861 {
1862 MP4_AUTHOR_FF_FILE_IO_WRAP fp;
1863
1864 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs);
1865
1866 PVA_FF_AtomUtils::openFile(&fp, filename, Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY);
1867
1868 if (fp._filePtr == NULL)
1869 {
1870 return false;
1871 }
1872 /*
1873 * Setting the major brand in ftyp atom
1874 */
1875
1876 if (_o3GPPTrack)
1877 {
1878 setMajorBrand(BRAND_3GPP4);
1879 setMajorBrandVersion(VERSION_3GPP4);
1880 }
1881 else if (_oMPEGTrack)
1882 {
1883 setMajorBrand(BRAND_MPEG4);
1884 setMajorBrandVersion(VERSION_MPEG4);
1885 }
1886 else if (_oPVMMTrack)
1887 {
1888 setMajorBrand(PVMM_BRAND);
1889 setMajorBrandVersion(PVMM_VERSION);
1890 }
1891
1892 /*
1893 * Add compatible brands
1894 */
1895 if (_o3GPPTrack)
1896 {
1897 addCompatibleBrand(BRAND_3GPP4);
1898 }
1899 if (_oPVMMTrack)
1900 {
1901 addCompatibleBrand(PVMM_BRAND);
1902 }
1903 if (_oMPEGTrack)
1904 {
1905 addCompatibleBrand(BRAND_MPEG4);
1906 }
1907 addCompatibleBrand(BRAND_3GPP5);
1908
1909 if ((_o3GPPTrack == true) || (_oPVMMTrack == true) || (_oMPEGTrack == true))
1910 {
1911 _pFileTypeAtom->renderToFileStream(&fp);
1912 }
1913 {
1914 populateUserDataAtom();
1915 _puserDataAtom->renderToFileStream(&fp);
1916 }
1917 _oFileRenderCalled = true;
1918
1919 PVA_FF_AtomUtils::closeFile(&fp);
1920
1921 return true;
1922 }
1923
1924 uint32
convertCreationTime(PVA_FF_UNICODE_STRING_PARAM creationDate)1925 PVA_FF_Mpeg4File::convertCreationTime(PVA_FF_UNICODE_STRING_PARAM creationDate)
1926 {
1927 uint32 numSecs = 0;
1928
1929 uint32 numDaysInMonth[12] =
1930 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1931
1932 uint32 numDaysInLeapFeb = 29;
1933 uint32 refYear = 1904;
1934
1935 // (365*4 + 1) * 24 * 3600
1936 uint32 numSecsInABlkofFourYears = 126230400;
1937
1938 OSCL_TCHAR *date_ptr = (OSCL_TCHAR *)(creationDate.get_cstr());
1939
1940 uint32 index = 0;
1941 uint32 currYear = 0;
1942 uint32 month = 0;
1943 uint32 day = 0;
1944 uint32 hour = 0;
1945 uint32 minutes = 0;
1946 uint32 seconds = 0;
1947
1948 bool nextChar = (date_ptr[index] == 0) ? false : true;
1949
1950 char *c = (char *)(oscl_malloc(5 * sizeof(char)));
1951
1952 uint8 s = 0;
1953 oscl_memset(c, 0, 5);
1954
1955 while (nextChar && (index < 4))
1956 {
1957 c[s++] = (char)(date_ptr[index]);
1958
1959 index++;
1960
1961 nextChar = (date_ptr[index] == 0) ? false : true;
1962 }
1963
1964 PV_atoi(c, 'd', currYear);
1965
1966 if (currYear < refYear)
1967 {
1968 oscl_free(c);
1969 return 0;
1970 }
1971
1972 if (index != 4)
1973 {
1974 oscl_free(c);
1975 return 0;
1976 }
1977
1978 s = 0;
1979 oscl_memset(c, 0, 5);
1980
1981 while (nextChar && (index < 6))
1982 {
1983 c[s++] = (char)(date_ptr[index]);
1984
1985 index++;
1986
1987 nextChar = (date_ptr[index] == 0) ? false : true;
1988 }
1989
1990 PV_atoi(c, 'd', month);
1991
1992 if (index != 6)
1993 {
1994 oscl_free(c);
1995 return 0;
1996 }
1997
1998 s = 0;
1999 oscl_memset(c, 0, 5);
2000
2001 while (nextChar && (index < 8))
2002 {
2003 c[s++] = (char)(date_ptr[index]);
2004
2005 index++;
2006
2007 nextChar = (date_ptr[index] == 0) ? false : true;
2008 }
2009
2010 PV_atoi(c, 'd', day);
2011
2012 if (index != 8)
2013 {
2014 oscl_free(c);
2015 return 0;
2016 }
2017
2018 char val = (char)(date_ptr[index]);
2019
2020 if (val != 'T')
2021 {
2022 oscl_free(c);
2023 return 0;
2024 }
2025 else
2026 {
2027 index++;
2028 }
2029
2030 s = 0;
2031 oscl_memset(c, 0, 5);
2032
2033 while (nextChar && (index < 11))
2034 {
2035 c[s++] = (char)(date_ptr[index]);
2036
2037 index++;
2038
2039 nextChar = (date_ptr[index] == 0) ? false : true;
2040 }
2041
2042 PV_atoi(c, 'd', hour);
2043
2044 if (index != 11)
2045 {
2046 oscl_free(c);
2047 return 0;
2048 }
2049
2050 s = 0;
2051 oscl_memset(c, 0, 5);
2052
2053 while (nextChar && (index < 13))
2054 {
2055 c[s++] = (char)(date_ptr[index]);
2056
2057 index++;
2058
2059 nextChar = (date_ptr[index] == 0) ? false : true;
2060 }
2061
2062 PV_atoi(c, 'd', minutes);
2063
2064 if (index != 13)
2065 {
2066 oscl_free(c);
2067 return 0;
2068 }
2069
2070 s = 0;
2071 oscl_memset(c, 0, 5);
2072
2073 while (nextChar && (index < 15))
2074 {
2075 c[s++] = (char)(date_ptr[index]);
2076
2077 index++;
2078
2079 nextChar = (date_ptr[index] == 0) ? false : true;
2080 }
2081
2082 PV_atoi(c, 'd', seconds);
2083
2084 uint32 deltaYears = currYear - refYear;
2085
2086 uint32 numBlks = (deltaYears / 4);
2087
2088 uint32 numLeftOverYears = (deltaYears - (numBlks * 4));
2089
2090 numSecs = (numBlks * numSecsInABlkofFourYears);
2091
2092 uint32 numDays = 0;
2093
2094 if (numLeftOverYears > 1)
2095 {
2096 // Acct for leap year
2097 numDays = ((numLeftOverYears * 365) + 1);
2098
2099 for (uint32 i = 0; i < month; i++)
2100 {
2101 numDays += numDaysInMonth[i];
2102 }
2103
2104 numDays += day;
2105
2106 uint32 numHours = (numDays * 24);
2107
2108 numHours += hour;
2109
2110 uint32 numMins = (numHours * 60);
2111
2112 numMins += minutes;
2113
2114 numSecs += ((numMins * 60) + seconds);
2115 }
2116 else
2117 {
2118 for (uint32 i = 0; i < month; i++)
2119 {
2120 if (i != 1)
2121 numDays += numDaysInMonth[i];
2122 else
2123 numDays += numDaysInLeapFeb;
2124 }
2125
2126 numDays += day;
2127
2128 uint32 numHours = (numDays * 24);
2129
2130 numHours += hour;
2131
2132 uint32 numMins = (numHours * 60);
2133
2134 numMins += minutes;
2135
2136 numSecs += ((numMins * 60) + seconds);
2137 }
2138
2139 oscl_free(c);
2140
2141 return (numSecs);
2142 }
2143
2144 bool
checkInterLeaveDuration(uint32 trackID,uint32 ts)2145 PVA_FF_Mpeg4File::checkInterLeaveDuration(uint32 trackID, uint32 ts)
2146 {
2147 // get the interleave buffer for the track
2148 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID);
2149
2150 PVA_FF_TrackAtom* mediaTrack = _pmovieAtom->getMediaTrack(trackID);
2151
2152 uint32 lastChunkEndTime = pInterLeaveBuffer->getLastChunkEndTime();
2153
2154 uint32 timescale = mediaTrack->getMediaTimeScale();
2155
2156 uint32 interLeaveDurationInTrackTimeScale =
2157 (uint32)((_interLeaveDuration) * (timescale / 1000.0f));
2158
2159 if ((ts - lastChunkEndTime) >= interLeaveDurationInTrackTimeScale)
2160 {
2161 pInterLeaveBuffer->setLastChunkEndTime(ts);
2162 return true;
2163 }
2164
2165 return false;
2166 }
2167
2168 bool
flushInterLeaveBuffer(uint32 trackID)2169 PVA_FF_Mpeg4File::flushInterLeaveBuffer(uint32 trackID)
2170 {
2171 uint32 mediaType;
2172 int32 codecType;
2173
2174
2175 PVA_FF_TrackAtom* mediaTrack = _pmovieAtom->getMediaTrack(trackID);
2176 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID);
2177 if ((NULL == mediaTrack) || (NULL == pInterLeaveBuffer))
2178 {
2179 // Returning true here might sound strange, however this is a valid case
2180 // where by tracks like odsm or sdsm might not have a valid mediaTrack
2181 // However if false is returned here, the function renderToFile will
2182 // break the for loops and return back.
2183 return true;
2184 }
2185 if (!(_oMovieFragmentEnabled && _oComposeMoofAtom))
2186 {
2187 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID);
2188
2189 mediaType = mediaTrack->getMediaType();
2190 codecType = _pmovieAtom->getCodecType(trackID);
2191
2192 _oChunkStart = true;
2193
2194 Oscl_Vector<uint32, OsclMemAllocator> *tsVec = pInterLeaveBuffer->getTimeStampVec();
2195
2196 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec = pInterLeaveBuffer->getSampleSizeVec();
2197
2198 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec = pInterLeaveBuffer->getFlagsVec();
2199
2200 Oscl_Vector<int32, OsclMemAllocator> *indexVec = NULL;
2201
2202 if (mediaType == MEDIA_TYPE_TEXT && codecType == CODEC_TYPE_TIMED_TEXT)
2203 {
2204 indexVec = pInterLeaveBuffer->getTextIndexVec();
2205 }
2206
2207 int32 numBufferedSamples = tsVec->size();
2208
2209 if (numBufferedSamples > 0)
2210 {
2211 for (int32 i = 0; i < numBufferedSamples; i++)
2212 {
2213 if (mediaType == MEDIA_TYPE_TEXT && codecType == CODEC_TYPE_TIMED_TEXT)
2214 {
2215 uint32 sampleTS = (*tsVec)[i];
2216 uint32 sampleSize = (*sizeVec)[i];
2217 uint8 sampleFlag = (*flagsVec)[i];
2218 int32 sampleIndex = (*indexVec)[i];
2219
2220 // Add to moov atom (in turn adds to tracks)
2221 _pmovieAtom->addTextSampleToTrack(trackID,
2222 NULL,
2223 sampleSize,
2224 sampleTS,
2225 sampleFlag,
2226 sampleIndex,
2227 _baseOffset,
2228 _oChunkStart);
2229
2230 }
2231 else
2232 {
2233 uint32 sampleTS = (*tsVec)[i];
2234 uint32 sampleSize = (*sizeVec)[i];
2235 uint8 sampleFlag = (*flagsVec)[i];
2236
2237 // Add to moov atom (in turn adds to tracks)
2238 _pmovieAtom->addSampleToTrack(trackID,
2239 NULL,
2240 sampleSize,
2241 sampleTS,
2242 sampleFlag,
2243 _baseOffset,
2244 _oChunkStart);
2245 }
2246
2247
2248 _oChunkStart = false;
2249 }
2250
2251 //Render chunk
2252 uint32 chunkSize = 0;
2253 uint8* ptr = pInterLeaveBuffer->resetInterLeaveBuffer(chunkSize);
2254
2255 if (!mdatAtom->addRawSample(ptr, chunkSize))
2256 {
2257 return false;
2258 }
2259 _baseOffset += chunkSize;
2260 }
2261 }
2262 else
2263 {
2264 // add remaining samples as last TRUN in current track fragment
2265 PVA_FF_TrackFragmentAtom *pCurrentTrackFragment;
2266 pCurrentTrackFragment = _pCurrentMoofAtom->getTrackFragment(trackID);
2267
2268 // Set trun end time to the last sample TS
2269 // in the interleave buffer
2270
2271 _oTrunStart = true;
2272
2273 Oscl_Vector<uint32, OsclMemAllocator> *tsVec = pInterLeaveBuffer->getTimeStampVec();
2274
2275 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec = pInterLeaveBuffer->getSampleSizeVec();
2276
2277 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec = pInterLeaveBuffer->getFlagsVec();
2278
2279 int32 numBufferedSamples = tsVec->size();
2280
2281 int32 ii = 0;
2282
2283 for (ii = 0; ii < numBufferedSamples; ii++)
2284 {
2285 uint32 sampleTS = (*tsVec)[ii];
2286 uint32 sampleSize = (*sizeVec)[ii];
2287 uint8 sampleFlag = (*flagsVec)[ii];
2288 uint32 mediaType = mediaTrack->getMediaType();
2289
2290 // Add to moof atom (in turn adds to tracks)
2291 _pCurrentMoofAtom->addSampleToFragment(trackID, sampleSize, sampleTS,
2292 sampleFlag,
2293 _baseOffset, // update data offset for each new trun
2294 _oTrunStart); // determine to add new trun or not
2295
2296 // update movie duration in MVEX atom
2297 _pmovieAtom->updateMovieFragmentDuration(trackID, sampleTS);
2298
2299 if (mediaType == MEDIA_TYPE_VISUAL)
2300 {
2301 // make entry for every sync sample
2302 uint8 codingType = (uint8)((sampleFlag >> 2) & 0x03);
2303 if (codingType == CODING_TYPE_I)
2304 {
2305 // add video key frame as random sample entry
2306 _pMfraAtom->addSampleEntry(trackID, sampleTS, _currentMoofOffset,
2307 _pCurrentMoofAtom->getTrackFragmentNumber(trackID),
2308 pCurrentTrackFragment->getTrunNumber(),
2309 (ii + 1));
2310 }
2311 }
2312 else if (mediaType == MEDIA_TYPE_AUDIO && _oTrunStart == true)
2313 {
2314 // add first audio sample in each TRUN as random sample entry
2315 _pMfraAtom->addSampleEntry(trackID, sampleTS, _currentMoofOffset,
2316 _pCurrentMoofAtom->getTrackFragmentNumber(trackID),
2317 pCurrentTrackFragment->getTrunNumber(),
2318 (ii + 1));
2319
2320 }
2321
2322 _oTrunStart = false;
2323 }
2324
2325 // update the last TS entry only if there is 1 sample in buffer
2326
2327 if (numBufferedSamples == 1)
2328 {
2329 uint32 lastSampleTS = pInterLeaveBuffer->getLastSampleTS();
2330 uint32 ts = pInterLeaveBuffer->getLastChunkEndTime();
2331 pCurrentTrackFragment->updateLastTSEntry(ts + (ts - lastSampleTS));
2332 _pmovieAtom->updateMovieFragmentDuration(trackID, ts + (ts - lastSampleTS));
2333 }
2334 // make entry for last sample same as duration of second to last sample
2335 else
2336 {
2337 if (tsVec->size() > 1)
2338 {
2339 uint32 delta = (*tsVec)[ii -1] - (*tsVec)[ii -2];
2340 uint32 ts = (*tsVec)[ii -1];
2341 pCurrentTrackFragment->updateLastTSEntry(ts + delta);
2342 _pmovieAtom->updateMovieFragmentDuration(trackID, ts + delta);
2343 }
2344 }
2345
2346
2347 if (numBufferedSamples > 0)
2348 {
2349 //Render chunk
2350 uint32 trunSize = 0;
2351 uint8* ptr = pInterLeaveBuffer->resetInterLeaveBuffer(trunSize);
2352
2353 if (!_pCurrentMediaDataAtom->addRawSample(ptr, trunSize))
2354 {
2355 return false;
2356 }
2357 _baseOffset += trunSize;
2358 }
2359 }
2360
2361 return true;
2362 }
2363
2364 bool
getTargetFileSize(uint32 & metaDataSize,uint32 & mediaDataSize)2365 PVA_FF_Mpeg4File::getTargetFileSize(uint32 &metaDataSize, uint32 &mediaDataSize)
2366 {
2367 metaDataSize = 0;
2368 mediaDataSize = 0;
2369
2370 for (uint32 k = 0; k < _pmediaDataAtomVec->size(); k++)
2371 {
2372 mediaDataSize += (*_pmediaDataAtomVec)[k]->getMediaDataSize();
2373
2374 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec =
2375 (*_pmediaDataAtomVec)[k]->getTrackReferencePtrVec();
2376
2377 if (trefVec != NULL)
2378 {
2379 for (uint32 trefVecIndex = 0;
2380 trefVecIndex < trefVec->size();
2381 trefVecIndex++)
2382 {
2383 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex];
2384
2385 /*
2386 * Account for media data that is remaining in the interleave
2387 * buffers
2388 */
2389 if (_oInterLeaveEnabled)
2390 {
2391 uint32 trackID = pTrack->getTrackID();
2392 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID);
2393 if (pInterLeaveBuffer)
2394 {
2395 uint32 currInterLeaveBufferSize = pInterLeaveBuffer->getCurrentInterLeaveBufferSize();
2396
2397 mediaDataSize += currInterLeaveBufferSize;
2398 }
2399 }
2400 }
2401 }
2402 }
2403
2404
2405 if (_pFileTypeAtom != NULL)
2406 {
2407 metaDataSize += _pFileTypeAtom->getSize();
2408 }
2409
2410 if (_pmovieAtom != NULL)
2411 {
2412 metaDataSize += _pmovieAtom->getSize();
2413 }
2414
2415 metaDataSize += 1024; //Gaurd Band
2416
2417 return true;
2418 }
2419
2420 bool
prepareToEncode()2421 PVA_FF_Mpeg4File::prepareToEncode()
2422 {
2423 if (_oInterLeaveEnabled)
2424 {
2425 if (!_totalTempFileRemoval)
2426 {
2427 return true;
2428 }
2429 }
2430
2431 /*
2432 * Setting the major brand in ftyp atom
2433 */
2434 if (_o3GPPTrack)
2435 {
2436 if (_oMovieFragmentEnabled)
2437 {
2438 setMajorBrand(BRAND_3GPP6);
2439 setMajorBrandVersion(VERSION_3GPP6);
2440 }
2441 else
2442 {
2443 setMajorBrand(BRAND_3GPP4);
2444 setMajorBrandVersion(VERSION_3GPP4);
2445 }
2446 }
2447 else if (_oMPEGTrack)
2448 {
2449 setMajorBrand(BRAND_MPEG4);
2450 setMajorBrandVersion(VERSION_MPEG4);
2451 }
2452 else if (_oPVMMTrack)
2453 {
2454 setMajorBrand(PVMM_BRAND);
2455 setMajorBrandVersion(PVMM_VERSION);
2456 }
2457
2458 /*
2459 * Add compatible brands
2460 */
2461 if (_o3GPPTrack)
2462 {
2463 if (_oMovieFragmentEnabled)
2464 addCompatibleBrand(BRAND_3GPP6);
2465 else
2466 addCompatibleBrand(BRAND_3GPP4);
2467 }
2468 if (_oPVMMTrack)
2469 {
2470 addCompatibleBrand(PVMM_BRAND);
2471 }
2472 if (_oMPEGTrack)
2473 {
2474 addCompatibleBrand(BRAND_MPEG4);
2475 }
2476
2477 if (!_oMovieFragmentEnabled)
2478 {
2479 addCompatibleBrand(BRAND_3GPP6);
2480 }
2481
2482 _initialUserDataSize += _pFileTypeAtom->getSize();
2483
2484 _oFtypPopulated = true;
2485
2486 if (_oDirectRenderEnabled)
2487 {
2488 if ((_oSetTitleDone == false) ||
2489 (_oSetAuthorDone == false) ||
2490 (_oSetCopyrightDone == false) ||
2491 (_oSetDescriptionDone == false) ||
2492 (_oSetRatingDone == false) ||
2493 (_pmediaDataAtomVec->size() == 0))
2494 {
2495 // Requirements for this API not met
2496 return false;
2497 }
2498
2499 /*
2500 * If VOL Header had not been set, use the pre defined
2501 * value.
2502 */
2503 for (uint32 j = 0; j < _pmediaDataAtomVec->size(); j++)
2504 {
2505 PVA_FF_TrackAtom *pTrack =
2506 (PVA_FF_TrackAtom *)((*_pmediaDataAtomVec)[j]->getTrackReferencePtr());
2507
2508 uint32 codecType = pTrack->getCodecType();
2509 // uint32 trackID = pTrack->getTrackID();
2510 uint32 mediaType = pTrack->getMediaType();
2511
2512 if (mediaType == MEDIA_TYPE_VISUAL)
2513 {
2514 if (codecType == CODEC_TYPE_MPEG4_VIDEO)
2515 {
2516 if (!pTrack->IsDecoderSpecificInfoSet())
2517 {
2518 _initialUserDataSize +=
2519 MAX_PV_BASE_SIMPLE_PROFILE_VOL_HEADER_SIZE;
2520 }
2521 }
2522 }
2523 }
2524 {
2525 populateUserDataAtom();
2526 _initialUserDataSize += _puserDataAtom->getSize();
2527 }
2528 }
2529
2530 bool targetRender = false;
2531
2532 for (uint32 j = 0; j < _pmediaDataAtomVec->size(); j++)
2533 {
2534 bool tempVal = ((*_pmediaDataAtomVec)[j]->IsTargetRender());
2535
2536 if (tempVal)
2537 {
2538 if (targetRender)
2539 {
2540 //Only one track is allowed to be rendered directly onto the target
2541 //file
2542 return false;
2543 }
2544 else
2545 {
2546 targetRender = true;
2547 ((*_pmediaDataAtomVec)[j]->prepareTargetFile(_initialUserDataSize));
2548 }
2549 }
2550 }
2551
2552 return true;
2553 }
2554
2555 void
populateUserDataAtom()2556 PVA_FF_Mpeg4File::populateUserDataAtom()
2557 {
2558 _oUserDataPopulated = true;
2559 }
2560
2561 bool
addMediaSampleInterleave(uint32 trackID,Oscl_Vector<OsclMemoryFragment,OsclMemAllocator> & fragmentList,uint32 size,uint32 ts,uint8 flags)2562 PVA_FF_Mpeg4File::addMediaSampleInterleave(uint32 trackID,
2563 Oscl_Vector < OsclMemoryFragment,
2564 OsclMemAllocator > & fragmentList,
2565 uint32 size, uint32 ts, uint8 flags)
2566 {
2567 PVA_FF_TrackAtom *mediaTrack = _pmovieAtom->getMediaTrack(trackID);
2568 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID);
2569 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID);
2570 int32 codecType = _pmovieAtom->getCodecType(trackID);
2571 uint32 mediaType = mediaTrack->getMediaType();
2572 int32 index = 0;
2573 if (true == _oComposeMoofAtom)
2574 _pmovieAtom->SetMaxSampleSize(trackID, size);
2575 if (_oFirstSampleEditMode)
2576 {
2577 _oChunkStart = true;
2578 /*
2579 * In this mode very first sample in each track is authored
2580 * in a separate chunk. It is easier to go back and edit the
2581 * sample meta data if we authored it in a seperate chunk by
2582 * itself.
2583 */
2584 if (mediaTrack->IsFirstSample())
2585 {
2586 // Add to moov atom (in turn adds to tracks)
2587 _pmovieAtom->addSampleToTrack(trackID,
2588 fragmentList,
2589 size,
2590 ts,
2591 flags,
2592 _baseOffset,
2593 _oChunkStart);
2594 _oChunkStart = false;
2595
2596 if (!mdatAtom->addRawSample(fragmentList, size, mediaType, codecType))
2597 {
2598 return false;
2599 }
2600 _baseOffset += size;
2601 return true;
2602 }
2603 }
2604
2605 /* Movie Fragment : check if fragment duration reached for MOOV atom. If yes, allocate new
2606 movie fragment (MOOF) and write data in new media data atom.
2607 */
2608 if (_oMovieFragmentEnabled == true && _oComposeMoofAtom == false)
2609 {
2610 uint32 duration = _pmovieAtom->getDuration();
2611 uint32 duration_msec = (uint)((((float)duration / _pmovieAtom->getTimeScale()) * 1000.0f));
2612
2613 if (duration_msec >= _movieFragmentDuration)
2614 {
2615 // render MOOV and MDAT atoms
2616 renderMoovAtom();
2617
2618 _oComposeMoofAtom = true;
2619
2620 // allocate Moof movie fragments
2621 PVA_FF_MovieFragmentAtom *pMoofAtom;
2622 _sequenceNumber++;
2623 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MovieFragmentAtom, (_sequenceNumber,
2624 _movieFragmentDuration,
2625 _interLeaveDuration),
2626 pMoofAtom);
2627
2628 _pCurrentMoofAtom = pMoofAtom;
2629
2630 // set Movie fragment duration
2631 _pmovieAtom->setMovieFragmentDuration();
2632
2633 // add track fragments
2634 for (uint32 kk = 0; kk < _pmediaDataAtomVec->size(); kk++)
2635 {
2636 // add track fragments from MDAT with interleaved data
2637 if ((*_pmediaDataAtomVec)[kk]->IsTargetRender())
2638 {
2639 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec =
2640 (*_pmediaDataAtomVec)[kk]->getTrackReferencePtrVec();
2641
2642 if (trefVec != NULL)
2643 {
2644 for (uint32 trefVecIndex = 0; trefVecIndex < trefVec->size(); trefVecIndex++)
2645 {
2646 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex];
2647
2648 _pCurrentMoofAtom->addTrackFragment(pTrack->getMediaType(),
2649 pTrack->getCodecType(),
2650 pTrack->getTrackID(),
2651 pTrack->getMediaTimeScale());
2652
2653 // add random access atom for each track
2654 _pMfraAtom->addTrackFragmentRandomAccessAtom(pTrack->getTrackID());
2655 }
2656 }
2657 }
2658 }
2659
2660 // form new MDAT atom
2661 PVA_FF_MediaDataAtom *pMdatAtom = NULL;
2662 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_targetFileHandle, _aFs, iCacheSize), pMdatAtom);
2663
2664 _pCurrentMediaDataAtom = pMdatAtom;
2665
2666 // current moof offset set at start of mdat, (later updated by size of mdat atom)
2667 _currentMoofOffset = _baseOffset;
2668
2669 // base offset set to start of mdat (after fourcc code) as base data offset
2670 _baseOffset += _pCurrentMediaDataAtom->prepareTargetFileForFragments(_directRenderFileOffset);
2671
2672 }
2673
2674 }
2675
2676 if (_oMovieFragmentEnabled == false || _oComposeMoofAtom == false)
2677 {
2678
2679 if (!pInterLeaveBuffer->checkInterLeaveBufferSpace(size))
2680 {
2681 // Set Chunk end time to the last sample TS
2682 // in the interleave buffer
2683 pInterLeaveBuffer->setLastChunkEndTime(ts);
2684
2685 _oChunkStart = true;
2686
2687 Oscl_Vector<uint32, OsclMemAllocator> *tsVec =
2688 pInterLeaveBuffer->getTimeStampVec();
2689
2690 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec =
2691 pInterLeaveBuffer->getSampleSizeVec();
2692
2693 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec =
2694 pInterLeaveBuffer->getFlagsVec();
2695
2696 int32 numBufferedSamples = tsVec->size();
2697
2698 for (int32 ii = 0; ii < numBufferedSamples; ii++)
2699 {
2700 uint32 sampleTS = (*tsVec)[ii];
2701 uint32 sampleSize = (*sizeVec)[ii];
2702 uint8 sampleFlag = (*flagsVec)[ii];
2703
2704 // Add to moov atom (in turn adds to tracks)
2705 _pmovieAtom->addSampleToTrack(trackID,
2706 fragmentList,
2707 sampleSize,
2708 sampleTS,
2709 sampleFlag,
2710 _baseOffset,
2711 _oChunkStart);
2712
2713 _oChunkStart = false;
2714 }
2715
2716 if (numBufferedSamples > 0)
2717 {
2718 //Render chunk
2719 uint32 chunkSize = 0;
2720 uint8* ptr = pInterLeaveBuffer->resetInterLeaveBuffer(chunkSize);
2721
2722 if (!mdatAtom->addRawSample(ptr, chunkSize))
2723 {
2724 return false;
2725 }
2726 _baseOffset += chunkSize;
2727 }
2728
2729 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList,
2730 size, ts, flags, index)))
2731 {
2732 return false;
2733 }
2734 }
2735 else
2736 {
2737 if (checkInterLeaveDuration(trackID, ts))
2738 {
2739 _oChunkStart = true;
2740
2741 Oscl_Vector<uint32, OsclMemAllocator> *tsVec =
2742 pInterLeaveBuffer->getTimeStampVec();
2743
2744 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec =
2745 pInterLeaveBuffer->getSampleSizeVec();
2746
2747 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec =
2748 pInterLeaveBuffer->getFlagsVec();
2749
2750 int32 numBufferedSamples = tsVec->size();
2751
2752 for (int32 ii = 0; ii < numBufferedSamples; ii++)
2753 {
2754 uint32 sampleTS = (*tsVec)[ii];
2755 uint32 sampleSize = (*sizeVec)[ii];
2756 uint8 sampleFlag = (*flagsVec)[ii];
2757
2758 // Add to moov atom (in turn adds to tracks)
2759 _pmovieAtom->addSampleToTrack(trackID,
2760 fragmentList,
2761 sampleSize,
2762 sampleTS,
2763 sampleFlag,
2764 _baseOffset,
2765 _oChunkStart);
2766
2767 _oChunkStart = false;
2768 }
2769
2770 if (numBufferedSamples > 0)
2771 {
2772 //Render chunk
2773 uint32 chunkSize = 0;
2774 uint8* ptr = pInterLeaveBuffer->resetInterLeaveBuffer(chunkSize);
2775
2776 if (!mdatAtom->addRawSample(ptr, chunkSize))
2777 {
2778 return false;
2779 }
2780 _baseOffset += chunkSize;
2781 }
2782 }
2783 else
2784 {
2785 _oChunkStart = false;
2786 }
2787
2788 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList,
2789 size, ts, flags, index)))
2790 {
2791 return false;
2792 }
2793 }
2794 }
2795 else
2796 {
2797 // add data in movie fragment
2798 uint32 trackFragmentDuration = _pCurrentMoofAtom->getTrackFragmentDuration(trackID);
2799
2800 // check if Movie Fragment duration is reached for current fragment
2801 if (trackFragmentDuration < _movieFragmentDuration)
2802 {
2803 // add fragment to the current track fragment
2804
2805 //check for interleaving in current track fragment
2806 PVA_FF_TrackFragmentAtom *pCurrentTrackFragment;
2807 pCurrentTrackFragment = _pCurrentMoofAtom->getTrackFragment(trackID);
2808
2809 if (!pInterLeaveBuffer->checkInterLeaveBufferSpace(size))
2810 {
2811 // Set trun end time to the last sample TS
2812 // in the interleave buffer
2813 pInterLeaveBuffer->setLastChunkEndTime(ts);
2814
2815 _oTrunStart = true;
2816
2817 Oscl_Vector<uint32, OsclMemAllocator> *tsVec =
2818 pInterLeaveBuffer->getTimeStampVec();
2819
2820 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec =
2821 pInterLeaveBuffer->getSampleSizeVec();
2822
2823 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec =
2824 pInterLeaveBuffer->getFlagsVec();
2825
2826 int32 numBufferedSamples = tsVec->size();
2827
2828
2829 for (int32 ii = 0; ii < numBufferedSamples; ii++)
2830 {
2831 uint32 sampleTS = (*tsVec)[ii];
2832 uint32 sampleSize = (*sizeVec)[ii];
2833 uint8 sampleFlag = (*flagsVec)[ii];
2834
2835 // Add to moof atom (in turn adds to tracks)
2836 _pCurrentMoofAtom->addSampleToFragment(trackID, sampleSize, sampleTS,
2837 sampleFlag,
2838 _baseOffset, // update data offset for each new trun
2839 _oTrunStart); // determine to add new trun or not
2840
2841 // update movie duration in MVEX atom
2842 _pmovieAtom->updateMovieFragmentDuration(trackID, sampleTS);
2843
2844 if (mediaType == MEDIA_TYPE_VISUAL)
2845 {
2846 // make entry for every sync sample
2847 uint8 codingType = (uint8)((sampleFlag >> 2) & 0x03);
2848 if (codingType == CODING_TYPE_I)
2849 {
2850 // add video key frame as random sample entry
2851 _pMfraAtom->addSampleEntry(trackID, sampleTS, _currentMoofOffset,
2852 _pCurrentMoofAtom->getTrackFragmentNumber(trackID),
2853 pCurrentTrackFragment->getTrunNumber(),
2854 (ii + 1));
2855 }
2856 }
2857 else if (mediaType == MEDIA_TYPE_AUDIO && _oTrunStart == true)
2858 {
2859 // add first audio sample in each TRUN as random sample entry
2860 _pMfraAtom->addSampleEntry(trackID, sampleTS, _currentMoofOffset,
2861 _pCurrentMoofAtom->getTrackFragmentNumber(trackID),
2862 pCurrentTrackFragment->getTrunNumber(),
2863 (ii + 1));
2864
2865 }
2866
2867 _oTrunStart = false;
2868 }
2869
2870 pCurrentTrackFragment->updateLastTSEntry(ts);
2871
2872 if (numBufferedSamples > 0)
2873 {
2874 //Render chunk
2875 uint32 trunSize = 0;
2876 uint8* ptr = pInterLeaveBuffer->resetInterLeaveBuffer(trunSize);
2877
2878 if (!_pCurrentMediaDataAtom->addRawSample(ptr, trunSize))
2879 {
2880 return false;
2881 }
2882 _baseOffset += trunSize;
2883 }
2884
2885 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList, size, ts, flags, index)))
2886 {
2887 return false;
2888 }
2889 }
2890 else
2891 {
2892 if (checkInterLeaveDuration(trackID, ts))
2893 {
2894 _oTrunStart = true;
2895
2896
2897 Oscl_Vector<uint32, OsclMemAllocator> *tsVec =
2898 pInterLeaveBuffer->getTimeStampVec();
2899
2900 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec =
2901 pInterLeaveBuffer->getSampleSizeVec();
2902
2903 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec =
2904 pInterLeaveBuffer->getFlagsVec();
2905
2906 int32 numBufferedSamples = tsVec->size();
2907
2908 for (int32 ii = 0; ii < numBufferedSamples; ii++)
2909 {
2910 uint32 sampleTS = (*tsVec)[ii];
2911 uint32 sampleSize = (*sizeVec)[ii];
2912 uint8 sampleFlag = (*flagsVec)[ii];
2913
2914 // update movie duration in MVEX atom
2915 _pmovieAtom->updateMovieFragmentDuration(trackID, sampleTS);
2916
2917 // Add to moov atom (in turn adds to tracks)
2918 _pCurrentMoofAtom->addSampleToFragment(trackID, sampleSize, sampleTS,
2919 sampleFlag,
2920 _baseOffset,
2921 _oTrunStart);
2922
2923 if (mediaType == MEDIA_TYPE_VISUAL)
2924 {
2925 // make entry for every sync sample
2926 uint8 codingType = (uint8)((sampleFlag >> 2) & 0x03);
2927 if (codingType == CODING_TYPE_I)
2928 {
2929 // add video key frame as random sample entry
2930 _pMfraAtom->addSampleEntry(trackID, sampleTS, _currentMoofOffset,
2931 _pCurrentMoofAtom->getTrackFragmentNumber(trackID),
2932 pCurrentTrackFragment->getTrunNumber(),
2933 (ii + 1));
2934 }
2935 }
2936 else if (mediaType == MEDIA_TYPE_AUDIO && _oTrunStart == true)
2937 {
2938 // add first audio sample in each TRUN as random sample entry
2939 _pMfraAtom->addSampleEntry(trackID, sampleTS, _currentMoofOffset,
2940 _pCurrentMoofAtom->getTrackFragmentNumber(trackID),
2941 pCurrentTrackFragment->getTrunNumber(),
2942 (ii + 1));
2943
2944 }
2945
2946
2947 _oTrunStart = false;
2948 }
2949
2950 pCurrentTrackFragment->updateLastTSEntry(ts);
2951
2952 if (numBufferedSamples > 0)
2953 {
2954 //Render chunk
2955 uint32 trunSize = 0;
2956 uint8* ptr = pInterLeaveBuffer->resetInterLeaveBuffer(trunSize);
2957
2958 if (!_pCurrentMediaDataAtom->addRawSample(ptr, trunSize))
2959 {
2960 return false;
2961 }
2962 _baseOffset += trunSize;
2963 }
2964 }
2965 else
2966 {
2967 _oTrunStart = false;
2968 }
2969
2970 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList, size,
2971 ts, flags, index)))
2972 {
2973 return false;
2974 }
2975 }
2976 }
2977 else
2978 {
2979
2980 // add sample
2981 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList, size,
2982 ts, flags, index)))
2983 {
2984 return false;
2985 }
2986
2987 uint32 kk = 0;
2988
2989 // update last sample TS entry
2990 for (kk = 0; kk < _pmediaDataAtomVec->size(); kk++)
2991 {
2992 if ((*_pmediaDataAtomVec)[kk]->IsTargetRender())
2993 {
2994
2995 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec =
2996 (*_pmediaDataAtomVec)[kk]->getTrackReferencePtrVec();
2997
2998 if (trefVec != NULL)
2999 {
3000 for (uint32 trefVecIndex = 0; trefVecIndex < trefVec->size(); trefVecIndex++)
3001 {
3002 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex];
3003 uint32 trackID = pTrack->getTrackID();
3004
3005 PVA_FF_TrackFragmentAtom *pCurrentTrackFragment;
3006 pCurrentTrackFragment = _pCurrentMoofAtom->getTrackFragment(trackID);
3007
3008 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID);
3009 uint32 ts = pInterLeaveBuffer->getFirstTSEntry();
3010 pCurrentTrackFragment->updateLastTSEntry(ts);
3011 }
3012 }
3013 }
3014 }
3015
3016 // close MDAT atom and render current fragment
3017 if (!renderMovieFragments())
3018 {
3019 _fileWriteFailed = true;
3020 return false;
3021 }
3022
3023 // delete current moof atom
3024 PV_MP4_FF_DELETE(NULL, PVA_FF_MovieFragmentAtom, _pCurrentMoofAtom);
3025
3026 // allocate new fragment
3027 PVA_FF_MovieFragmentAtom *pMoofAtom;
3028 _sequenceNumber++;
3029 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MovieFragmentAtom, (_sequenceNumber,
3030 _movieFragmentDuration,
3031 _interLeaveDuration),
3032 pMoofAtom);
3033 _pCurrentMoofAtom = pMoofAtom;
3034
3035 // add track fragments
3036 for (kk = 0; kk < _pmediaDataAtomVec->size(); kk++)
3037 {
3038 if ((*_pmediaDataAtomVec)[kk]->IsTargetRender())
3039 {
3040 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec =
3041 (*_pmediaDataAtomVec)[kk]->getTrackReferencePtrVec();
3042
3043 if (trefVec != NULL)
3044 {
3045 for (uint32 trefVecIndex = 0; trefVecIndex < trefVec->size(); trefVecIndex++)
3046 {
3047 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex];
3048
3049 _pCurrentMoofAtom->addTrackFragment(pTrack->getMediaType(),
3050 pTrack->getCodecType(),
3051 pTrack->getTrackID(),
3052 pTrack->getMediaTimeScale());
3053
3054 }
3055 }
3056 }
3057 }
3058
3059 // delete current MDAT atom for movie fragment
3060 PV_MP4_FF_DELETE(NULL, PVA_FF_MediaDataAtom, _pCurrentMediaDataAtom);
3061
3062 // form new MDAT atom
3063 PVA_FF_MediaDataAtom *pMdatAtom = NULL;
3064 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_targetFileHandle, _aFs, iCacheSize), pMdatAtom);
3065
3066 _pCurrentMediaDataAtom = pMdatAtom;
3067
3068 // current moof offset set at start of mdat, (later updated by size of mdat atom)
3069 _currentMoofOffset = _baseOffset;
3070
3071 // base offset set to start of mdat (after fourcc code) as base data offset
3072 _baseOffset += _pCurrentMediaDataAtom->prepareTargetFileForFragments(_directRenderFileOffset);
3073
3074 }
3075
3076 }
3077 return true;
3078
3079 }
3080
3081 bool
addTextMediaSampleInterleave(uint32 trackID,Oscl_Vector<OsclMemoryFragment,OsclMemAllocator> & fragmentList,uint32 size,uint32 ts,uint8 flags,int32 index)3082 PVA_FF_Mpeg4File::addTextMediaSampleInterleave(uint32 trackID,
3083 Oscl_Vector <OsclMemoryFragment, OsclMemAllocator>& fragmentList,
3084 uint32 size, uint32 ts, uint8 flags, int32 index)
3085 {
3086 PVA_FF_TrackAtom *mediaTrack = _pmovieAtom->getMediaTrack(trackID);
3087 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID);
3088 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID);
3089 int32 codecType = _pmovieAtom->getCodecType(trackID);
3090 uint32 mediaType = mediaTrack->getMediaType();
3091
3092 if (_oFirstSampleEditMode)
3093 {
3094 _oChunkStart = true;
3095 /*
3096 * In this mode very first sample in each track is authored
3097 * in a separate chunk. It is easier to go back and edit the
3098 * sample meta data if we authored it in a seperate chunk by
3099 * itself.
3100 */
3101 if (mediaTrack->IsFirstSample())
3102 {
3103 // Add to moov atom (in turn adds to tracks)
3104 _pmovieAtom->addTextSampleToTrack(trackID,
3105 fragmentList,
3106 size,
3107 ts,
3108 flags,
3109 index,
3110 _baseOffset,
3111 _oChunkStart);
3112 _oChunkStart = false;
3113
3114 if (!mdatAtom->addRawSample(fragmentList, size, mediaType, codecType))
3115 {
3116 return false;
3117 }
3118 _baseOffset += size;
3119 return true;
3120 }
3121 }
3122
3123 if (!pInterLeaveBuffer->checkInterLeaveBufferSpace(size))
3124 {
3125 // Set Chunk end time to the last sample TS
3126 // in the interleave buffer
3127 pInterLeaveBuffer->setLastChunkEndTime();
3128
3129 _oChunkStart = true;
3130
3131 Oscl_Vector<uint32, OsclMemAllocator> *tsVec =
3132 pInterLeaveBuffer->getTimeStampVec();
3133
3134 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec =
3135 pInterLeaveBuffer->getSampleSizeVec();
3136
3137 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec =
3138 pInterLeaveBuffer->getFlagsVec();
3139
3140 Oscl_Vector<int32, OsclMemAllocator> *indexVec =
3141 pInterLeaveBuffer->getTextIndexVec();
3142
3143 int32 numBufferedSamples = tsVec->size();
3144
3145 for (int32 i = 0; i < numBufferedSamples; i++)
3146 {
3147 uint32 sampleTS = (*tsVec)[i];
3148 uint32 sampleSize = (*sizeVec)[i];
3149 uint8 sampleFlag = (*flagsVec)[i];
3150 int32 sampleIndex = (*indexVec)[i];
3151
3152 // Add to moov atom (in turn adds to tracks)
3153 _pmovieAtom->addTextSampleToTrack(trackID,
3154 fragmentList,
3155 sampleSize,
3156 sampleTS,
3157 sampleFlag,
3158 sampleIndex,
3159 _baseOffset,
3160 _oChunkStart);
3161
3162 _oChunkStart = false;
3163 }
3164
3165 if (numBufferedSamples > 0)
3166 {
3167 //Render chunk
3168 uint32 chunkSize = 0;
3169 uint8* ptr =
3170 pInterLeaveBuffer->resetInterLeaveBuffer(chunkSize);
3171
3172 if (!mdatAtom->addRawSample(ptr, chunkSize))
3173 {
3174 return false;
3175 }
3176 _baseOffset += chunkSize;
3177 }
3178
3179 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList,
3180 size, ts, flags, index)))
3181 {
3182 return false;
3183 }
3184 }
3185 else
3186 {
3187 if (checkInterLeaveDuration(trackID, ts))
3188 {
3189 _oChunkStart = true;
3190
3191 Oscl_Vector<uint32, OsclMemAllocator> *tsVec =
3192 pInterLeaveBuffer->getTimeStampVec();
3193
3194 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec =
3195 pInterLeaveBuffer->getSampleSizeVec();
3196
3197 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec =
3198 pInterLeaveBuffer->getFlagsVec();
3199
3200 Oscl_Vector<int32, OsclMemAllocator> *indexVec =
3201 pInterLeaveBuffer->getTextIndexVec();
3202
3203 int32 numBufferedSamples = tsVec->size();
3204
3205 for (int32 i = 0; i < numBufferedSamples; i++)
3206 {
3207 uint32 sampleTS = (*tsVec)[i];
3208 uint32 sampleSize = (*sizeVec)[i];
3209 uint8 sampleFlag = (*flagsVec)[i];
3210 int32 sampleIndex = (*indexVec)[i];
3211
3212 // Add to moov atom (in turn adds to tracks)
3213 _pmovieAtom->addTextSampleToTrack(trackID,
3214 fragmentList,
3215 sampleSize,
3216 sampleTS,
3217 sampleFlag,
3218 sampleIndex,
3219 _baseOffset,
3220 _oChunkStart);
3221
3222
3223
3224 _oChunkStart = false;
3225 }
3226
3227 if (numBufferedSamples > 0)
3228 {
3229 //Render chunk
3230 uint32 chunkSize = 0;
3231 uint8* ptr =
3232 pInterLeaveBuffer->resetInterLeaveBuffer(chunkSize);
3233
3234 if (!mdatAtom->addRawSample(ptr, chunkSize))
3235 {
3236 return false;
3237 }
3238 _baseOffset += chunkSize;
3239 }
3240 }
3241 else
3242 {
3243 _oChunkStart = false;
3244 }
3245
3246 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList, size, ts, flags , index)))
3247 {
3248 return false;
3249 }
3250 }
3251
3252 return true;
3253 }
3254
3255 bool
reAuthorFirstSampleInTrack(uint32 trackID,uint8 * psample,uint32 size)3256 PVA_FF_Mpeg4File::reAuthorFirstSampleInTrack(uint32 trackID,
3257 uint8 *psample,
3258 uint32 size)
3259 {
3260 bool retVal = false;
3261 if (_oInterLeaveEnabled)
3262 {
3263 PVA_FF_TrackAtom *mediaTrack = _pmovieAtom->getMediaTrack(trackID);
3264 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID);
3265
3266 mediaTrack = _pmovieAtom->getMediaTrack(trackID);
3267
3268 // Add to moov atom (in turn adds to tracks)
3269 retVal =
3270 _pmovieAtom->reAuthorFirstSampleInTrack(trackID,
3271 size,
3272 _baseOffset);
3273
3274 if (!mdatAtom->addRawSample(psample, size))
3275 {
3276 retVal = false;
3277 }
3278 else
3279 {
3280 _baseOffset += size;
3281 }
3282 }
3283 return retVal;
3284 }
3285
3286
3287 bool
renderMoovAtom()3288 PVA_FF_Mpeg4File::renderMoovAtom()
3289 {
3290 MP4_AUTHOR_FF_FILE_IO_WRAP fp;
3291 fp._filePtr = NULL;
3292 fp._osclFileServerSession = NULL;
3293
3294 //make sure to flush the interleave buffers, be it to temp files
3295 //or to target files
3296 uint32 kk = 0;
3297
3298 for (kk = 0; kk < _pmediaDataAtomVec->size(); kk++)
3299 {
3300 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec =
3301 (*_pmediaDataAtomVec)[kk]->getTrackReferencePtrVec();
3302
3303 if (trefVec != NULL)
3304 {
3305 for (uint32 trefVecIndex = 0; trefVecIndex < trefVec->size(); trefVecIndex++)
3306 {
3307 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex];
3308 uint32 trackID = pTrack->getTrackID();
3309 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID);
3310 if (pInterLeaveBuffer != NULL)
3311 {
3312 uint32 ts = pInterLeaveBuffer->getFirstTSEntry();
3313 pTrack->updateLastTSEntry(ts);
3314 }
3315 }
3316 }
3317 }
3318
3319 bool targetRender = false;
3320 _directRenderFileOffset = 0;
3321
3322 if ((_oDirectRenderEnabled) || (_totalTempFileRemoval))
3323 {
3324 for (uint32 kk = 0; kk < _pmediaDataAtomVec->size(); kk++)
3325 {
3326 bool tempVal = ((*_pmediaDataAtomVec)[kk]->IsTargetRender());
3327
3328 if (tempVal)
3329 {
3330 if (targetRender)
3331 {
3332 //Only one track is allowed to be rendered directly onto the target
3333 //file
3334 return false;
3335 }
3336 else
3337 {
3338 targetRender = true;
3339
3340 if (!((*_pmediaDataAtomVec)[kk]->closeTargetFile()))
3341 {
3342 return false;
3343 }
3344
3345 fp._filePtr = ((*_pmediaDataAtomVec)[kk]->getTargetFilePtr());
3346 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs);
3347
3348 _directRenderFileOffset =
3349 ((*_pmediaDataAtomVec)[kk]->getTotalDataRenderedToTargetFileInDirectRenderMode());
3350 }
3351 }
3352 }
3353 }
3354
3355 if (fp._filePtr == NULL)
3356 {
3357 return false;
3358 }
3359
3360 if (!renderToFileStream(&fp))
3361 {
3362 return false;
3363 }
3364 _directRenderFileOffset = PVA_FF_AtomUtils::getCurrentFilePosition(&fp); // hereafter movie fragments are written
3365 _baseOffset = _directRenderFileOffset; // base offset is used to set base data offset of Moof
3366
3367
3368 // store target file handle used to write further movie fragments
3369 _targetFileHandle = fp._filePtr;
3370
3371 return true;
3372 }
3373
3374 bool
renderMovieFragments()3375 PVA_FF_Mpeg4File::renderMovieFragments()
3376 {
3377 uint32 size;
3378
3379 uint32 fileWriteOffset;
3380
3381 MP4_AUTHOR_FF_FILE_IO_WRAP fp;
3382
3383 fp._filePtr = _pCurrentMediaDataAtom->getTargetFilePtr();
3384 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs);
3385
3386 fileWriteOffset = PVA_FF_AtomUtils::getCurrentFilePosition(&fp);
3387
3388 _pCurrentMediaDataAtom->closeTargetFile();
3389
3390 size = _pCurrentMediaDataAtom->getMediaDataSize();
3391
3392 _pMfraAtom->updateMoofOffset(size);
3393
3394 PVA_FF_AtomUtils::seekFromStart(&fp, fileWriteOffset);
3395
3396
3397 if (!(_pCurrentMoofAtom->renderToFileStream(&fp)))
3398 {
3399 return false;
3400 }
3401
3402 _directRenderFileOffset = PVA_FF_AtomUtils::getCurrentFilePosition(&fp); // hereafter further movie fragments are written
3403 _baseOffset = _directRenderFileOffset; // base offset is used to set base data offset of Moof
3404
3405 return true;
3406 }
3407
3408
3409 void
addInterLeaveBuffer(PVA_FF_InterLeaveBuffer * pInterLeaveBuffer)3410 PVA_FF_Mpeg4File::addInterLeaveBuffer(PVA_FF_InterLeaveBuffer *pInterLeaveBuffer)
3411 {
3412 if (_oInterLeaveEnabled)
3413 {
3414 if (_modifiable)
3415 {
3416 _pInterLeaveBufferVec->push_back(pInterLeaveBuffer);
3417 }
3418 }
3419 }
3420
3421
3422
3423 PVA_FF_InterLeaveBuffer*
getInterLeaveBuffer(uint32 trackID)3424 PVA_FF_Mpeg4File::getInterLeaveBuffer(uint32 trackID)
3425 {
3426 if (_pInterLeaveBufferVec->size() > 0)
3427 {
3428 for (uint32 ii = 0; ii < _pInterLeaveBufferVec->size(); ii++)
3429 {
3430 if ((*_pInterLeaveBufferVec)[ii]->getTrackID() == trackID)
3431 return (*_pInterLeaveBufferVec)[ii];
3432 }
3433 }
3434 return NULL;
3435 }
3436
3437 void
setAudioEncodeParams(uint32 trackId,PVMP4FFComposerAudioEncodeParams & audioParams)3438 PVA_FF_Mpeg4File::setAudioEncodeParams(uint32 trackId,
3439 PVMP4FFComposerAudioEncodeParams &audioParams)
3440 {
3441 PVA_FF_TrackAtom *trackAtom;
3442 trackAtom = _pmovieAtom->getMediaTrack(trackId);
3443
3444 if (trackAtom != NULL)
3445 trackAtom->setAudioEncodeParams(audioParams);
3446
3447 return;
3448 }
3449
3450
3451
3452
3453