VirtualBox

Changeset 70622 in vbox


Ignore:
Timestamp:
Jan 18, 2018 9:52:31 AM (7 years ago)
Author:
vboxsync
Message:

VideoRec/WebMWriter: Added support for relative and absolute Timecodes, emphasizing its usage; renaming.

Location:
trunk/src/VBox/Main/src-client
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-client/WebMWriter.cpp

    r69689 r70622  
    55
    66/*
    7  * Copyright (C) 2013-2017 Oracle Corporation
     7 * Copyright (C) 2013-2018 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    5959WebMWriter::~WebMWriter(void)
    6060{
    61     close();
     61    Close();
    6262}
    6363
     
    137137int WebMWriter::Close(void)
    138138{
     139    LogFlowFuncEnter();
     140
    139141    if (!isOpen())
    140142        return VINF_SUCCESS;
    141 
    142     LogFunc(("\n"));
    143143
    144144    /* Make sure to drain all queues. */
     
    366366    CurSeg.offStart = RTFileTell(getFile());
    367367
    368     writeSegSeekInfo();
     368    writeSeekHeader();
    369369
    370370    /* Save offset of upcoming tracks segment. */
     
    390390    WebMCluster &Cluster = CurSeg.CurCluster;
    391391
    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",
    393393              a_pTrack->uTrack, Cluster.uID, RTFileTell(getFile()),
    394               a_pBlock->Data.tcPTSMs, a_pBlock->Data.tcRelToClusterMs, a_pBlock->Data.cb));
     394              a_pBlock->Data.tcAbsPTSMs, a_pBlock->Data.tcRelToClusterMs, a_pBlock->Data.cb));
    395395#endif
    396396    /*
     
    400400    /* Block size. */
    401401    writeUnsignedInteger(0x10000000u | (  1                 /* Track number size. */
    402                                                + m_cbTimecode      /* Timecode size .*/
    403                                                + 1                 /* Flags size. */
    404                                                + a_pBlock->Data.cb /* Actual frame data size. */),  4);
     402                                        + m_cbTimecode      /* Timecode size .*/
     403                                        + 1                 /* Flags size. */
     404                                        + a_pBlock->Data.cb /* Actual frame data size. */),  4);
    405405    /* Track number. */
    406406    writeSize(a_pTrack->uTrack);
     
    430430    try
    431431    {
    432         const WebMTimecode tcMap = a_pBlock->Data.tcPTSMs;
     432        const WebMTimecodeAbs tcAbsPTS = a_pBlock->Data.tcAbsPTSMs;
    433433
    434434        /* See if we already have an entry for the specified timecode in our queue. */
    435         WebMBlockMap::iterator itQueue = CurSeg.queueBlocks.Map.find(tcMap);
     435        WebMBlockMap::iterator itQueue = CurSeg.queueBlocks.Map.find(tcAbsPTS);
    436436        if (itQueue != CurSeg.queueBlocks.Map.end()) /* Use existing queue. */
    437437        {
     
    444444            Blocks.Enqueue(a_pBlock);
    445445
    446             CurSeg.queueBlocks.Map[tcMap] = Blocks;
     446            CurSeg.queueBlocks.Map[tcAbsPTS] = Blocks;
    447447        }
    448448
     
    473473    RT_NOREF(a_pTrack);
    474474
    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;
    483482    }
    484483
     
    493492    return writeSimpleBlockQueued(a_pTrack,
    494493                                  new WebMSimpleBlock(a_pTrack,
    495                                                       tcPTSMs, a_pPkt->data.frame.buf, a_pPkt->data.frame.sz, fFlags));
     494                                                      tcAbsPTSMs, a_pPkt->data.frame.buf, a_pPkt->data.frame.sz, fFlags));
    496495}
    497496#endif /* VBOX_WITH_LIBVPX */
     
    505504 * @param   pvData          Pointer to simple data block to write.
    506505 * @param   cbData          Size (in bytes) of simple data block to write.
    507  * @param   uPTSMs          PTS of simple data block.
     506 * @param   tcAbsPTSMs      Absolute PTS of simple data block.
    508507 *
    509508 * @remarks Audio blocks that have same absolute timecode as video blocks SHOULD be written before the video blocks.
    510509 */
    511 int WebMWriter::writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecode uPTSMs)
     510int WebMWriter::writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecodeAbs tcAbsPTSMs)
    512511{
    513512    AssertPtrReturn(a_pTrack, VERR_INVALID_POINTER);
     
    519518
    520519    return writeSimpleBlockQueued(a_pTrack,
    521                                   new WebMSimpleBlock(a_pTrack,
    522                                                       uPTSMs, pvData, cbData, fFlags));
     520                                  new WebMSimpleBlock(a_pTrack, tcAbsPTSMs, pvData, cbData, fFlags));
    523521}
    524522#endif /* VBOX_WITH_LIBOPUS */
     
    609607int WebMWriter::processQueues(WebMQueue *pQueue, bool fForce)
    610608{
    611     if (pQueue->tslastProcessedMs == 0)
    612         pQueue->tslastProcessedMs = RTTimeMilliTS();
     609    if (pQueue->tsLastProcessedMs == 0)
     610        pQueue->tsLastProcessedMs = RTTimeMilliTS();
    613611
    614612    if (!fForce)
    615613    {
    616614        /* Only process when we reached a certain threshold. */
    617         if (RTTimeMilliTS() - pQueue->tslastProcessedMs < 5000 /* ms */ /** @todo Make this configurable */)
     615        if (RTTimeMilliTS() - pQueue->tsLastProcessedMs < 5000 /* ms */ /** @todo Make this configurable */)
    618616            return VINF_SUCCESS;
    619617    }
     
    625623    while (it != CurSeg.queueBlocks.Map.end())
    626624    {
    627         WebMTimecode       mapTC     = it->first;
    628         RT_NOREF(mapTC);
    629         WebMTimecodeBlocks mapBlocks = it->second;
     625        WebMTimecodeAbs    mapAbsPTSMs = it->first;
     626        WebMTimecodeBlocks mapBlocks   = it->second;
    630627
    631628        /* Whether to start a new cluster or not. */
     
    637634
    638635        /* Did we reach the maximum a cluster can hold? Use a new cluster then. */
    639         if (mapTC - Cluster.tcStartMs > VBOX_WEBM_CLUSTER_MAX_LEN_MS)
     636        if (mapAbsPTSMs - Cluster.tcAbsStartMs > VBOX_WEBM_CLUSTER_MAX_LEN_MS)
    640637            fClusterStart = true;
    641638
     
    657654            }
    658655
    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));
    664664
    665665            if (CurSeg.cClusters)
    666                 AssertMsg(Cluster.tcStartMs, ("[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.tcStartMs, 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));
    671671
    672672            subStart(MkvElem_Cluster)
    673                   .serializeUnsignedInteger(MkvElem_Timecode, Cluster.tcStartMs);
     673                .serializeUnsignedInteger(MkvElem_Timecode, Cluster.tcAbsStartMs);
    674674
    675675            CurSeg.cClusters++;
     
    688688
    689689            /* Calculate the block's relative time code to the current cluster's starting time code. */
    690             Assert(pBlock->Data.tcPTSMs >= Cluster.tcStartMs);
    691             pBlock->Data.tcRelToClusterMs = pBlock->Data.tcPTSMs - Cluster.tcStartMs;
     690            Assert(pBlock->Data.tcAbsPTSMs >= Cluster.tcAbsStartMs);
     691            pBlock->Data.tcRelToClusterMs = pBlock->Data.tcAbsPTSMs - Cluster.tcAbsStartMs;
    692692
    693693            int rc2 = writeSimpleBlockEBML(pTrack, pBlock);
     
    697697
    698698            pTrack->cTotalBlocks++;
    699             pTrack->tcLastWrittenMs = pBlock->Data.tcPTSMs;
    700 
    701             if (CurSeg.tcLastWrittenMs < pTrack->tcLastWrittenMs)
    702                 CurSeg.tcLastWrittenMs = pTrack->tcLastWrittenMs;
     699            pTrack->tcAbsLastWrittenMs = pBlock->Data.tcAbsPTSMs;
     700
     701            if (CurSeg.tcAbsLastWrittenMs < pTrack->tcAbsLastWrittenMs)
     702                CurSeg.tcAbsLastWrittenMs = pTrack->tcAbsLastWrittenMs;
    703703
    704704            /* Save a cue point if this is a keyframe. */
    705705            if (pBlock->Data.fFlags & VBOX_WEBM_BLOCK_FLAG_KEY_FRAME)
    706706            {
    707                 WebMCuePoint cue(pBlock->pTrack, Cluster.offStart, pBlock->Data.tcPTSMs);
     707                WebMCuePoint cue(pBlock->pTrack, Cluster.offStart, Cluster.tcAbsStartMs);
    708708                CurSeg.lstCues.push_back(cue);
    709709            }
     
    724724    Assert(CurSeg.queueBlocks.Map.empty());
    725725
    726     pQueue->tslastProcessedMs = RTTimeMilliTS();
     726    pQueue->tsLastProcessedMs = RTTimeMilliTS();
    727727
    728728    return VINF_SUCCESS;
     
    753753     * Write Cues element.
    754754     */
    755     LogFunc(("Cues @ %RU64\n", RTFileTell(getFile())));
    756 
    757755    CurSeg.offCues = RTFileTell(getFile());
     756    LogFunc(("Cues @ %RU64\n", CurSeg.offCues));
    758757
    759758    subStart(MkvElem_Cues);
     
    765764        AssertPtr(itCuePoint->pTrack);
    766765
    767         LogFunc(("CuePoint @ %RU64: Track #%RU8 (Cluster @ %RU64, TC %RU64)\n",
     766        LogFunc(("CuePoint @ %RU64: Track #%RU8 (Cluster @ %RU64, tcAbs=%RU64)\n",
    768767                 RTFileTell(getFile()), itCuePoint->pTrack->uTrack,
    769768                 itCuePoint->offCluster, itCuePoint->tcAbs));
    770769
    771770        subStart(MkvElem_CuePoint)
    772                   .serializeUnsignedInteger(MkvElem_CueTime,                itCuePoint->tcAbs)
    773                   .subStart(MkvElem_CueTrackPositions)
    774                       .serializeUnsignedInteger(MkvElem_CueTrack,           itCuePoint->pTrack->uTrack)
    775                       .serializeUnsignedInteger(MkvElem_CueClusterPosition, itCuePoint->offCluster, 8)
    776               .subEnd(MkvElem_CueTrackPositions)
    777               .subEnd(MkvElem_CuePoint);
     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);
    778777
    779778        itCuePoint++;
     
    784783
    785784    /*
    786      * Re-Update SeekHead / Info elements.
     785     * Re-Update seek header with final information.
    787786     */
    788787
    789     writeSegSeekInfo();
     788    writeSeekHeader();
    790789
    791790    return RTFileSeek(getFile(), 0, RTFILE_SEEK_END, NULL);
     
    793792
    794793/**
    795  * Writes the segment's seek information and cue points.
    796  */
    797 void WebMWriter::writeSegSeekInfo(void)
     794 * Writes the segment's seek header.
     795 */
     796void WebMWriter::writeSeekHeader(void)
    798797{
    799798    if (CurSeg.offSeekInfo)
     
    802801        CurSeg.offSeekInfo = RTFileTell(getFile());
    803802
    804     LogFunc(("SeekHead @ %RU64\n", CurSeg.offSeekInfo));
     803    LogFunc(("Seek Headeder @ %RU64\n", CurSeg.offSeekInfo));
    805804
    806805    subStart(MkvElem_SeekHead);
     
    811810          .subEnd(MkvElem_Seek);
    812811
    813     Assert(CurSeg.offCues - CurSeg.offStart > 0); /* Sanity. */
     812    if (CurSeg.offCues)
     813        LogFunc(("Updating Cues @ %RU64\n", CurSeg.offCues));
    814814
    815815    subStart(MkvElem_Seek)
     
    825825    subEnd(MkvElem_SeekHead);
    826826
    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. */
    828832    CurSeg.offInfo = RTFileTell(getFile());
    829833
     
    840844    RTStrPrintf(szApp, sizeof(szApp), VBOX_PRODUCT " %sr%u", VBOX_VERSION_STRING, RTBldCfgRevision());
    841845
    842     const WebMTimecode tcDuration = CurSeg.tcLastWrittenMs - CurSeg.tcStartMs;
     846    const WebMTimecodeAbs tcAbsDurationMs = CurSeg.tcAbsLastWrittenMs - CurSeg.tcAbsStartMs;
    843847
    844848    if (!CurSeg.lstCues.empty())
    845849    {
    846         LogFunc(("tcDuration=%RU64\n", tcDuration));
    847         AssertMsg(tcDuration, ("Segment seems to be empty\n"));
     850        LogFunc(("tcAbsDurationMs=%RU64\n", tcAbsDurationMs));
     851        AssertMsg(tcAbsDurationMs, ("Segment seems to be empty (duration is 0)\n"));
    848852    }
    849853
    850854    subStart(MkvElem_Info)
    851           .serializeUnsignedInteger(MkvElem_TimecodeScale, CurSeg.uTimecodeScaleFactor)
    852           .serializeFloat(MkvElem_Segment_Duration, tcDuration)
    853           .serializeString(MkvElem_MuxingApp, szMux)
    854           .serializeString(MkvElem_WritingApp, szApp)
    855           .subEnd(MkvElem_Info);
    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  
    55
    66/*
    7  * Copyright (C) 2013-2017 Oracle Corporation
     7 * Copyright (C) 2013-2018 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    9191public:
    9292
    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;
    9598
    9699    /** Defines the WebM block flags data type. */
     
    140143    {
    141144        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)
    143146            : pTrack(a_pTrack)
    144147        {
    145             Data.tcPTSMs = 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;
    148151
    149152            if (Data.cb)
     
    169172        struct
    170173        {
    171             WebMTimecode   tcPTSMs;
    172             WebMTimecode  tcRelToClusterMs;
     174            WebMTimecodeAbs tcAbsPTSMs;
     175            WebMTimecodeRel tcRelToClusterMs;
    173176            void          *pv;
    174177            size_t         cb;
     
    212215     *  The key specifies a unique timecode, whereas the value
    213216     *  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;
    215218
    216219    /**
     
    220223    {
    221224        WebMQueue(void)
    222             : tcLastBlockWrittenMs(0)
    223             , tslastProcessedMs(0) { }
     225            : tcAbsLastBlockWrittenMs(0)
     226            , tsLastProcessedMs(0) { }
    224227
    225228        /** 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;
    229232        /** Time stamp (in ms) of when the queue was processed last. */
    230         uint64_t     tslastProcessedMs;
     233        uint64_t        tsLastProcessedMs;
    231234    };
    232235
     
    241244            , offUUID(a_offID)
    242245            , cTotalBlocks(0)
    243             , tcLastWrittenMs(0)
     246            , tcAbsLastWrittenMs(0)
    244247        {
    245248            uUUID = RTRandU32();
     
    281284        /** Total number of blocks. */
    282285        uint64_t            cTotalBlocks;
    283         /** Timecode (in ms) of last write. */
    284         WebMTimecode        tcLastWrittenMs;
     286        /** Absoute timecode (in ms) of last write. */
     287        WebMTimecodeAbs     tcAbsLastWrittenMs;
    285288    };
    286289
     
    290293    struct WebMCuePoint
    291294    {
    292         WebMCuePoint(WebMTrack *a_pTrack, uint64_t a_offCluster, WebMTimecode a_tcAbs)
     295        WebMCuePoint(WebMTrack *a_pTrack, uint64_t a_offCluster, WebMTimecodeAbs a_tcAbs)
    293296            : pTrack(a_pTrack)
    294297            , offCluster(a_offCluster), tcAbs(a_tcAbs) { }
    295298
    296299        /** Associated track. */
    297         WebMTrack   *pTrack;
     300        WebMTrack      *pTrack;
    298301        /** 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;
    302305    };
    303306
     
    311314            , offStart(0)
    312315            , fOpen(false)
    313             , tcStartMs(0)
     316            , tcAbsStartMs(0)
    314317            , cBlocks(0) { }
    315318
    316319        /** This cluster's ID. */
    317         uint64_t      uID;
     320        uint64_t        uID;
    318321        /** Absolute offset (in bytes) of this cluster.
    319322         *  Needed for seeking info table. */
    320         uint64_t      offStart;
     323        uint64_t        offStart;
    321324        /** 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;
    325328        /** Number of (simple) blocks in this cluster. */
    326         uint64_t      cBlocks;
     329        uint64_t        cBlocks;
    327330    };
    328331
     
    335338    {
    336339        WebMSegment(void)
    337             : tcStartMs(0)
    338             , tcLastWrittenMs(0)
     340            : tcAbsStartMs(0)
     341            , tcAbsLastWrittenMs(0)
    339342            , offStart(0)
    340343            , offInfo(0)
     
    364367        uint64_t                        uTimecodeScaleFactor;
    365368
    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;
    370373
    371374        /** Absolute offset (in bytes) of CurSeg. */
     
    407410    bool                        m_fInTracksSection;
    408411
    409     /** Size of timecodes in bytes. */
     412    /** Size of timecodes (in bytes). */
    410413    size_t                      m_cbTimecode;
    411414    /** Maximum value a timecode can have. */
     
    474477    int writeHeader(void);
    475478
    476     void writeSegSeekInfo(void);
     479    void writeSeekHeader(void);
    477480
    478481    int writeFooter(void);
     
    487490
    488491#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);
    490493#endif
    491494
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette