@@ -213,15 +213,7 @@ bool QuickTimeMuxer::writeMoovBox() {
213213 size_t mdatTotalSize = mdatDataSize + 8 ;
214214
215215 // Update mdat size at the beginning
216- if (lseek (m_fd, m_mdatStartPos, SEEK_SET) == -1 ) {
217- LOG (ERROR) << " [QuickTimeMuxer] Failed to seek to mdat position" ;
218- return false ;
219- }
220-
221- uint32_t mdatSizeBE = htonl (static_cast <uint32_t >(mdatTotalSize));
222- ssize_t written = write (m_fd, &mdatSizeBE, 4 );
223- if (written != 4 ) {
224- LOG (ERROR) << " [QuickTimeMuxer] Failed to write mdat size" ;
216+ if (!updateMdatSize (mdatTotalSize)) {
225217 return false ;
226218 }
227219
@@ -243,37 +235,45 @@ bool QuickTimeMuxer::writeMoovBox() {
243235 );
244236
245237 // Update stsz entry_sizes with actual frame sizes from m_frames
246- // Find 'stsz' box and update entries
247- bool stszFound = false ;
248- for (size_t i = 0 ; i + 20 + m_frames.size () * 4 <= moovBox.size (); i++) {
249- if (moovBox[i] == 0x73 && moovBox[i+1 ] == 0x74 &&
250- moovBox[i+2 ] == 0x73 && moovBox[i+3 ] == 0x7A ) {
251- // Found 'stsz', update entries
252- size_t entriesStart = i + 16 ; // After 'stsz' + version/flags + sample_size + sample_count
253-
254- for (size_t j = 0 ; j < m_frames.size (); j++) {
255- size_t entryPos = entriesStart + j * 4 ;
256- if (entryPos + 4 <= moovBox.size ()) {
257- uint32_t frameSize = m_frames[j].size ;
258- moovBox[entryPos] = (frameSize >> 24 ) & 0xFF ;
259- moovBox[entryPos+1 ] = (frameSize >> 16 ) & 0xFF ;
260- moovBox[entryPos+2 ] = (frameSize >> 8 ) & 0xFF ;
261- moovBox[entryPos+3 ] = frameSize & 0xFF ;
262- }
263- }
264-
265- stszFound = true ;
266- LOG (DEBUG) << " [QuickTimeMuxer] Updated stsz with " << m_frames.size () << " frame sizes" ;
267- break ;
268- }
238+ updateFrameSizes (moovBox);
239+
240+ // Fix stss (sync samples) to contain only actual keyframes, not all frames
241+ updateKeyframes (moovBox);
242+
243+ // Fix stco (chunk offset) to point to actual mdat data position
244+ // stco must point to where frames start in the file (after ftyp and mdat header)
245+ uint32_t actualChunkOffset = m_mdatStartPos + 8 ; // mdat header is 8 bytes (size + 'mdat')
246+ updateChunkOffset (moovBox, actualChunkOffset);
247+
248+ // Write moov at the end of file
249+ ssize_t written = write (m_fd, moovBox.data (), moovBox.size ());
250+ if (written != static_cast <ssize_t >(moovBox.size ())) {
251+ LOG (ERROR) << " [QuickTimeMuxer] Failed to write moov box: " << written << " /" << moovBox.size ();
252+ return false ;
269253 }
270254
271- if (!stszFound) {
272- LOG (WARN) << " [QuickTimeMuxer] Could not find stsz box in moov to update frame sizes!" ;
255+ // CRITICAL: Sync data to disk BEFORE truncate
256+ // Otherwise ftruncate may not work correctly with buffered data
257+ fsync (m_fd);
258+
259+ // Truncate file to current position (remove any garbage after moov)
260+ off_t finalSize = moovStart + moovBox.size ();
261+ if (ftruncate (m_fd, finalSize) == -1 ) {
262+ LOG (WARN) << " [QuickTimeMuxer] Failed to truncate file to " << finalSize << " bytes (errno: " << errno << " )" ;
263+ } else {
264+ LOG (DEBUG) << " [QuickTimeMuxer] Truncated file to " << finalSize << " bytes" ;
273265 }
274266
275- // Fix stss (sync samples) to contain only actual keyframes, not all frames
276- // Find 'stss' box and rebuild with only keyframe indices
267+ // Final sync after truncate
268+ fsync (m_fd);
269+
270+ LOG (INFO) << " [QuickTimeMuxer] Wrote moov box (" << moovBox.size () << " bytes) at end, mdat size (" << mdatTotalSize << " bytes), final file size " << finalSize;
271+
272+ return true ;
273+ }
274+
275+ // Step 19.3: Extract keyframes update logic
276+ void QuickTimeMuxer::updateKeyframes (std::vector<uint8_t >& moovBox) {
277277 bool stssFound = false ;
278278 for (size_t i = 0 ; i + 16 <= moovBox.size (); i++) {
279279 if (moovBox[i] == 0x73 && moovBox[i+1 ] == 0x74 &&
@@ -387,11 +387,10 @@ bool QuickTimeMuxer::writeMoovBox() {
387387 if (!stssFound) {
388388 LOG (WARN) << " [QuickTimeMuxer] Could not find stss box in moov to fix keyframes!" ;
389389 }
390-
391- // Fix stco (chunk offset) to point to actual mdat data position
392- // stco must point to where frames start in the file (after ftyp and mdat header)
393- uint32_t actualChunkOffset = m_mdatStartPos + 8 ; // mdat header is 8 bytes (size + 'mdat')
394-
390+ }
391+
392+ // Step 19.4: Extract chunk offset update logic
393+ void QuickTimeMuxer::updateChunkOffset (std::vector<uint8_t >& moovBox, uint32_t actualChunkOffset) {
395394 bool stcoFound = false ;
396395 for (size_t i = 0 ; i + 16 <= moovBox.size (); i++) {
397396 if (moovBox[i] == 0x73 && moovBox[i+1 ] == 0x74 &&
@@ -416,31 +415,53 @@ bool QuickTimeMuxer::writeMoovBox() {
416415 if (!stcoFound) {
417416 LOG (WARN) << " [QuickTimeMuxer] Could not find stco box in moov to fix chunk offset!" ;
418417 }
418+ }
419+
420+ // Step 19.2: Extract frame sizes update logic
421+ void QuickTimeMuxer::updateFrameSizes (std::vector<uint8_t >& moovBox) {
422+ bool stszFound = false ;
423+ for (size_t i = 0 ; i + 20 + m_frames.size () * 4 <= moovBox.size (); i++) {
424+ if (moovBox[i] == 0x73 && moovBox[i+1 ] == 0x74 &&
425+ moovBox[i+2 ] == 0x73 && moovBox[i+3 ] == 0x7A ) {
426+ // Found 'stsz', update entries
427+ size_t entriesStart = i + 16 ; // After 'stsz' + version/flags + sample_size + sample_count
428+
429+ for (size_t j = 0 ; j < m_frames.size (); j++) {
430+ size_t entryPos = entriesStart + j * 4 ;
431+ if (entryPos + 4 <= moovBox.size ()) {
432+ uint32_t frameSize = m_frames[j].size ;
433+ moovBox[entryPos] = (frameSize >> 24 ) & 0xFF ;
434+ moovBox[entryPos+1 ] = (frameSize >> 16 ) & 0xFF ;
435+ moovBox[entryPos+2 ] = (frameSize >> 8 ) & 0xFF ;
436+ moovBox[entryPos+3 ] = frameSize & 0xFF ;
437+ }
438+ }
439+
440+ stszFound = true ;
441+ LOG (DEBUG) << " [QuickTimeMuxer] Updated stsz with " << m_frames.size () << " frame sizes" ;
442+ break ;
443+ }
444+ }
419445
420- // Write moov at the end of file
421- written = write (m_fd, moovBox.data (), moovBox.size ());
422- if (written != static_cast <ssize_t >(moovBox.size ())) {
423- LOG (ERROR) << " [QuickTimeMuxer] Failed to write moov box: " << written << " /" << moovBox.size ();
446+ if (!stszFound) {
447+ LOG (WARN) << " [QuickTimeMuxer] Could not find stsz box in moov to update frame sizes!" ;
448+ }
449+ }
450+
451+ // Step 19.1: Extract mdat size update logic
452+ bool QuickTimeMuxer::updateMdatSize (size_t mdatTotalSize) {
453+ if (lseek (m_fd, m_mdatStartPos, SEEK_SET) == -1 ) {
454+ LOG (ERROR) << " [QuickTimeMuxer] Failed to seek to mdat position" ;
424455 return false ;
425456 }
426457
427- // CRITICAL: Sync data to disk BEFORE truncate
428- // Otherwise ftruncate may not work correctly with buffered data
429- fsync (m_fd);
430-
431- // Truncate file to current position (remove any garbage after moov)
432- off_t finalSize = moovStart + moovBox.size ();
433- if (ftruncate (m_fd, finalSize) == -1 ) {
434- LOG (WARN) << " [QuickTimeMuxer] Failed to truncate file to " << finalSize << " bytes (errno: " << errno << " )" ;
435- } else {
436- LOG (DEBUG) << " [QuickTimeMuxer] Truncated file to " << finalSize << " bytes" ;
458+ uint32_t mdatSizeBE = htonl (static_cast <uint32_t >(mdatTotalSize));
459+ ssize_t written = write (m_fd, &mdatSizeBE, 4 );
460+ if (written != 4 ) {
461+ LOG (ERROR) << " [QuickTimeMuxer] Failed to write mdat size" ;
462+ return false ;
437463 }
438464
439- // Final sync after truncate
440- fsync (m_fd);
441-
442- LOG (INFO) << " [QuickTimeMuxer] Wrote moov box (" << moovBox.size () << " bytes) at end, mdat size (" << mdatTotalSize << " bytes), final file size " << finalSize;
443-
444465 return true ;
445466}
446467
0 commit comments