VirtualBox

Changeset 68451 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Aug 17, 2017 7:54:52 PM (7 years ago)
Author:
vboxsync
Message:

VideoRec: Main/EbmlWriter: More stuff for audio support.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-client/EbmlMkvIDs.h

    r68428 r68451  
    7070    MkvElem_PixelWidth              = 0xB0,
    7171    MkvElem_PixelHeight             = 0xBA,
    72     MkvElem_FrameRate               = 0x2383E3,
    7372
    7473    MkvElem_Audio                   = 0xE1,
  • trunk/src/VBox/Main/src-client/EbmlWriter.cpp

    r68372 r68451  
    1414 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
    1515 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
     16 */
     17
     18/**
     19 * For more information, see:
     20 * - https://w3c.github.io/media-source/webm-byte-stream-format.html
     21 * - https://www.webmproject.org/docs/container/#muxer-guidelines
    1622 */
    1723
     
    309315#define VBOX_WEBM_TIMECODESCALE_FACTOR_MS   1000000
    310316
     317/** Maximum time (in ms) a cluster can store. */
     318#define VBOX_WEBM_CLUSTER_MAX_LEN_MS        INT16_MAX
     319
     320/** Maximum time a block can store.
     321 *  With signed 16-bit timecodes and a default timecode scale of 1ms per unit this makes 65536ms. */
     322#define VBOX_WEBM_BLOCK_MAX_LEN_MS          UINT16_MAX
     323
    311324class WebMWriter_Impl
    312325{
    313     /**
    314      * Structure for keeping a cue entry.
    315      */
    316     struct WebMCueEntry
    317     {
    318         WebMCueEntry(uint32_t t, uint64_t l)
    319             : time(t), loc(l) {}
    320 
    321         uint32_t    time;
    322         uint64_t    loc;
    323     };
    324 
    325326    /**
    326327     * Track type enumeration.
     
    371372                 *  60           2880
    372373                 */
    373                 uint16_t csFrame;
     374                uint16_t framesPerBlock;
     375                /** How many milliseconds (ms) one written (simple) block represents. */
     376                uint16_t msPerBlock;
    374377            } Audio;
    375378        };
     
    389392
    390393    /**
     394     * Structure for keeping a cue point.
     395     */
     396    struct WebMCuePoint
     397    {
     398        WebMCuePoint(WebMTrack *a_pTrack, uint32_t a_tcClusterStart, uint64_t a_offClusterStart)
     399            : pTrack(a_pTrack)
     400            , tcClusterStart(a_tcClusterStart), offClusterStart(a_offClusterStart) {}
     401
     402        /** Associated track. */
     403        WebMTrack *pTrack;
     404        /** Start time code of the related cluster. */
     405        uint32_t   tcClusterStart;
     406        /** Start offset of the related cluster. */
     407        uint64_t   offClusterStart;
     408    };
     409
     410    /**
    391411     * Structure for keeping a WebM cluster entry.
    392412     */
     
    397417            , offCluster(0)
    398418            , fOpen(false)
    399             , tcStart(0)
    400             , tcLast(0)
    401             , cBlocks(0)
    402             , cbData(0) { }
     419            , tcStartMs(0)
     420            , tcEndMs(0)
     421            , cBlocks(0) { }
    403422
    404423        /** This cluster's ID. */
     
    409428        /** Whether this cluster element is opened currently. */
    410429        bool          fOpen;
    411         /** Timecode when starting this cluster. */
    412         uint64_t      tcStart;
    413         /** Timecode when this cluster was last touched. */
    414         uint64_t      tcLast;
     430        /** Timecode (in ms) when starting this cluster. */
     431        uint64_t      tcStartMs;
     432        /** Timecode (in ms) when this cluster ends. */
     433        uint64_t      tcEndMs;
    415434        /** Number of (simple) blocks in this cluster. */
    416435        uint64_t      cBlocks;
    417         /** Size (in bytes) of data already written. */
    418         uint64_t      cbData;
    419436    };
    420437
     
    459476        uint64_t                        offCues;
    460477        /** List of cue points. Needed for seeking table. */
    461         std::list<WebMCueEntry>         lstCues;
     478        std::list<WebMCuePoint>         lstCues;
    462479
    463480        /** Map of tracks.
     
    574591            return rc;
    575592
     593        const uint8_t uTrack = (uint8_t)CurSeg.mapTracks.size();
     594
    576595        m_Ebml.subStart(MkvElem_TrackEntry);
    577         m_Ebml.serializeUnsignedInteger(MkvElem_TrackNumber, (uint8_t)CurSeg.mapTracks.size());
    578         /** @todo Implement track's "Language" property? Currently this defaults to English ("eng"). */
    579 
    580         uint8_t uTrack = (uint8_t)CurSeg.mapTracks.size();
     596
     597        m_Ebml.serializeUnsignedInteger(MkvElem_TrackNumber, (uint8_t)uTrack);
     598        m_Ebml.serializeString         (MkvElem_Language,    "und" /* "Undefined"; see ISO-639-2. */);
     599        m_Ebml.serializeUnsignedInteger(MkvElem_FlagLacing,  (uint8_t)0);
    581600
    582601        WebMTrack *pTrack = new WebMTrack(WebMTrackType_Audio, uTrack, RTFileTell(m_Ebml.getFile()));
    583602
    584         pTrack->Audio.uHz     = uHz;
    585         pTrack->Audio.csFrame = pTrack->Audio.uHz / (1000 /* s in ms */ / 20 /* ms */); /** @todo 20 ms of audio data. Make this configurable? */
     603        pTrack->Audio.uHz            = uHz;
     604        pTrack->Audio.msPerBlock     = 20; /** Opus uses 20ms by default. Make this configurable? */
     605        pTrack->Audio.framesPerBlock = uHz / (1000 /* s in ms */ / pTrack->Audio.msPerBlock);
    586606
    587607        OpusPrivData opusPrivData(uHz, cChannels);
    588608
    589         LogFunc(("Opus @ %RU16Hz (Frame size is %RU16 samples / channel))\n", pTrack->Audio.uHz, pTrack->Audio.csFrame));
     609        LogFunc(("Opus @ %RU16Hz (%RU16ms + %RU16 frames per block)\n",
     610                 pTrack->Audio.uHz, pTrack->Audio.msPerBlock, pTrack->Audio.framesPerBlock));
    590611
    591612        m_Ebml.serializeUnsignedInteger(MkvElem_TrackUID,     pTrack->uUUID, 4)
     
    617638    {
    618639#ifdef VBOX_WITH_LIBVPX
     640        RT_NOREF(dbFPS);
     641
     642        const uint8_t uTrack = (uint8_t)CurSeg.mapTracks.size();
     643
    619644        m_Ebml.subStart(MkvElem_TrackEntry);
    620         m_Ebml.serializeUnsignedInteger(MkvElem_TrackNumber, (uint8_t)CurSeg.mapTracks.size());
    621 
    622         uint8_t uTrack = (uint8_t)CurSeg.mapTracks.size();
     645
     646        m_Ebml.serializeUnsignedInteger(MkvElem_TrackNumber, (uint8_t)uTrack);
     647        m_Ebml.serializeString         (MkvElem_Language,    "und" /* "Undefined"; see ISO-639-2. */);
     648        m_Ebml.serializeUnsignedInteger(MkvElem_FlagLacing,  (uint8_t)0);
    623649
    624650        WebMTrack *pTrack = new WebMTrack(WebMTrackType_Video, uTrack, RTFileTell(m_Ebml.getFile()));
     
    629655              .serializeString(MkvElem_CodecID,              "V_VP8")
    630656              .subStart(MkvElem_Video)
    631               .serializeUnsignedInteger(MkvElem_PixelWidth,  uWidth)
    632               .serializeUnsignedInteger(MkvElem_PixelHeight, uHeight)
    633               .serializeFloat(MkvElem_FrameRate,             dbFPS)
    634               .subEnd(MkvElem_Video)
    635               .subEnd(MkvElem_TrackEntry);
     657                  .serializeUnsignedInteger(MkvElem_PixelWidth,  uWidth)
     658                  .serializeUnsignedInteger(MkvElem_PixelHeight, uHeight)
     659              .subEnd(MkvElem_Video);
     660
     661        m_Ebml.subEnd(MkvElem_TrackEntry);
    636662
    637663        CurSeg.mapTracks[uTrack] = pTrack;
     
    713739        RT_NOREF(a_pTrack);
    714740
    715         /* Calculate the PTS of this frame in milliseconds. */
    716         uint64_t tcPTS = a_pPkt->data.frame.pts * 1000
     741        WebMCluster &Cluster = CurSeg.CurCluster;
     742
     743        /* Calculate the PTS of this frame (in ms). */
     744        uint64_t tcPTSMs = a_pPkt->data.frame.pts * 1000
    717745                         * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den;
    718746
    719         if (tcPTS <= CurSeg.CurCluster.tcLast)
    720             tcPTS = CurSeg.CurCluster.tcLast + 1;
    721 
    722         CurSeg.CurCluster.tcLast = tcPTS;
    723 
    724         if (CurSeg.CurCluster.tcStart == UINT64_MAX)
    725             CurSeg.CurCluster.tcStart = CurSeg.CurCluster.tcLast;
    726 
    727         /* Calculate the relative time of this block. */
    728         uint16_t tcBlock       = 0;
    729         bool     fClusterStart = false;
    730 
    731         /* Did we reach the maximum our timecode can hold? Use a new cluster then. */
    732         if (tcPTS - CurSeg.CurCluster.tcStart > m_uTimecodeMax)
     747        if (   tcPTSMs
     748            && tcPTSMs <= CurSeg.CurCluster.tcEndMs)
     749        {
     750            tcPTSMs = CurSeg.CurCluster.tcEndMs + 1;
     751        }
     752
     753        /* Whether to start a new cluster or not. */
     754        bool fClusterStart = false;
     755
     756        /* No blocks written yet? Start a new cluster. */
     757        if (a_pTrack->cTotalBlocks == 0)
    733758            fClusterStart = true;
    734         else
    735         {
    736             /* Calculate the block's timecode, which is relative to the current cluster's starting timecode. */
    737             tcBlock = static_cast<uint16_t>(tcPTS - CurSeg.CurCluster.tcStart);
     759
     760        /* Did we reach the maximum a cluster can hold? Use a new cluster then. */
     761        if (tcPTSMs > VBOX_WEBM_CLUSTER_MAX_LEN_MS)
     762        {
     763            tcPTSMs = 0;
     764
     765            fClusterStart = true;
    738766        }
    739767
     
    743771            || fKeyframe)
    744772        {
    745             WebMCluster &Cluster = CurSeg.CurCluster;
    746 
    747             a_pTrack->cTotalClusters++;
    748 
    749773            if (Cluster.fOpen) /* Close current cluster first. */
    750774            {
     
    753777            }
    754778
    755             tcBlock = 0;
    756 
    757             /* Open a new cluster. */
    758779            Cluster.fOpen      = true;
    759             Cluster.tcStart    = tcPTS;
     780            Cluster.uID        = a_pTrack->cTotalClusters;
     781            Cluster.tcStartMs  = tcPTSMs;
    760782            Cluster.offCluster = RTFileTell(m_Ebml.getFile());
    761783            Cluster.cBlocks    = 0;
    762             Cluster.cbData     = 0;
    763 
    764             LogFunc(("[C%RU64] Start @ tc=%RU64 off=%RU64\n", a_pTrack->cTotalClusters, Cluster.tcStart, Cluster.offCluster));
     784
     785            LogFunc(("[T%RU8C%RU64] Start @ %RU64ms / %RU64 bytes\n",
     786                     a_pTrack->uTrack, Cluster.uID, Cluster.tcStartMs, Cluster.offCluster));
    765787
    766788            m_Ebml.subStart(MkvElem_Cluster)
    767                   .serializeUnsignedInteger(MkvElem_Timecode, Cluster.tcStart);
     789                  .serializeUnsignedInteger(MkvElem_Timecode, Cluster.tcStartMs);
    768790
    769791            /* Save a cue point if this is a keyframe. */
    770792            if (fKeyframe)
    771793            {
    772                 WebMCueEntry cue(Cluster.tcStart, Cluster.offCluster);
     794                WebMCuePoint cue(a_pTrack, Cluster.tcStartMs, Cluster.offCluster);
    773795                CurSeg.lstCues.push_back(cue);
    774796            }
    775         }
    776 
    777         LogFunc(("tcPTS=%RU64, s=%RU64, e=%RU64\n", tcPTS, CurSeg.CurCluster.tcStart, CurSeg.CurCluster.tcLast));
     797
     798            a_pTrack->cTotalClusters++;
     799        }
     800
     801        Cluster.tcEndMs = tcPTSMs;
     802        Cluster.cBlocks++;
     803
     804        /* Calculate the block's timecode, which is relative to the cluster's starting timecode. */
     805        uint16_t tcBlockMs = static_cast<uint16_t>(tcPTSMs - Cluster.tcStartMs);
     806
     807        Log2Func(("tcPTSMs=%RU64, tcBlockMs=%RU64\n", tcPTSMs, tcBlockMs));
     808
     809        Log2Func(("[C%RU64] cBlocks=%RU64, tcStartMs=%RU64, tcEndMs=%RU64 (%zums)\n",
     810                  Cluster.uID, Cluster.cBlocks, Cluster.tcStartMs, Cluster.tcEndMs, Cluster.tcEndMs - Cluster.tcStartMs));
    778811
    779812        uint8_t fFlags = 0;
     
    783816            fFlags |= VBOX_WEBM_BLOCK_FLAG_INVISIBLE;
    784817
    785         return writeSimpleBlockInternal(a_pTrack, tcBlock, a_pPkt->data.frame.buf, a_pPkt->data.frame.sz, fFlags);
     818        return writeSimpleBlockInternal(a_pTrack, tcBlockMs, a_pPkt->data.frame.buf, a_pPkt->data.frame.sz, fFlags);
    786819    }
    787820#endif /* VBOX_WITH_LIBVPX */
     
    792825    {
    793826        AssertPtrReturn(a_pTrack, VERR_INVALID_POINTER);
    794         AssertPtrReturn(pvData, VERR_INVALID_POINTER);
    795         AssertReturn(cbData, VERR_INVALID_PARAMETER);
     827        AssertPtrReturn(pvData,   VERR_INVALID_POINTER);
     828        AssertReturn(cbData,      VERR_INVALID_PARAMETER);
    796829
    797830        RT_NOREF(uTimeStampMs);
     
    799832        WebMCluster &Cluster = CurSeg.CurCluster;
    800833
    801         /* Calculate the PTS. */
    802         /* Make sure to round the result. This is very important! */
    803         uint64_t tcPTSRaw = lround((CurSeg.uTimecodeScaleFactor * 1000 * Cluster.cbData) / a_pTrack->Audio.uHz);
    804 
    805         /* Calculate the absolute PTS. */
    806         uint64_t tcPTS = lround(tcPTSRaw / CurSeg.uTimecodeScaleFactor);
    807 
    808         if (Cluster.tcStart == UINT64_MAX)
    809             Cluster.tcStart = tcPTS;
    810 
    811         Cluster.tcLast = tcPTS;
    812 
    813         uint16_t tcBlock;
    814         bool     fClusterStart = false;
     834        /* Calculate the PTS of the current block:
     835         *
     836         * The "raw PTS" is the exact time of an object represented in nanoseconds):
     837         *     Raw Timecode = (Block timecode + Cluster timecode) * TimecodeScaleFactor
     838         */
     839        uint64_t tcPTSMs  = Cluster.tcStartMs + (Cluster.cBlocks * 20 /*ms */);
     840
     841        /* Whether to start a new cluster or not. */
     842        bool fClusterStart = false;
    815843
    816844        if (a_pTrack->cTotalBlocks == 0)
    817845            fClusterStart = true;
    818846
    819         /* Did we reach the maximum our timecode can hold? Use a new cluster then. */
    820         if (tcPTS - Cluster.tcStart > m_uTimecodeMax)
    821         {
    822             tcBlock = 0;
    823 
     847        /* Did we reach the maximum a cluster can hold? Use a new cluster then. */
     848        if (tcPTSMs > VBOX_WEBM_CLUSTER_MAX_LEN_MS)
    824849            fClusterStart = true;
    825         }
    826         else
    827         {
    828             /* Calculate the block's timecode, which is relative to the Cluster timecode. */
    829             tcBlock = static_cast<uint16_t>(tcPTS - Cluster.tcStart);
    830         }
    831850
    832851        if (fClusterStart)
    833852        {
    834             if (Cluster.fOpen) /* Close current cluster first. */
     853            if (Cluster.fOpen) /* Close current clusters first. */
    835854            {
    836855                m_Ebml.subEnd(MkvElem_Cluster);
     
    838857            }
    839858
    840             tcBlock = 0;
    841 
    842859            Cluster.fOpen      = true;
    843860            Cluster.uID        = a_pTrack->cTotalClusters;
    844             Cluster.tcStart    = tcPTS;
    845             Cluster.tcLast     = Cluster.tcStart;
     861            Cluster.tcStartMs  = Cluster.tcEndMs;
    846862            Cluster.offCluster = RTFileTell(m_Ebml.getFile());
    847863            Cluster.cBlocks    = 0;
    848             Cluster.cbData     = 0;
    849 
    850             LogFunc(("[C%RU64] Start @ tc=%RU64 off=%RU64\n", Cluster.uID, Cluster.tcStart, Cluster.offCluster));
     864
     865            LogFunc(("[T%RU8C%RU64] Start @ %RU64ms / %RU64 bytes\n",
     866                     a_pTrack->uTrack, Cluster.uID, Cluster.tcStartMs, Cluster.offCluster));
     867
     868            /* As all audio frame as key frames, insert a new cue point when a new cluster starts. */
     869            WebMCuePoint cue(a_pTrack, Cluster.tcStartMs, Cluster.offCluster);
     870            CurSeg.lstCues.push_back(cue);
    851871
    852872            m_Ebml.subStart(MkvElem_Cluster)
    853                   .serializeUnsignedInteger(MkvElem_Timecode, Cluster.tcStart);
     873                  .serializeUnsignedInteger(MkvElem_Timecode, Cluster.tcStartMs);
    854874
    855875            a_pTrack->cTotalClusters++;
    856876        }
    857877
    858         Cluster.cBlocks += 1;
    859         Cluster.cbData  += cbData;
    860 
    861         Log2Func(("[C%RU64] tcBlock=%RU64, tcClusterStart=%RU64, tcClusterLast=%RU64, cbData=%zu\n",
    862                   Cluster.uID, tcBlock, CurSeg.CurCluster.tcStart, CurSeg.CurCluster.tcLast, CurSeg.CurCluster.cbData));
    863 
    864         return writeSimpleBlockInternal(a_pTrack, tcBlock, pvData, cbData, VBOX_WEBM_BLOCK_FLAG_KEY_FRAME);
     878        Cluster.tcEndMs = tcPTSMs;
     879        Cluster.cBlocks++;
     880
     881        /* Calculate the block's timecode, which is relative to the cluster's starting timecode. */
     882        uint16_t tcBlockMs = static_cast<uint16_t>(tcPTSMs - Cluster.tcStartMs);
     883
     884        Log2Func(("tcPTSMs=%RU64, tcBlockMs=%RU64\n", tcPTSMs, tcBlockMs));
     885
     886        Log2Func(("[C%RU64] cBlocks=%RU64, tcStartMs=%RU64, tcEndMs=%RU64 (%zums)\n",
     887                  Cluster.uID, Cluster.cBlocks, Cluster.tcStartMs, Cluster.tcEndMs, Cluster.tcEndMs - Cluster.tcStartMs));
     888
     889        return writeSimpleBlockInternal(a_pTrack, tcBlockMs,
     890                                        pvData, cbData, VBOX_WEBM_BLOCK_FLAG_KEY_FRAME);
    865891    }
    866892#endif /* VBOX_WITH_LIBOPUS */
     
    943969         * Write Cues element.
    944970         */
    945         if (CurSeg.lstCues.size())
    946         {
    947             LogFunc(("Cues @ %RU64\n", RTFileTell(m_Ebml.getFile())));
    948 
    949             CurSeg.offCues = RTFileTell(m_Ebml.getFile());
    950 
    951             m_Ebml.subStart(MkvElem_Cues);
    952 
    953             std::list<WebMCueEntry>::iterator itCuePoint = CurSeg.lstCues.begin();
    954             while (itCuePoint != CurSeg.lstCues.end())
    955             {
    956                 LogFunc(("CuePoint @ %RU64\n", RTFileTell(m_Ebml.getFile())));
    957 
    958                 m_Ebml.subStart(MkvElem_CuePoint)
    959                       .serializeUnsignedInteger(MkvElem_CueTime, itCuePoint->time)
     971        LogFunc(("Cues @ %RU64\n", RTFileTell(m_Ebml.getFile())));
     972
     973        CurSeg.offCues = RTFileTell(m_Ebml.getFile());
     974
     975        m_Ebml.subStart(MkvElem_Cues);
     976
     977        std::list<WebMCuePoint>::iterator itCuePoint = CurSeg.lstCues.begin();
     978        while (itCuePoint != CurSeg.lstCues.end())
     979        {
     980            /* Sanity. */
     981            AssertPtr(itCuePoint->pTrack);
     982
     983            const uint64_t uClusterPos = itCuePoint->offClusterStart - CurSeg.offStart;
     984
     985            LogFunc(("CuePoint @ %RU64: Track #%RU8 (Time %RU64, Pos %RU64)\n",
     986                     RTFileTell(m_Ebml.getFile()), itCuePoint->pTrack->uTrack, itCuePoint->tcClusterStart, uClusterPos));
     987
     988            m_Ebml.subStart(MkvElem_CuePoint)
     989                      .serializeUnsignedInteger(MkvElem_CueTime, itCuePoint->tcClusterStart)
    960990                      .subStart(MkvElem_CueTrackPositions)
    961                       .serializeUnsignedInteger(MkvElem_CueTrack, 1)
    962                       .serializeUnsignedInteger(MkvElem_CueClusterPosition, itCuePoint->loc - CurSeg.offStart, 8)
    963                       .subEnd(MkvElem_CueTrackPositions)
    964                       .subEnd(MkvElem_CuePoint);
    965 
    966                 itCuePoint++;
    967             }
    968 
    969             m_Ebml.subEnd(MkvElem_Cues);
    970         }
    971 
     991                          .serializeUnsignedInteger(MkvElem_CueTrack,           itCuePoint->pTrack->uTrack)
     992                          .serializeUnsignedInteger(MkvElem_CueClusterPosition, uClusterPos, 8)
     993                  .subEnd(MkvElem_CueTrackPositions)
     994                  .subEnd(MkvElem_CuePoint);
     995
     996            itCuePoint++;
     997        }
     998
     999        m_Ebml.subEnd(MkvElem_Cues);
    9721000        m_Ebml.subEnd(MkvElem_Segment);
    9731001
     
    10231051              .subEnd(MkvElem_Seek);
    10241052
    1025         if (CurSeg.lstCues.size())
    1026         {
    1027             Assert(CurSeg.offCues - CurSeg.offStart > 0); /* Sanity. */
    1028 
    1029             m_Ebml.subStart(MkvElem_Seek)
    1030                   .serializeUnsignedInteger(MkvElem_SeekID, MkvElem_Cues)
    1031                   .serializeUnsignedInteger(MkvElem_SeekPosition, CurSeg.offCues - CurSeg.offStart, 8)
    1032                   .subEnd(MkvElem_Seek);
    1033         }
     1053        Assert(CurSeg.offCues - CurSeg.offStart > 0); /* Sanity. */
     1054
     1055        m_Ebml.subStart(MkvElem_Seek)
     1056              .serializeUnsignedInteger(MkvElem_SeekID, MkvElem_Cues)
     1057              .serializeUnsignedInteger(MkvElem_SeekPosition, CurSeg.offCues - CurSeg.offStart, 8)
     1058              .subEnd(MkvElem_Seek);
    10341059
    10351060        m_Ebml.subStart(MkvElem_Seek)
     
    10591084        m_Ebml.subStart(MkvElem_Info)
    10601085              .serializeUnsignedInteger(MkvElem_TimecodeScale, CurSeg.uTimecodeScaleFactor)
    1061               .serializeFloat(MkvElem_Segment_Duration, CurSeg.tcEnd /*+ iFrameTime*/ - CurSeg.tcStart)
     1086              .serializeFloat(MkvElem_Segment_Duration, CurSeg.tcEnd - CurSeg.tcStart)
    10621087              .serializeString(MkvElem_MuxingApp, szMux)
    10631088              .serializeString(MkvElem_WritingApp, szApp)
  • trunk/src/VBox/Main/src-client/EbmlWriter.h

    r68332 r68451  
    4949    {
    5050        /** No audio codec specified. */
    51         AudioCodec_Unknown = 0,
     51        AudioCodec_None = 0,
    5252        /** Opus. */
    53         AudioCodec_Opus    = 1
     53        AudioCodec_Opus = 1
    5454    };
    5555
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