Index: trunk/src/VBox/Main/src-client/WebMWriter.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/WebMWriter.cpp	(revision 70621)
+++ trunk/src/VBox/Main/src-client/WebMWriter.cpp	(revision 70622)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2013-2017 Oracle Corporation
+ * Copyright (C) 2013-2018 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -59,5 +59,5 @@
 WebMWriter::~WebMWriter(void)
 {
-    close();
+    Close();
 }
 
@@ -137,8 +137,8 @@
 int WebMWriter::Close(void)
 {
+    LogFlowFuncEnter();
+
     if (!isOpen())
         return VINF_SUCCESS;
-
-    LogFunc(("\n"));
 
     /* Make sure to drain all queues. */
@@ -366,5 +366,5 @@
     CurSeg.offStart = RTFileTell(getFile());
 
-    writeSegSeekInfo();
+    writeSeekHeader();
 
     /* Save offset of upcoming tracks segment. */
@@ -390,7 +390,7 @@
     WebMCluster &Cluster = CurSeg.CurCluster;
 
-    Log3Func(("[T%RU8C%RU64] Off=%RU64, PTS=%RU16, RelToClusterMs=%RU16, %zu bytes\n",
+    Log3Func(("[T%RU8C%RU64] Off=%RU64, AbsPTSMs=%RU64, RelToClusterMs=%RU16, %zu bytes\n",
               a_pTrack->uTrack, Cluster.uID, RTFileTell(getFile()),
-              a_pBlock->Data.tcPTSMs, a_pBlock->Data.tcRelToClusterMs, a_pBlock->Data.cb));
+              a_pBlock->Data.tcAbsPTSMs, a_pBlock->Data.tcRelToClusterMs, a_pBlock->Data.cb));
 #endif
     /*
@@ -400,7 +400,7 @@
     /* Block size. */
     writeUnsignedInteger(0x10000000u | (  1                 /* Track number size. */
-                                               + m_cbTimecode      /* Timecode size .*/
-                                               + 1                 /* Flags size. */
-                                               + a_pBlock->Data.cb /* Actual frame data size. */),  4);
+                                        + m_cbTimecode      /* Timecode size .*/
+                                        + 1                 /* Flags size. */
+                                        + a_pBlock->Data.cb /* Actual frame data size. */),  4);
     /* Track number. */
     writeSize(a_pTrack->uTrack);
@@ -430,8 +430,8 @@
     try
     {
-        const WebMTimecode tcMap = a_pBlock->Data.tcPTSMs;
+        const WebMTimecodeAbs tcAbsPTS = a_pBlock->Data.tcAbsPTSMs;
 
         /* See if we already have an entry for the specified timecode in our queue. */
-        WebMBlockMap::iterator itQueue = CurSeg.queueBlocks.Map.find(tcMap);
+        WebMBlockMap::iterator itQueue = CurSeg.queueBlocks.Map.find(tcAbsPTS);
         if (itQueue != CurSeg.queueBlocks.Map.end()) /* Use existing queue. */
         {
@@ -444,5 +444,5 @@
             Blocks.Enqueue(a_pBlock);
 
-            CurSeg.queueBlocks.Map[tcMap] = Blocks;
+            CurSeg.queueBlocks.Map[tcAbsPTS] = Blocks;
         }
 
@@ -473,12 +473,11 @@
     RT_NOREF(a_pTrack);
 
-    /* Calculate the PTS of this frame (in ms). */
-    WebMTimecode tcPTSMs = a_pPkt->data.frame.pts * 1000
-                         * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den;
-
-    if (   tcPTSMs
-        && tcPTSMs <= a_pTrack->tcLastWrittenMs)
-    {
-        tcPTSMs = a_pTrack->tcLastWrittenMs + 1;
+    /* Calculate the absolute PTS of this frame (in ms). */
+    WebMTimecodeAbs tcAbsPTSMs =   a_pPkt->data.frame.pts * 1000
+                                 * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den;
+    if (   tcAbsPTSMs
+        && tcAbsPTSMs <= a_pTrack->tcAbsLastWrittenMs)
+    {
+        tcAbsPTSMs = a_pTrack->tcAbsLastWrittenMs + 1;
     }
 
@@ -493,5 +492,5 @@
     return writeSimpleBlockQueued(a_pTrack,
                                   new WebMSimpleBlock(a_pTrack,
-                                                      tcPTSMs, a_pPkt->data.frame.buf, a_pPkt->data.frame.sz, fFlags));
+                                                      tcAbsPTSMs, a_pPkt->data.frame.buf, a_pPkt->data.frame.sz, fFlags));
 }
 #endif /* VBOX_WITH_LIBVPX */
@@ -505,9 +504,9 @@
  * @param   pvData          Pointer to simple data block to write.
  * @param   cbData          Size (in bytes) of simple data block to write.
- * @param   uPTSMs          PTS of simple data block.
+ * @param   tcAbsPTSMs      Absolute PTS of simple data block.
  *
  * @remarks Audio blocks that have same absolute timecode as video blocks SHOULD be written before the video blocks.
  */
-int WebMWriter::writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecode uPTSMs)
+int WebMWriter::writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecodeAbs tcAbsPTSMs)
 {
     AssertPtrReturn(a_pTrack, VERR_INVALID_POINTER);
@@ -519,6 +518,5 @@
 
     return writeSimpleBlockQueued(a_pTrack,
-                                  new WebMSimpleBlock(a_pTrack,
-                                                      uPTSMs, pvData, cbData, fFlags));
+                                  new WebMSimpleBlock(a_pTrack, tcAbsPTSMs, pvData, cbData, fFlags));
 }
 #endif /* VBOX_WITH_LIBOPUS */
@@ -609,11 +607,11 @@
 int WebMWriter::processQueues(WebMQueue *pQueue, bool fForce)
 {
-    if (pQueue->tslastProcessedMs == 0)
-        pQueue->tslastProcessedMs = RTTimeMilliTS();
+    if (pQueue->tsLastProcessedMs == 0)
+        pQueue->tsLastProcessedMs = RTTimeMilliTS();
 
     if (!fForce)
     {
         /* Only process when we reached a certain threshold. */
-        if (RTTimeMilliTS() - pQueue->tslastProcessedMs < 5000 /* ms */ /** @todo Make this configurable */)
+        if (RTTimeMilliTS() - pQueue->tsLastProcessedMs < 5000 /* ms */ /** @todo Make this configurable */)
             return VINF_SUCCESS;
     }
@@ -625,7 +623,6 @@
     while (it != CurSeg.queueBlocks.Map.end())
     {
-        WebMTimecode       mapTC     = it->first;
-        RT_NOREF(mapTC);
-        WebMTimecodeBlocks mapBlocks = it->second;
+        WebMTimecodeAbs    mapAbsPTSMs = it->first;
+        WebMTimecodeBlocks mapBlocks   = it->second;
 
         /* Whether to start a new cluster or not. */
@@ -637,5 +634,5 @@
 
         /* Did we reach the maximum a cluster can hold? Use a new cluster then. */
-        if (mapTC - Cluster.tcStartMs > VBOX_WEBM_CLUSTER_MAX_LEN_MS)
+        if (mapAbsPTSMs - Cluster.tcAbsStartMs > VBOX_WEBM_CLUSTER_MAX_LEN_MS)
             fClusterStart = true;
 
@@ -657,19 +654,22 @@
             }
 
-            Cluster.fOpen     = true;
-            Cluster.uID       = CurSeg.cClusters;
-            Cluster.tcStartMs = mapTC;
-            Cluster.offStart  = RTFileTell(getFile());
-            Cluster.cBlocks   = 0;
+            Cluster.fOpen        = true;
+            Cluster.uID          = CurSeg.cClusters;
+            Cluster.tcAbsStartMs = mapAbsPTSMs;
+            Cluster.offStart     = RTFileTell(getFile());
+            Cluster.cBlocks      = 0;
+
+            Log2Func(("[C%RU64] Start @ %RU64ms (map TC is %RU64) / %RU64 bytes\n",
+                      Cluster.uID, Cluster.tcAbsStartMs, mapAbsPTSMs, Cluster.offStart));
 
             if (CurSeg.cClusters)
-                AssertMsg(Cluster.tcStartMs, ("[C%RU64] @ %RU64 starting timecode is 0 which is invalid\n",
-                                              Cluster.uID, Cluster.offStart));
-
-            Log2Func(("[C%RU64] Start @ %RU64ms (map TC is %RU64) / %RU64 bytes\n",
-                      Cluster.uID, Cluster.tcStartMs, mapTC, Cluster.offStart));
+                AssertMsg(Cluster.tcAbsStartMs, ("[C%RU64] @ %RU64 starting timecode is 0 which is invalid\n",
+                                                 Cluster.uID, Cluster.offStart));
+
+            Log2Func(("[C%RU64] Start @ %RU64ms (mapAbsPTSMs %RU64ms) / %RU64 bytes\n",
+                      Cluster.uID, Cluster.tcAbsStartMs, mapAbsPTSMs, Cluster.offStart));
 
             subStart(MkvElem_Cluster)
-                  .serializeUnsignedInteger(MkvElem_Timecode, Cluster.tcStartMs);
+                .serializeUnsignedInteger(MkvElem_Timecode, Cluster.tcAbsStartMs);
 
             CurSeg.cClusters++;
@@ -688,6 +688,6 @@
 
             /* Calculate the block's relative time code to the current cluster's starting time code. */
-            Assert(pBlock->Data.tcPTSMs >= Cluster.tcStartMs);
-            pBlock->Data.tcRelToClusterMs = pBlock->Data.tcPTSMs - Cluster.tcStartMs;
+            Assert(pBlock->Data.tcAbsPTSMs >= Cluster.tcAbsStartMs);
+            pBlock->Data.tcRelToClusterMs = pBlock->Data.tcAbsPTSMs - Cluster.tcAbsStartMs;
 
             int rc2 = writeSimpleBlockEBML(pTrack, pBlock);
@@ -697,13 +697,13 @@
 
             pTrack->cTotalBlocks++;
-            pTrack->tcLastWrittenMs = pBlock->Data.tcPTSMs;
-
-            if (CurSeg.tcLastWrittenMs < pTrack->tcLastWrittenMs)
-                CurSeg.tcLastWrittenMs = pTrack->tcLastWrittenMs;
+            pTrack->tcAbsLastWrittenMs = pBlock->Data.tcAbsPTSMs;
+
+            if (CurSeg.tcAbsLastWrittenMs < pTrack->tcAbsLastWrittenMs)
+                CurSeg.tcAbsLastWrittenMs = pTrack->tcAbsLastWrittenMs;
 
             /* Save a cue point if this is a keyframe. */
             if (pBlock->Data.fFlags & VBOX_WEBM_BLOCK_FLAG_KEY_FRAME)
             {
-                WebMCuePoint cue(pBlock->pTrack, Cluster.offStart, pBlock->Data.tcPTSMs);
+                WebMCuePoint cue(pBlock->pTrack, Cluster.offStart, Cluster.tcAbsStartMs);
                 CurSeg.lstCues.push_back(cue);
             }
@@ -724,5 +724,5 @@
     Assert(CurSeg.queueBlocks.Map.empty());
 
-    pQueue->tslastProcessedMs = RTTimeMilliTS();
+    pQueue->tsLastProcessedMs = RTTimeMilliTS();
 
     return VINF_SUCCESS;
@@ -753,7 +753,6 @@
      * Write Cues element.
      */
-    LogFunc(("Cues @ %RU64\n", RTFileTell(getFile())));
-
     CurSeg.offCues = RTFileTell(getFile());
+    LogFunc(("Cues @ %RU64\n", CurSeg.offCues));
 
     subStart(MkvElem_Cues);
@@ -765,15 +764,15 @@
         AssertPtr(itCuePoint->pTrack);
 
-        LogFunc(("CuePoint @ %RU64: Track #%RU8 (Cluster @ %RU64, TC %RU64)\n",
+        LogFunc(("CuePoint @ %RU64: Track #%RU8 (Cluster @ %RU64, tcAbs=%RU64)\n",
                  RTFileTell(getFile()), itCuePoint->pTrack->uTrack,
                  itCuePoint->offCluster, itCuePoint->tcAbs));
 
         subStart(MkvElem_CuePoint)
-                  .serializeUnsignedInteger(MkvElem_CueTime,                itCuePoint->tcAbs)
-                  .subStart(MkvElem_CueTrackPositions)
-                      .serializeUnsignedInteger(MkvElem_CueTrack,           itCuePoint->pTrack->uTrack)
-                      .serializeUnsignedInteger(MkvElem_CueClusterPosition, itCuePoint->offCluster, 8)
-              .subEnd(MkvElem_CueTrackPositions)
-              .subEnd(MkvElem_CuePoint);
+            .serializeUnsignedInteger(MkvElem_CueTime,                itCuePoint->tcAbs)
+            .subStart(MkvElem_CueTrackPositions)
+                .serializeUnsignedInteger(MkvElem_CueTrack,           itCuePoint->pTrack->uTrack)
+                .serializeUnsignedInteger(MkvElem_CueClusterPosition, itCuePoint->offCluster - CurSeg.offStart, 8)
+                .subEnd(MkvElem_CueTrackPositions)
+            .subEnd(MkvElem_CuePoint);
 
         itCuePoint++;
@@ -784,8 +783,8 @@
 
     /*
-     * Re-Update SeekHead / Info elements.
+     * Re-Update seek header with final information.
      */
 
-    writeSegSeekInfo();
+    writeSeekHeader();
 
     return RTFileSeek(getFile(), 0, RTFILE_SEEK_END, NULL);
@@ -793,7 +792,7 @@
 
 /**
- * Writes the segment's seek information and cue points.
- */
-void WebMWriter::writeSegSeekInfo(void)
+ * Writes the segment's seek header.
+ */
+void WebMWriter::writeSeekHeader(void)
 {
     if (CurSeg.offSeekInfo)
@@ -802,5 +801,5 @@
         CurSeg.offSeekInfo = RTFileTell(getFile());
 
-    LogFunc(("SeekHead @ %RU64\n", CurSeg.offSeekInfo));
+    LogFunc(("Seek Headeder @ %RU64\n", CurSeg.offSeekInfo));
 
     subStart(MkvElem_SeekHead);
@@ -811,5 +810,6 @@
           .subEnd(MkvElem_Seek);
 
-    Assert(CurSeg.offCues - CurSeg.offStart > 0); /* Sanity. */
+    if (CurSeg.offCues)
+        LogFunc(("Updating Cues @ %RU64\n", CurSeg.offCues));
 
     subStart(MkvElem_Seek)
@@ -825,5 +825,9 @@
     subEnd(MkvElem_SeekHead);
 
-    //int64_t iFrameTime = (int64_t)1000 * 1 / 25; //m_Framerate.den / m_Framerate.num; /** @todo Fix this! */
+    /*
+     * Write the segment's info element.
+     */
+
+    /* Save offset of the segment's info element. */
     CurSeg.offInfo = RTFileTell(getFile());
 
@@ -840,18 +844,18 @@
     RTStrPrintf(szApp, sizeof(szApp), VBOX_PRODUCT " %sr%u", VBOX_VERSION_STRING, RTBldCfgRevision());
 
-    const WebMTimecode tcDuration = CurSeg.tcLastWrittenMs - CurSeg.tcStartMs;
+    const WebMTimecodeAbs tcAbsDurationMs = CurSeg.tcAbsLastWrittenMs - CurSeg.tcAbsStartMs;
 
     if (!CurSeg.lstCues.empty())
     {
-        LogFunc(("tcDuration=%RU64\n", tcDuration));
-        AssertMsg(tcDuration, ("Segment seems to be empty\n"));
+        LogFunc(("tcAbsDurationMs=%RU64\n", tcAbsDurationMs));
+        AssertMsg(tcAbsDurationMs, ("Segment seems to be empty (duration is 0)\n"));
     }
 
     subStart(MkvElem_Info)
-          .serializeUnsignedInteger(MkvElem_TimecodeScale, CurSeg.uTimecodeScaleFactor)
-          .serializeFloat(MkvElem_Segment_Duration, tcDuration)
-          .serializeString(MkvElem_MuxingApp, szMux)
-          .serializeString(MkvElem_WritingApp, szApp)
-          .subEnd(MkvElem_Info);
-}
-
+        .serializeUnsignedInteger(MkvElem_TimecodeScale, CurSeg.uTimecodeScaleFactor)
+        .serializeFloat(MkvElem_Segment_Duration, tcAbsDurationMs)
+        .serializeString(MkvElem_MuxingApp, szMux)
+        .serializeString(MkvElem_WritingApp, szApp)
+        .subEnd(MkvElem_Info);
+}
+
Index: trunk/src/VBox/Main/src-client/WebMWriter.h
===================================================================
--- trunk/src/VBox/Main/src-client/WebMWriter.h	(revision 70621)
+++ trunk/src/VBox/Main/src-client/WebMWriter.h	(revision 70622)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2013-2017 Oracle Corporation
+ * Copyright (C) 2013-2018 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -91,6 +91,9 @@
 public:
 
-    /** Defines a WebM timecode. */
-    typedef uint16_t WebMTimecode;
+    /** Defines an absolute WebM timecode (Block + Cluster). */
+    typedef uint64_t WebMTimecodeAbs;
+
+    /** Defines a relative WebM timecode (Block). */
+    typedef uint16_t WebMTimecodeRel;
 
     /** Defines the WebM block flags data type. */
@@ -140,10 +143,10 @@
     {
         WebMSimpleBlock(WebMTrack *a_pTrack,
-                        WebMTimecode a_tcPTSMs, const void *a_pvData, size_t a_cbData, WebMBlockFlags a_fFlags)
+                        WebMTimecodeAbs a_tcAbsPTSMs, const void *a_pvData, size_t a_cbData, WebMBlockFlags a_fFlags)
             : pTrack(a_pTrack)
         {
-            Data.tcPTSMs = a_tcPTSMs;
-            Data.cb      = a_cbData;
-            Data.fFlags  = a_fFlags;
+            Data.tcAbsPTSMs = a_tcAbsPTSMs;
+            Data.cb         = a_cbData;
+            Data.fFlags     = a_fFlags;
 
             if (Data.cb)
@@ -169,6 +172,6 @@
         struct
         {
-            WebMTimecode   tcPTSMs;
-            WebMTimecode   tcRelToClusterMs;
+            WebMTimecodeAbs tcAbsPTSMs;
+            WebMTimecodeRel tcRelToClusterMs;
             void          *pv;
             size_t         cb;
@@ -212,5 +215,5 @@
      *  The key specifies a unique timecode, whereas the value
      *  is a queue of blocks which all correlate to the key (timecode). */
-    typedef std::map<WebMTimecode, WebMTimecodeBlocks> WebMBlockMap;
+    typedef std::map<WebMTimecodeAbs, WebMTimecodeBlocks> WebMBlockMap;
 
     /**
@@ -220,13 +223,13 @@
     {
         WebMQueue(void)
-            : tcLastBlockWrittenMs(0)
-            , tslastProcessedMs(0) { }
+            : tcAbsLastBlockWrittenMs(0)
+            , tsLastProcessedMs(0) { }
 
         /** Blocks as FIFO (queue). */
-        WebMBlockMap Map;
-        /** Timecode (in ms) of last written block to queue. */
-        WebMTimecode tcLastBlockWrittenMs;
+        WebMBlockMap    Map;
+        /** Absolute timecode (in ms) of last written block to queue. */
+        WebMTimecodeAbs tcAbsLastBlockWrittenMs;
         /** Time stamp (in ms) of when the queue was processed last. */
-        uint64_t     tslastProcessedMs;
+        uint64_t        tsLastProcessedMs;
     };
 
@@ -241,5 +244,5 @@
             , offUUID(a_offID)
             , cTotalBlocks(0)
-            , tcLastWrittenMs(0)
+            , tcAbsLastWrittenMs(0)
         {
             uUUID = RTRandU32();
@@ -281,6 +284,6 @@
         /** Total number of blocks. */
         uint64_t            cTotalBlocks;
-        /** Timecode (in ms) of last write. */
-        WebMTimecode        tcLastWrittenMs;
+        /** Absoute timecode (in ms) of last write. */
+        WebMTimecodeAbs     tcAbsLastWrittenMs;
     };
 
@@ -290,14 +293,14 @@
     struct WebMCuePoint
     {
-        WebMCuePoint(WebMTrack *a_pTrack, uint64_t a_offCluster, WebMTimecode a_tcAbs)
+        WebMCuePoint(WebMTrack *a_pTrack, uint64_t a_offCluster, WebMTimecodeAbs a_tcAbs)
             : pTrack(a_pTrack)
             , offCluster(a_offCluster), tcAbs(a_tcAbs) { }
 
         /** Associated track. */
-        WebMTrack   *pTrack;
+        WebMTrack      *pTrack;
         /** Offset (in bytes) of the related cluster containing the given position. */
-        uint64_t     offCluster;
-        /** Time code (absolute) of this cue point. */
-        WebMTimecode tcAbs;
+        uint64_t        offCluster;
+        /** Absolute time code according to the segment time base. */
+        WebMTimecodeAbs tcAbs;
     };
 
@@ -311,18 +314,18 @@
             , offStart(0)
             , fOpen(false)
-            , tcStartMs(0)
+            , tcAbsStartMs(0)
             , cBlocks(0) { }
 
         /** This cluster's ID. */
-        uint64_t      uID;
+        uint64_t        uID;
         /** Absolute offset (in bytes) of this cluster.
          *  Needed for seeking info table. */
-        uint64_t      offStart;
+        uint64_t        offStart;
         /** Whether this cluster element is opened currently. */
-        bool          fOpen;
-        /** Timecode (in ms) when this cluster starts. */
-        WebMTimecode  tcStartMs;
+        bool            fOpen;
+        /** Absolute timecode (in ms) when this cluster starts. */
+        WebMTimecodeAbs tcAbsStartMs;
         /** Number of (simple) blocks in this cluster. */
-        uint64_t      cBlocks;
+        uint64_t        cBlocks;
     };
 
@@ -335,6 +338,6 @@
     {
         WebMSegment(void)
-            : tcStartMs(0)
-            , tcLastWrittenMs(0)
+            : tcAbsStartMs(0)
+            , tcAbsLastWrittenMs(0)
             , offStart(0)
             , offInfo(0)
@@ -364,8 +367,8 @@
         uint64_t                        uTimecodeScaleFactor;
 
-        /** Timecode (in ms) when starting this segment. */
-        WebMTimecode                    tcStartMs;
-        /** Timecode (in ms) of last write. */
-        WebMTimecode                    tcLastWrittenMs;
+        /** Absolute timecode (in ms) when starting this segment. */
+        WebMTimecodeAbs                 tcAbsStartMs;
+        /** Absolute timecode (in ms) of last write. */
+        WebMTimecodeAbs                 tcAbsLastWrittenMs;
 
         /** Absolute offset (in bytes) of CurSeg. */
@@ -407,5 +410,5 @@
     bool                        m_fInTracksSection;
 
-    /** Size of timecodes in bytes. */
+    /** Size of timecodes (in bytes). */
     size_t                      m_cbTimecode;
     /** Maximum value a timecode can have. */
@@ -474,5 +477,5 @@
     int writeHeader(void);
 
-    void writeSegSeekInfo(void);
+    void writeSeekHeader(void);
 
     int writeFooter(void);
@@ -487,5 +490,5 @@
 
 #ifdef VBOX_WITH_LIBOPUS
-    int writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecode uPTSMs);
+    int writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecodeAbs tcAbsPTSMs);
 #endif
 
