Changeset 70622 in vbox
- Timestamp:
- Jan 18, 2018 9:52:31 AM (7 years ago)
- Location:
- trunk/src/VBox/Main/src-client
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-client/WebMWriter.cpp
r69689 r70622 5 5 6 6 /* 7 * Copyright (C) 2013-201 7Oracle Corporation7 * Copyright (C) 2013-2018 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 59 59 WebMWriter::~WebMWriter(void) 60 60 { 61 close();61 Close(); 62 62 } 63 63 … … 137 137 int WebMWriter::Close(void) 138 138 { 139 LogFlowFuncEnter(); 140 139 141 if (!isOpen()) 140 142 return VINF_SUCCESS; 141 142 LogFunc(("\n"));143 143 144 144 /* Make sure to drain all queues. */ … … 366 366 CurSeg.offStart = RTFileTell(getFile()); 367 367 368 writeSe gSeekInfo();368 writeSeekHeader(); 369 369 370 370 /* Save offset of upcoming tracks segment. */ … … 390 390 WebMCluster &Cluster = CurSeg.CurCluster; 391 391 392 Log3Func(("[T%RU8C%RU64] Off=%RU64, PTS=%RU16, RelToClusterMs=%RU16, %zu bytes\n",392 Log3Func(("[T%RU8C%RU64] Off=%RU64, AbsPTSMs=%RU64, RelToClusterMs=%RU16, %zu bytes\n", 393 393 a_pTrack->uTrack, Cluster.uID, RTFileTell(getFile()), 394 a_pBlock->Data.tc PTSMs, a_pBlock->Data.tcRelToClusterMs, a_pBlock->Data.cb));394 a_pBlock->Data.tcAbsPTSMs, a_pBlock->Data.tcRelToClusterMs, a_pBlock->Data.cb)); 395 395 #endif 396 396 /* … … 400 400 /* Block size. */ 401 401 writeUnsignedInteger(0x10000000u | ( 1 /* Track number size. */ 402 403 404 402 + m_cbTimecode /* Timecode size .*/ 403 + 1 /* Flags size. */ 404 + a_pBlock->Data.cb /* Actual frame data size. */), 4); 405 405 /* Track number. */ 406 406 writeSize(a_pTrack->uTrack); … … 430 430 try 431 431 { 432 const WebMTimecode tcMap = a_pBlock->Data.tcPTSMs;432 const WebMTimecodeAbs tcAbsPTS = a_pBlock->Data.tcAbsPTSMs; 433 433 434 434 /* See if we already have an entry for the specified timecode in our queue. */ 435 WebMBlockMap::iterator itQueue = CurSeg.queueBlocks.Map.find(tc Map);435 WebMBlockMap::iterator itQueue = CurSeg.queueBlocks.Map.find(tcAbsPTS); 436 436 if (itQueue != CurSeg.queueBlocks.Map.end()) /* Use existing queue. */ 437 437 { … … 444 444 Blocks.Enqueue(a_pBlock); 445 445 446 CurSeg.queueBlocks.Map[tc Map] = Blocks;446 CurSeg.queueBlocks.Map[tcAbsPTS] = Blocks; 447 447 } 448 448 … … 473 473 RT_NOREF(a_pTrack); 474 474 475 /* Calculate the PTS of this frame (in ms). */ 476 WebMTimecode tcPTSMs = a_pPkt->data.frame.pts * 1000 477 * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den; 478 479 if ( tcPTSMs 480 && tcPTSMs <= a_pTrack->tcLastWrittenMs) 481 { 482 tcPTSMs = a_pTrack->tcLastWrittenMs + 1; 475 /* Calculate the absolute PTS of this frame (in ms). */ 476 WebMTimecodeAbs tcAbsPTSMs = a_pPkt->data.frame.pts * 1000 477 * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den; 478 if ( tcAbsPTSMs 479 && tcAbsPTSMs <= a_pTrack->tcAbsLastWrittenMs) 480 { 481 tcAbsPTSMs = a_pTrack->tcAbsLastWrittenMs + 1; 483 482 } 484 483 … … 493 492 return writeSimpleBlockQueued(a_pTrack, 494 493 new WebMSimpleBlock(a_pTrack, 495 tc PTSMs, a_pPkt->data.frame.buf, a_pPkt->data.frame.sz, fFlags));494 tcAbsPTSMs, a_pPkt->data.frame.buf, a_pPkt->data.frame.sz, fFlags)); 496 495 } 497 496 #endif /* VBOX_WITH_LIBVPX */ … … 505 504 * @param pvData Pointer to simple data block to write. 506 505 * @param cbData Size (in bytes) of simple data block to write. 507 * @param uPTSMsPTS of simple data block.506 * @param tcAbsPTSMs Absolute PTS of simple data block. 508 507 * 509 508 * @remarks Audio blocks that have same absolute timecode as video blocks SHOULD be written before the video blocks. 510 509 */ 511 int WebMWriter::writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecode uPTSMs)510 int WebMWriter::writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecodeAbs tcAbsPTSMs) 512 511 { 513 512 AssertPtrReturn(a_pTrack, VERR_INVALID_POINTER); … … 519 518 520 519 return writeSimpleBlockQueued(a_pTrack, 521 new WebMSimpleBlock(a_pTrack, 522 uPTSMs, pvData, cbData, fFlags)); 520 new WebMSimpleBlock(a_pTrack, tcAbsPTSMs, pvData, cbData, fFlags)); 523 521 } 524 522 #endif /* VBOX_WITH_LIBOPUS */ … … 609 607 int WebMWriter::processQueues(WebMQueue *pQueue, bool fForce) 610 608 { 611 if (pQueue->ts lastProcessedMs == 0)612 pQueue->ts lastProcessedMs = RTTimeMilliTS();609 if (pQueue->tsLastProcessedMs == 0) 610 pQueue->tsLastProcessedMs = RTTimeMilliTS(); 613 611 614 612 if (!fForce) 615 613 { 616 614 /* Only process when we reached a certain threshold. */ 617 if (RTTimeMilliTS() - pQueue->ts lastProcessedMs < 5000 /* ms */ /** @todo Make this configurable */)615 if (RTTimeMilliTS() - pQueue->tsLastProcessedMs < 5000 /* ms */ /** @todo Make this configurable */) 618 616 return VINF_SUCCESS; 619 617 } … … 625 623 while (it != CurSeg.queueBlocks.Map.end()) 626 624 { 627 WebMTimecode mapTC = it->first; 628 RT_NOREF(mapTC); 629 WebMTimecodeBlocks mapBlocks = it->second; 625 WebMTimecodeAbs mapAbsPTSMs = it->first; 626 WebMTimecodeBlocks mapBlocks = it->second; 630 627 631 628 /* Whether to start a new cluster or not. */ … … 637 634 638 635 /* Did we reach the maximum a cluster can hold? Use a new cluster then. */ 639 if (map TC - Cluster.tcStartMs > VBOX_WEBM_CLUSTER_MAX_LEN_MS)636 if (mapAbsPTSMs - Cluster.tcAbsStartMs > VBOX_WEBM_CLUSTER_MAX_LEN_MS) 640 637 fClusterStart = true; 641 638 … … 657 654 } 658 655 659 Cluster.fOpen = true; 660 Cluster.uID = CurSeg.cClusters; 661 Cluster.tcStartMs = mapTC; 662 Cluster.offStart = RTFileTell(getFile()); 663 Cluster.cBlocks = 0; 656 Cluster.fOpen = true; 657 Cluster.uID = CurSeg.cClusters; 658 Cluster.tcAbsStartMs = mapAbsPTSMs; 659 Cluster.offStart = RTFileTell(getFile()); 660 Cluster.cBlocks = 0; 661 662 Log2Func(("[C%RU64] Start @ %RU64ms (map TC is %RU64) / %RU64 bytes\n", 663 Cluster.uID, Cluster.tcAbsStartMs, mapAbsPTSMs, Cluster.offStart)); 664 664 665 665 if (CurSeg.cClusters) 666 AssertMsg(Cluster.tc StartMs, ("[C%RU64] @ %RU64 starting timecode is 0 which is invalid\n",667 Cluster.uID, Cluster.offStart));668 669 Log2Func(("[C%RU64] Start @ %RU64ms (map TC is %RU64) / %RU64 bytes\n",670 Cluster.uID, Cluster.tc StartMs, mapTC, Cluster.offStart));666 AssertMsg(Cluster.tcAbsStartMs, ("[C%RU64] @ %RU64 starting timecode is 0 which is invalid\n", 667 Cluster.uID, Cluster.offStart)); 668 669 Log2Func(("[C%RU64] Start @ %RU64ms (mapAbsPTSMs %RU64ms) / %RU64 bytes\n", 670 Cluster.uID, Cluster.tcAbsStartMs, mapAbsPTSMs, Cluster.offStart)); 671 671 672 672 subStart(MkvElem_Cluster) 673 .serializeUnsignedInteger(MkvElem_Timecode, Cluster.tcStartMs);673 .serializeUnsignedInteger(MkvElem_Timecode, Cluster.tcAbsStartMs); 674 674 675 675 CurSeg.cClusters++; … … 688 688 689 689 /* Calculate the block's relative time code to the current cluster's starting time code. */ 690 Assert(pBlock->Data.tc PTSMs >= Cluster.tcStartMs);691 pBlock->Data.tcRelToClusterMs = pBlock->Data.tc PTSMs - Cluster.tcStartMs;690 Assert(pBlock->Data.tcAbsPTSMs >= Cluster.tcAbsStartMs); 691 pBlock->Data.tcRelToClusterMs = pBlock->Data.tcAbsPTSMs - Cluster.tcAbsStartMs; 692 692 693 693 int rc2 = writeSimpleBlockEBML(pTrack, pBlock); … … 697 697 698 698 pTrack->cTotalBlocks++; 699 pTrack->tc LastWrittenMs = pBlock->Data.tcPTSMs;700 701 if (CurSeg.tc LastWrittenMs < pTrack->tcLastWrittenMs)702 CurSeg.tc LastWrittenMs = pTrack->tcLastWrittenMs;699 pTrack->tcAbsLastWrittenMs = pBlock->Data.tcAbsPTSMs; 700 701 if (CurSeg.tcAbsLastWrittenMs < pTrack->tcAbsLastWrittenMs) 702 CurSeg.tcAbsLastWrittenMs = pTrack->tcAbsLastWrittenMs; 703 703 704 704 /* Save a cue point if this is a keyframe. */ 705 705 if (pBlock->Data.fFlags & VBOX_WEBM_BLOCK_FLAG_KEY_FRAME) 706 706 { 707 WebMCuePoint cue(pBlock->pTrack, Cluster.offStart, pBlock->Data.tcPTSMs);707 WebMCuePoint cue(pBlock->pTrack, Cluster.offStart, Cluster.tcAbsStartMs); 708 708 CurSeg.lstCues.push_back(cue); 709 709 } … … 724 724 Assert(CurSeg.queueBlocks.Map.empty()); 725 725 726 pQueue->ts lastProcessedMs = RTTimeMilliTS();726 pQueue->tsLastProcessedMs = RTTimeMilliTS(); 727 727 728 728 return VINF_SUCCESS; … … 753 753 * Write Cues element. 754 754 */ 755 LogFunc(("Cues @ %RU64\n", RTFileTell(getFile())));756 757 755 CurSeg.offCues = RTFileTell(getFile()); 756 LogFunc(("Cues @ %RU64\n", CurSeg.offCues)); 758 757 759 758 subStart(MkvElem_Cues); … … 765 764 AssertPtr(itCuePoint->pTrack); 766 765 767 LogFunc(("CuePoint @ %RU64: Track #%RU8 (Cluster @ %RU64, TC%RU64)\n",766 LogFunc(("CuePoint @ %RU64: Track #%RU8 (Cluster @ %RU64, tcAbs=%RU64)\n", 768 767 RTFileTell(getFile()), itCuePoint->pTrack->uTrack, 769 768 itCuePoint->offCluster, itCuePoint->tcAbs)); 770 769 771 770 subStart(MkvElem_CuePoint) 772 773 774 775 .serializeUnsignedInteger(MkvElem_CueClusterPosition, itCuePoint->offCluster, 8)776 .subEnd(MkvElem_CueTrackPositions)777 771 .serializeUnsignedInteger(MkvElem_CueTime, itCuePoint->tcAbs) 772 .subStart(MkvElem_CueTrackPositions) 773 .serializeUnsignedInteger(MkvElem_CueTrack, itCuePoint->pTrack->uTrack) 774 .serializeUnsignedInteger(MkvElem_CueClusterPosition, itCuePoint->offCluster - CurSeg.offStart, 8) 775 .subEnd(MkvElem_CueTrackPositions) 776 .subEnd(MkvElem_CuePoint); 778 777 779 778 itCuePoint++; … … 784 783 785 784 /* 786 * Re-Update SeekHead / Info elements.785 * Re-Update seek header with final information. 787 786 */ 788 787 789 writeSe gSeekInfo();788 writeSeekHeader(); 790 789 791 790 return RTFileSeek(getFile(), 0, RTFILE_SEEK_END, NULL); … … 793 792 794 793 /** 795 * Writes the segment's seek information and cue points.796 */ 797 void WebMWriter::writeSe gSeekInfo(void)794 * Writes the segment's seek header. 795 */ 796 void WebMWriter::writeSeekHeader(void) 798 797 { 799 798 if (CurSeg.offSeekInfo) … … 802 801 CurSeg.offSeekInfo = RTFileTell(getFile()); 803 802 804 LogFunc(("Seek Head@ %RU64\n", CurSeg.offSeekInfo));803 LogFunc(("Seek Headeder @ %RU64\n", CurSeg.offSeekInfo)); 805 804 806 805 subStart(MkvElem_SeekHead); … … 811 810 .subEnd(MkvElem_Seek); 812 811 813 Assert(CurSeg.offCues - CurSeg.offStart > 0); /* Sanity. */ 812 if (CurSeg.offCues) 813 LogFunc(("Updating Cues @ %RU64\n", CurSeg.offCues)); 814 814 815 815 subStart(MkvElem_Seek) … … 825 825 subEnd(MkvElem_SeekHead); 826 826 827 //int64_t iFrameTime = (int64_t)1000 * 1 / 25; //m_Framerate.den / m_Framerate.num; /** @todo Fix this! */ 827 /* 828 * Write the segment's info element. 829 */ 830 831 /* Save offset of the segment's info element. */ 828 832 CurSeg.offInfo = RTFileTell(getFile()); 829 833 … … 840 844 RTStrPrintf(szApp, sizeof(szApp), VBOX_PRODUCT " %sr%u", VBOX_VERSION_STRING, RTBldCfgRevision()); 841 845 842 const WebMTimecode tcDuration = CurSeg.tcLastWrittenMs - CurSeg.tcStartMs;846 const WebMTimecodeAbs tcAbsDurationMs = CurSeg.tcAbsLastWrittenMs - CurSeg.tcAbsStartMs; 843 847 844 848 if (!CurSeg.lstCues.empty()) 845 849 { 846 LogFunc(("tc Duration=%RU64\n", tcDuration));847 AssertMsg(tc Duration, ("Segment seems to be empty\n"));850 LogFunc(("tcAbsDurationMs=%RU64\n", tcAbsDurationMs)); 851 AssertMsg(tcAbsDurationMs, ("Segment seems to be empty (duration is 0)\n")); 848 852 } 849 853 850 854 subStart(MkvElem_Info) 851 852 .serializeFloat(MkvElem_Segment_Duration, tcDuration)853 854 855 856 } 857 855 .serializeUnsignedInteger(MkvElem_TimecodeScale, CurSeg.uTimecodeScaleFactor) 856 .serializeFloat(MkvElem_Segment_Duration, tcAbsDurationMs) 857 .serializeString(MkvElem_MuxingApp, szMux) 858 .serializeString(MkvElem_WritingApp, szApp) 859 .subEnd(MkvElem_Info); 860 } 861 -
trunk/src/VBox/Main/src-client/WebMWriter.h
r69689 r70622 5 5 6 6 /* 7 * Copyright (C) 2013-201 7Oracle Corporation7 * Copyright (C) 2013-2018 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 91 91 public: 92 92 93 /** Defines a WebM timecode. */ 94 typedef uint16_t WebMTimecode; 93 /** Defines an absolute WebM timecode (Block + Cluster). */ 94 typedef uint64_t WebMTimecodeAbs; 95 96 /** Defines a relative WebM timecode (Block). */ 97 typedef uint16_t WebMTimecodeRel; 95 98 96 99 /** Defines the WebM block flags data type. */ … … 140 143 { 141 144 WebMSimpleBlock(WebMTrack *a_pTrack, 142 WebMTimecode a_tcPTSMs, const void *a_pvData, size_t a_cbData, WebMBlockFlags a_fFlags)145 WebMTimecodeAbs a_tcAbsPTSMs, const void *a_pvData, size_t a_cbData, WebMBlockFlags a_fFlags) 143 146 : pTrack(a_pTrack) 144 147 { 145 Data.tc PTSMs = a_tcPTSMs;146 Data.cb = a_cbData;147 Data.fFlags = a_fFlags;148 Data.tcAbsPTSMs = a_tcAbsPTSMs; 149 Data.cb = a_cbData; 150 Data.fFlags = a_fFlags; 148 151 149 152 if (Data.cb) … … 169 172 struct 170 173 { 171 WebMTimecode tcPTSMs;172 WebMTimecode 174 WebMTimecodeAbs tcAbsPTSMs; 175 WebMTimecodeRel tcRelToClusterMs; 173 176 void *pv; 174 177 size_t cb; … … 212 215 * The key specifies a unique timecode, whereas the value 213 216 * is a queue of blocks which all correlate to the key (timecode). */ 214 typedef std::map<WebMTimecode , WebMTimecodeBlocks> WebMBlockMap;217 typedef std::map<WebMTimecodeAbs, WebMTimecodeBlocks> WebMBlockMap; 215 218 216 219 /** … … 220 223 { 221 224 WebMQueue(void) 222 : tc LastBlockWrittenMs(0)223 , ts lastProcessedMs(0) { }225 : tcAbsLastBlockWrittenMs(0) 226 , tsLastProcessedMs(0) { } 224 227 225 228 /** Blocks as FIFO (queue). */ 226 WebMBlockMap Map;227 /** Timecode (in ms) of last written block to queue. */228 WebMTimecode tcLastBlockWrittenMs;229 WebMBlockMap Map; 230 /** Absolute timecode (in ms) of last written block to queue. */ 231 WebMTimecodeAbs tcAbsLastBlockWrittenMs; 229 232 /** Time stamp (in ms) of when the queue was processed last. */ 230 uint64_t tslastProcessedMs;233 uint64_t tsLastProcessedMs; 231 234 }; 232 235 … … 241 244 , offUUID(a_offID) 242 245 , cTotalBlocks(0) 243 , tc LastWrittenMs(0)246 , tcAbsLastWrittenMs(0) 244 247 { 245 248 uUUID = RTRandU32(); … … 281 284 /** Total number of blocks. */ 282 285 uint64_t cTotalBlocks; 283 /** Timecode (in ms) of last write. */284 WebMTimecode tcLastWrittenMs;286 /** Absoute timecode (in ms) of last write. */ 287 WebMTimecodeAbs tcAbsLastWrittenMs; 285 288 }; 286 289 … … 290 293 struct WebMCuePoint 291 294 { 292 WebMCuePoint(WebMTrack *a_pTrack, uint64_t a_offCluster, WebMTimecode a_tcAbs)295 WebMCuePoint(WebMTrack *a_pTrack, uint64_t a_offCluster, WebMTimecodeAbs a_tcAbs) 293 296 : pTrack(a_pTrack) 294 297 , offCluster(a_offCluster), tcAbs(a_tcAbs) { } 295 298 296 299 /** Associated track. */ 297 WebMTrack *pTrack;300 WebMTrack *pTrack; 298 301 /** Offset (in bytes) of the related cluster containing the given position. */ 299 uint64_t offCluster;300 /** Time code (absolute) of this cue point. */301 WebMTimecode tcAbs;302 uint64_t offCluster; 303 /** Absolute time code according to the segment time base. */ 304 WebMTimecodeAbs tcAbs; 302 305 }; 303 306 … … 311 314 , offStart(0) 312 315 , fOpen(false) 313 , tc StartMs(0)316 , tcAbsStartMs(0) 314 317 , cBlocks(0) { } 315 318 316 319 /** This cluster's ID. */ 317 uint64_t uID;320 uint64_t uID; 318 321 /** Absolute offset (in bytes) of this cluster. 319 322 * Needed for seeking info table. */ 320 uint64_t offStart;323 uint64_t offStart; 321 324 /** Whether this cluster element is opened currently. */ 322 bool fOpen;323 /** Timecode (in ms) when this cluster starts. */324 WebMTimecode tcStartMs;325 bool fOpen; 326 /** Absolute timecode (in ms) when this cluster starts. */ 327 WebMTimecodeAbs tcAbsStartMs; 325 328 /** Number of (simple) blocks in this cluster. */ 326 uint64_t cBlocks;329 uint64_t cBlocks; 327 330 }; 328 331 … … 335 338 { 336 339 WebMSegment(void) 337 : tc StartMs(0)338 , tc LastWrittenMs(0)340 : tcAbsStartMs(0) 341 , tcAbsLastWrittenMs(0) 339 342 , offStart(0) 340 343 , offInfo(0) … … 364 367 uint64_t uTimecodeScaleFactor; 365 368 366 /** Timecode (in ms) when starting this segment. */367 WebMTimecode tcStartMs;368 /** Timecode (in ms) of last write. */369 WebMTimecode tcLastWrittenMs;369 /** Absolute timecode (in ms) when starting this segment. */ 370 WebMTimecodeAbs tcAbsStartMs; 371 /** Absolute timecode (in ms) of last write. */ 372 WebMTimecodeAbs tcAbsLastWrittenMs; 370 373 371 374 /** Absolute offset (in bytes) of CurSeg. */ … … 407 410 bool m_fInTracksSection; 408 411 409 /** Size of timecodes in bytes. */412 /** Size of timecodes (in bytes). */ 410 413 size_t m_cbTimecode; 411 414 /** Maximum value a timecode can have. */ … … 474 477 int writeHeader(void); 475 478 476 void writeSe gSeekInfo(void);479 void writeSeekHeader(void); 477 480 478 481 int writeFooter(void); … … 487 490 488 491 #ifdef VBOX_WITH_LIBOPUS 489 int writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecode uPTSMs);492 int writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecodeAbs tcAbsPTSMs); 490 493 #endif 491 494
Note:
See TracChangeset
for help on using the changeset viewer.