VirtualBox

Changeset 96260 in vbox


Ignore:
Timestamp:
Aug 17, 2022 12:02:46 PM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
153072
Message:

Recording/Main: Greatly reduced workload spent in the recording driver's async I/O thread by also encoding the audio data in the dedicated recording thread (using two different block maps, see comments for details). bugref:10275

Location:
trunk/src/VBox/Main
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/Recording.h

    r96229 r96260  
    8383    RecordingStream *getStreamInternal(unsigned uScreen) const;
    8484
    85     int writeCommonData(PRECORDINGCODEC pCodec, const void *pvData, size_t cbData, uint64_t msAbsPTS, uint32_t uFlags);
     85    int processCommonData(RecordingBlockMap &mapCommon, RTMSINTERVAL msTimeout);
     86    int writeCommonData(RecordingBlockMap &mapCommon, PRECORDINGCODEC pCodec, const void *pvData, size_t cbData, uint64_t msAbsPTS, uint32_t uFlags);
    8687
    8788    int lock(void);
     
    145146    RECORDINGCODEC               CodecAudio;
    146147#endif /* VBOX_WITH_AUDIO_RECORDING */
    147     /** Block map of common blocks which need to get multiplexed
    148      *  to all recording streams. This common block maps should help
    149      *  reducing the time spent in EMT and avoid doing the (expensive)
    150      *  multiplexing work in there.
     148    /** Block map of raw common data blocks which need to get encoded first. */
     149    RecordingBlockMap            mapBlocksRaw;
     150    /** Block map of encoded common blocks.
     151     *
     152     *  Only do the encoding of common data blocks only once and then multiplex
     153     *  the encoded data to all affected recording streams.
     154     *
     155     *  This avoids doing the (expensive) encoding + multiplexing work in other
     156     *  threads like EMT / audio async I/O..
    151157     *
    152158     *  For now this only affects audio, e.g. all recording streams
    153159     *  need to have the same audio data at a specific point in time. */
    154     RecordingBlockMap            mapBlocksCommon;
     160    RecordingBlockMap            mapBlocksEncoded;
    155161};
    156162#endif /* !MAIN_INCLUDED_Recording_h */
  • trunk/src/VBox/Main/include/RecordingStream.h

    r96229 r96260  
    120120
    121121    int Process(RecordingBlockMap &mapBlocksCommon);
     122    int SendAudioFrame(const void *pvData, size_t cbData, uint64_t msTimestamp);
    122123    int SendVideoFrame(uint32_t x, uint32_t y, uint32_t uPixelFormat, uint32_t uBPP, uint32_t uBytesPerLine,
    123124                       uint32_t uSrcWidth, uint32_t uSrcHeight, uint8_t *puSrcData, uint64_t msTimestamp);
  • trunk/src/VBox/Main/src-client/DrvAudioRec.cpp

    r96229 r96260  
    171171typedef struct AVRECSINK
    172172{
    173     /** Pointer (weak) to audio codec to use. */
    174     PRECORDINGCODEC      pCodec;
     173    /** Pointer (weak) to recording stream to bind to. */
     174    RecordingStream     *pRecStream;
    175175    /** Container data to use for data processing. */
    176176    AVRECCONTAINER       Con;
     
    323323 */
    324324static int avRecCreateStreamOut(PDRVAUDIORECORDING pThis, PAVRECSTREAM pStreamAV,
    325                                 PAVRECSINK pSink, PRECORDINGCODEC pCodec, PCPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     325                                PAVRECSINK pSink, PCPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    326326{
    327327    AssertPtrReturn(pThis,     VERR_INVALID_POINTER);
    328328    AssertPtrReturn(pStreamAV, VERR_INVALID_POINTER);
    329329    AssertPtrReturn(pSink,     VERR_INVALID_POINTER);
    330     AssertPtrReturn(pCodec,    VERR_INVALID_POINTER);
    331330    AssertPtrReturn(pCfgReq,   VERR_INVALID_POINTER);
    332331    AssertPtrReturn(pCfgAcq,   VERR_INVALID_POINTER);
     
    338337        return VERR_NOT_SUPPORTED;
    339338    }
     339
     340    PRECORDINGCODEC pCodec = pSink->pRecStream->GetAudioCodec();
    340341
    341342    /* Stuff which has to be set by now. */
     
    357358            /* Make sure to let the driver backend know that we need the audio data in
    358359             * a specific sampling rate the codec is optimized for. */
    359 /** @todo r=bird: pCfgAcq->Props isn't initialized at all, except for uHz... */
    360             pCfgAcq->Props.uHz         = pCodec->Parms.Audio.PCMProps.uHz;
    361 //                pCfgAcq->Props.cShift      = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfgAcq->Props.cbSample, pCfgAcq->Props.cChannels);
    362 
    363             /* Every Opus frame marks a period for now. Optimize this later. */
     360            pCfgAcq->Props = pCodec->Parms.Audio.PCMProps;
     361
     362            /* Every codec frame marks a period for now. Optimize this later. */
    364363            pCfgAcq->Backend.cFramesPeriod       = PDMAudioPropsMilliToFrames(&pCfgAcq->Props, pCodec->Parms.msFrame);
    365             pCfgAcq->Backend.cFramesBufferSize   = PDMAudioPropsMilliToFrames(&pCfgAcq->Props, 100 /*ms*/); /** @todo Make this configurable. */
    366             pCfgAcq->Backend.cFramesPreBuffering = pCfgAcq->Backend.cFramesPeriod * 2;
     364            pCfgAcq->Backend.cFramesBufferSize   = pCfgAcq->Backend.cFramesPeriod * 2;
     365            pCfgAcq->Backend.cFramesPreBuffering = pCfgAcq->Backend.cFramesPeriod;
    367366        }
    368367        else
     
    394393    PAVRECSINK pSink = &pThis->Sink;
    395394
    396     int vrc = avRecCreateStreamOut(pThis, pStreamAV, pSink, pSink->pCodec, pCfgReq, pCfgAcq);
     395    int vrc = avRecCreateStreamOut(pThis, pStreamAV, pSink, pCfgReq, pCfgAcq);
    397396    PDMAudioStrmCfgCopy(&pStreamAV->Cfg, pCfgAcq);
    398397
     
    516515static DECLCALLBACK(uint32_t) drvAudioVideoRecHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    517516{
    518     RT_NOREF(pInterface, pStream);
    519     return UINT32_MAX;
     517    RT_NOREF(pInterface);
     518    PAVRECSTREAM pStreamAV = (PAVRECSTREAM)pStream;
     519
     520    RecordingStream *pRecStream = pStreamAV->pSink->pRecStream;
     521    PRECORDINGCODEC  pCodec     = pRecStream->GetAudioCodec();
     522
     523    return pCodec->Parms.cbFrame;
    520524}
    521525
     
    540544    PAVRECSINK pSink       = pStreamAV->pSink;
    541545    AssertPtr(pSink);
    542     PRECORDINGCODEC pCodec = pSink->pCodec;
    543     AssertPtr(pCodec);
    544546    PRTCIRCBUF pCircBuf    = pStreamAV->pCircBuf;
    545547    AssertPtr(pCircBuf);
    546548
    547     uint32_t cbToWrite = cbBuf;
     549    uint32_t cbToWrite = RT_MIN(cbBuf, RTCircBufFree(pCircBuf));
     550    AssertReturn(cbToWrite, VERR_BUFFER_OVERFLOW);
    548551
    549552    /*
    550553     * Write as much as we can into our internal ring buffer.
    551554     */
    552     while (   cbToWrite > 0
    553            && RTCircBufFree(pCircBuf))
     555    while (cbToWrite)
    554556    {
    555557        void  *pvCircBuf = NULL;
     
    557559        RTCircBufAcquireWriteBlock(pCircBuf, cbToWrite, &pvCircBuf, &cbCircBuf);
    558560
    559         if (cbCircBuf)
    560         {
    561             memcpy(pvCircBuf, (uint8_t *)pvBuf + cbWrittenTotal, cbCircBuf),
    562             cbWrittenTotal += (uint32_t)cbCircBuf;
    563             Assert(cbToWrite >= cbCircBuf);
    564             cbToWrite      -= (uint32_t)cbCircBuf;
    565         }
     561        Log3Func(("cbToWrite=%RU32, cbCircBuf=%zu\n", cbToWrite, cbCircBuf));
     562
     563        memcpy(pvCircBuf, (uint8_t *)pvBuf + cbWrittenTotal, cbCircBuf),
     564        cbWrittenTotal += (uint32_t)cbCircBuf;
     565        Assert(cbWrittenTotal <= cbBuf);
     566        Assert(cbToWrite >= cbCircBuf);
     567        cbToWrite      -= (uint32_t)cbCircBuf;
    566568
    567569        RTCircBufReleaseWriteBlock(pCircBuf, cbCircBuf);
    568         AssertBreak(cbCircBuf);
    569     }
    570 
    571     /*
    572      * Process our internal ring buffer and encode the data.
    573      */
    574 
    575     /* Only encode data if we have data for at least one full frame. */
    576     while (RTCircBufUsed(pCircBuf) >= pCodec->Parms.cbFrame)
    577     {
    578         LogFunc(("cbAvail=%zu, csFrame=%RU32, cbFrame=%RU32\n",
    579                  RTCircBufUsed(pCircBuf), pCodec->Parms.csFrame, pCodec->Parms.cbFrame));
    580 
    581         /** @todo Can we encode more than a frame at a time? Optimize this! */
    582         uint32_t const cbFramesToEncode = pCodec->Parms.cbFrame; /* 1 frame. */
    583 
     570    }
     571
     572    RecordingStream *pRecStream = pStreamAV->pSink->pRecStream;
     573    PRECORDINGCODEC  pCodec     = pRecStream->GetAudioCodec();
     574
     575    /*
     576     * Process our internal ring buffer and send the obtained audio data to our encoding thread.
     577    */
     578    cbToWrite = RTCircBufUsed(pCircBuf);
     579
     580    /** @todo Can we encode more than a frame at a time? Optimize this! */
     581    uint32_t const cbFrame = pCodec->Parms.cbFrame;
     582
     583    /* Only encode data if we have data for at least one full codec frame. */
     584    while (cbToWrite >= cbFrame)
     585    {
    584586        uint32_t cbSrc = 0;
    585         while (cbSrc < cbFramesToEncode)
     587        do
    586588        {
    587589            void  *pvCircBuf = NULL;
    588590            size_t cbCircBuf = 0;
    589             RTCircBufAcquireReadBlock(pCircBuf, cbFramesToEncode - cbSrc, &pvCircBuf, &cbCircBuf);
    590 
    591             if (cbCircBuf)
     591            RTCircBufAcquireReadBlock(pCircBuf, cbFrame - cbSrc, &pvCircBuf, &cbCircBuf);
     592
     593            Log3Func(("cbSrc=%RU32, cbCircBuf=%zu\n", cbSrc, cbCircBuf));
     594
     595            memcpy((uint8_t *)pStreamAV->pvSrcBuf + cbSrc, pvCircBuf, cbCircBuf);
     596
     597            cbSrc += (uint32_t)cbCircBuf;
     598            Assert(cbSrc <= pStreamAV->cbSrcBuf);
     599            Assert(cbSrc <= cbFrame);
     600
     601            RTCircBufReleaseReadBlock(pCircBuf, cbCircBuf);
     602
     603            if (cbSrc == cbFrame) /* Only send full codec frames. */
    592604            {
    593                 memcpy((uint8_t *)pStreamAV->pvSrcBuf + cbSrc, pvCircBuf, cbCircBuf);
    594 
    595                 cbSrc += (uint32_t)cbCircBuf;
    596                 Assert(cbSrc <= pStreamAV->cbSrcBuf);
     605                vrc = pRecStream->SendAudioFrame(pStreamAV->pvSrcBuf, cbSrc, 0);
     606                if (RT_FAILURE(vrc))
     607                    break;
    597608            }
    598609
    599             RTCircBufReleaseReadBlock(pCircBuf, cbCircBuf);
    600             AssertBreak(cbCircBuf);
    601         }
    602 
    603         Assert(cbSrc == cbFramesToEncode);
    604 
    605         RECORDINGFRAME Frame;
    606         Frame.Audio.cbBuf = cbFramesToEncode;
    607         Frame.Audio.pvBuf = (uint8_t *)pStreamAV->pvSrcBuf;
    608 
    609         size_t cEncoded /* Blocks encoded */, cbEncoded /* Bytes encoded */;
    610         vrc = recordingCodecEncode(pSink->pCodec,
    611                                    /* Source */
    612                                    &Frame, &cEncoded, &cbEncoded);
    613         if (   RT_SUCCESS(vrc)
    614             && cEncoded)
    615         {
    616             Assert(cbEncoded);
    617         }
    618         else if (RT_FAILURE(vrc)) /* Something went wrong -- report all bytes as being processed, to not hold up others. */
    619             cbWrittenTotal = cbBuf;
     610        } while (cbSrc < cbFrame);
     611
     612        Assert(cbToWrite >= cbFrame);
     613        cbToWrite -= cbFrame;
    620614
    621615        if (RT_FAILURE(vrc))
     
    626620    *pcbWritten = cbWrittenTotal;
    627621
    628     LogFlowFunc(("csReadTotal=%RU32, vrc=%Rrc\n", cbWrittenTotal, vrc));
     622    LogFlowFunc(("cbBuf=%RU32, cbWrittenTotal=%RU32, vrc=%Rrc\n", cbBuf, cbWrittenTotal, vrc));
    629623    return VINF_SUCCESS; /* Don't propagate encoding errors to the caller. */
    630624}
     
    685679    AssertPtrReturnVoid(pSink);
    686680
    687     pSink->pCodec = NULL;
     681    pSink->pRecStream = NULL;
    688682
    689683    switch (pSink->Con.Parms.enmType)
     
    768762 * @param   pSink               Sink to initialize.
    769763 * @param   pConParms           Container parameters to set.
    770  * @param   pCodec              Codec to use.
    771  */
    772 static int avRecSinkInit(PDRVAUDIORECORDING pThis, PAVRECSINK pSink, PAVRECCONTAINERPARMS pConParms, PRECORDINGCODEC pCodec)
    773 {
    774     AssertReturn(pCodec->Parms.enmType == RECORDINGCODECTYPE_AUDIO, VERR_INVALID_PARAMETER);
     764 * @param   pStream             Recording stream to asssign sink to.
     765 */
     766static int avRecSinkInit(PDRVAUDIORECORDING pThis, PAVRECSINK pSink, PAVRECCONTAINERPARMS pConParms, RecordingStream *pStream)
     767{
     768    pSink->pRecStream = pStream;
    775769
    776770    int vrc = VINF_SUCCESS;
    777 
    778     pSink->pCodec = pCodec;
    779771
    780772    /*
     
    798790            case AVRECCONTAINERTYPE_WEBM:
    799791            {
     792        #if 0
    800793                /* If we only record audio, create our own WebM writer instance here. */
    801794                if (!pSink->Con.WebM.pWebM) /* Do we already have our WebM writer instance? */
     
    828821                }
    829822                break;
     823        #endif
    830824            }
    831825
     
    948942     * Obtain the recording context.
    949943     */
    950     pThis->pRecCtx =  pConsole->i_recordingGetContext();
     944    pThis->pRecCtx = pConsole->i_recordingGetContext();
    951945    AssertPtrReturn(pThis->pRecCtx, VERR_INVALID_POINTER);
    952946
     
    957951    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    958952
    959     const PRECORDINGCODEC pCodec = pStream->GetAudioCodec();
    960     AssertPtrReturn(pCodec, VERR_INVALID_POINTER);
    961 
    962953    /*
    963954     * Init the recording sink.
    964955     */
    965     vrc = avRecSinkInit(pThis, &pThis->Sink, &pThis->ContainerParms, pCodec);
     956    vrc = avRecSinkInit(pThis, &pThis->Sink, &pThis->ContainerParms, pStream);
    966957    if (RT_SUCCESS(vrc))
    967958        LogRel2(("Recording: Audio recording driver initialized\n"));
  • trunk/src/VBox/Main/src-client/Recording.cpp

    r96230 r96260  
    115115    RTThreadUserSignal(hThreadSelf);
    116116
    117     LogFunc(("Thread started\n"));
     117    LogRel2(("Recording: Thread started\n"));
    118118
    119119    for (;;)
     
    123123
    124124        Log2Func(("Processing %zu streams\n", pThis->vecStreams.size()));
     125
     126        /* Process common raw blocks (data which not has been encoded yet). */
     127        vrc = pThis->processCommonData(pThis->mapBlocksRaw, 100 /* ms timeout */);
    125128
    126129        /** @todo r=andy This is inefficient -- as we already wake up this thread
     
    132135            RecordingStream *pStream = (*itStream);
    133136
    134             vrc = pStream->Process(pThis->mapBlocksCommon);
     137            /* Hand-in common encoded blocks. */
     138            vrc = pStream->Process(pThis->mapBlocksEncoded);
    135139            if (RT_FAILURE(vrc))
    136140            {
     
    155159    } /* for */
    156160
    157     LogFunc(("Thread ended\n"));
     161    LogRel2(("Recording: Thread ended\n"));
    158162    return VINF_SUCCESS;
    159163}
     
    170174
    171175/**
    172  * Writes block data which are common (shared) between all streams.
    173  *
    174  * To save time spent in EMT or other important threads (such as audio async I/O),
    175  * do the required audio multiplexing in the encoding thread.
     176 * Worker function for processing common block data.
     177 *
     178 * @returns VBox status code.
     179 * @param   mapCommon           Common block map to handle.
     180 * @param   msTimeout           Timeout to use for maximum time spending to process data.
     181 *                              Use RT_INDEFINITE_WAIT for processing all data.
     182 *
     183 * @note    Runs in recording thread.
     184 */
     185int RecordingContext::processCommonData(RecordingBlockMap &mapCommon, RTMSINTERVAL msTimeout)
     186{
     187    Log2Func(("Processing %zu common blocks (%RU32ms timeout)\n", mapCommon.size(), msTimeout));
     188
     189    int vrc = VINF_SUCCESS;
     190
     191    uint64_t const msStart = RTTimeMilliTS();
     192    RecordingBlockMap::iterator itCommonBlocks = mapCommon.begin();
     193    while (itCommonBlocks != mapCommon.end())
     194    {
     195        RecordingBlockList::iterator itBlock = itCommonBlocks->second->List.begin();
     196        while (itBlock != itCommonBlocks->second->List.end())
     197        {
     198            RecordingBlock *pBlockCommon = (RecordingBlock *)(*itBlock);
     199            switch (pBlockCommon->enmType)
     200            {
     201#ifdef VBOX_WITH_AUDIO_RECORDING
     202                case RECORDINGBLOCKTYPE_AUDIO:
     203                {
     204                    PRECORDINGAUDIOFRAME pAudioFrame = (PRECORDINGAUDIOFRAME)pBlockCommon->pvData;
     205
     206                    RECORDINGFRAME Frame;
     207                    Frame.msTimestamp = pBlockCommon->msTimestamp;
     208                    Frame.Audio.pvBuf = pAudioFrame->pvBuf;
     209                    Frame.Audio.cbBuf = pAudioFrame->cbBuf;
     210
     211                    vrc = recordingCodecEncode(&this->CodecAudio, &Frame, NULL, NULL);
     212                    break;
     213                }
     214#endif /* VBOX_WITH_AUDIO_RECORDING */
     215                default:
     216                    /* Skip unknown stuff. */
     217                    break;
     218            }
     219
     220            itCommonBlocks->second->List.erase(itBlock);
     221            delete pBlockCommon;
     222            itBlock = itCommonBlocks->second->List.begin();
     223
     224            if (RT_FAILURE(vrc) || RTTimeMilliTS() > msStart + msTimeout)
     225                break;
     226        }
     227
     228        /* If no entries are left over in the block map, remove it altogether. */
     229        if (itCommonBlocks->second->List.empty())
     230        {
     231            delete itCommonBlocks->second;
     232            mapCommon.erase(itCommonBlocks);
     233            itCommonBlocks = mapCommon.begin();
     234        }
     235        else
     236            ++itCommonBlocks;
     237
     238        if (RT_FAILURE(vrc))
     239            break;
     240    }
     241
     242    return vrc;
     243}
     244
     245/**
     246 * Writes common block data (i.e. shared / the same) in all streams.
    176247 *
    177248 * The multiplexing is needed to supply all recorded (enabled) screens with the same
     
    179250 *
    180251 * Currently this only is being used for audio data.
    181  */
    182 int RecordingContext::writeCommonData(PRECORDINGCODEC pCodec, const void *pvData, size_t cbData,
    183                                       uint64_t msAbsPTS, uint32_t uFlags)
     252 *
     253 * @returns VBox status code.
     254 * @param   mapCommon       Common block map to write data to.
     255 * @param   pCodec          Pointer to codec instance which has written the data.
     256 * @param   pvData          Pointer to written data (encoded).
     257 * @param   cbData          Size (in bytes) of \a pvData.
     258 * @param   msTimestamp     Absolute PTS (in ms) of the written data.
     259 * @param   uFlags          Encoding flags of type RECORDINGCODEC_ENC_F_XXX.
     260 */
     261int RecordingContext::writeCommonData(RecordingBlockMap &mapCommon, PRECORDINGCODEC pCodec, const void *pvData, size_t cbData,
     262                                      uint64_t msTimestamp, uint32_t uFlags)
    184263{
    185264    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
    186265    AssertReturn(cbData, VERR_INVALID_PARAMETER);
    187266
    188     LogFlowFunc(("pCodec=%p, cbData=%zu, msAbsPTS=%zu, uFlags=%#x\n",
    189                  pCodec, cbData, msAbsPTS, uFlags));
     267    LogFlowFunc(("pCodec=%p, cbData=%zu, msTimestamp=%zu, uFlags=%#x\n",
     268                 pCodec, cbData, msTimestamp, uFlags));
    190269
    191270    /** @todo Optimize this! Three allocations in here! */
     
    215294            pBlock->cbData      = sizeof(RECORDINGAUDIOFRAME) + cbData;
    216295            pBlock->cRefs       = this->cStreamsEnabled;
    217             pBlock->msTimestamp = msAbsPTS;
     296            pBlock->msTimestamp = msTimestamp;
    218297            pBlock->uFlags      = uFlags;
    219298
     
    232311    try
    233312    {
    234         RecordingBlockMap::iterator itBlocks = this->mapBlocksCommon.find(msAbsPTS);
    235         if (itBlocks == this->mapBlocksCommon.end())
     313        RecordingBlockMap::iterator itBlocks = mapCommon.find(msTimestamp);
     314        if (itBlocks == mapCommon.end())
    236315        {
    237316            RecordingBlocks *pRecordingBlocks = new RecordingBlocks();
    238317            pRecordingBlocks->List.push_back(pBlock);
    239318
    240             this->mapBlocksCommon.insert(std::make_pair(msAbsPTS, pRecordingBlocks));
     319            mapCommon.insert(std::make_pair(msTimestamp, pRecordingBlocks));
    241320        }
    242321        else
     
    261340#ifdef VBOX_WITH_AUDIO_RECORDING
    262341/**
    263  * Callback function for taking care of multiplexing the encoded audio data to all connected streams.
     342 * Callback function for writing encoded audio data into the common encoded block map.
     343 *
     344 * This is called by the audio codec when finishing encoding audio data.
    264345 *
    265346 * @copydoc RECORDINGCODECCALLBACKS::pfnWriteData
     
    269350                                                                uint64_t msAbsPTS, uint32_t uFlags, void *pvUser)
    270351{
    271 #if 0
    272352    RecordingContext *pThis = (RecordingContext *)pvUser;
    273 
    274     int vrc = VINF_SUCCESS;
    275 
    276     RecordingStreams::iterator itStream = pThis->vecStreams.begin();
    277     while (itStream != pThis->vecStreams.end())
    278     {
    279         RecordingStream *pStream = (*itStream);
    280 
    281         LogFlowFunc(("pStream=%p\n", pStream));
    282 
    283         if (pStream->GetConfig().isFeatureEnabled(RecordingFeature_Audio)) /** @todo Optimize this! Use a dedicated stream group for video-only / audio-only streams. */
    284         {
    285             vrc = RecordingStream::codecWriteDataCallback(pCodec, pvData, cbData, msAbsPTS, uFlags, pStream);
    286             if (RT_FAILURE(vrc))
    287             {
    288                 LogRel(("Recording: Calling audio write callback for stream #%RU16 failed (%Rrc)\n", pStream->GetID(), vrc));
    289                 break;
    290             }
    291         }
    292 
    293         ++itStream;
    294     }
    295 
    296     return vrc;
    297 #else
    298     RecordingContext *pThis = (RecordingContext *)pvUser;
    299 
    300     return pThis->writeCommonData(pCodec, pvData, cbData, msAbsPTS, uFlags);
    301 #endif
     353    return pThis->writeCommonData(pThis->mapBlocksEncoded, pCodec, pvData, cbData, msAbsPTS, uFlags);
    302354}
    303355
     
    503555    /* Sanity. */
    504556    Assert(this->vecStreams.empty());
    505     Assert(this->mapBlocksCommon.size() == 0);
     557    Assert(this->mapBlocksRaw.size() == 0);
     558    Assert(this->mapBlocksEncoded.size() == 0);
    506559
    507560    this->enmState = RECORDINGSTS_UNINITIALIZED;
     
    779832 * Sends an audio frame to the video encoding thread.
    780833 *
    781  * @thread  EMT
    782  *
    783834 * @returns VBox status code.
    784835 * @param   pvData              Audio frame data to send.
     
    789840{
    790841#ifdef VBOX_WITH_AUDIO_RECORDING
    791     return writeCommonData(&this->CodecAudio, pvData, cbData, msTimestamp, RECORDINGCODEC_ENC_F_BLOCK_IS_KEY);
     842    return writeCommonData(this->mapBlocksRaw, &this->CodecAudio,
     843                           pvData, cbData, msTimestamp, RECORDINGCODEC_ENC_F_BLOCK_IS_KEY);
    792844#else
    793845    RT_NOREF(pvData, cbData, msTimestamp);
    794     return VINF_SUCCESS;
     846    return VERR_NOT_SUPPORTED;
    795847#endif
    796848}
  • trunk/src/VBox/Main/src-client/RecordingStream.cpp

    r96243 r96260  
    319319            AssertPtr(pBlock);
    320320
    321             if (pBlock->enmType == RECORDINGBLOCKTYPE_VIDEO)
    322             {
    323                 RECORDINGFRAME Frame;
    324                 Frame.VideoPtr    = (PRECORDINGVIDEOFRAME)pBlock->pvData;
    325                 Frame.msTimestamp = msTimestamp;
    326 
    327                 int vrc2 = recordingCodecEncode(&this->CodecVideo, &Frame, NULL, NULL);
    328                 AssertRC(vrc2);
    329                 if (RT_SUCCESS(vrc))
    330                     vrc = vrc2;
     321            switch (pBlock->enmType)
     322            {
     323                case RECORDINGBLOCKTYPE_VIDEO:
     324                {
     325                    RECORDINGFRAME Frame;
     326                    Frame.VideoPtr    = (PRECORDINGVIDEOFRAME)pBlock->pvData;
     327                    Frame.msTimestamp = msTimestamp;
     328
     329                    int vrc2 = recordingCodecEncode(&this->CodecVideo, &Frame, NULL, NULL);
     330                    AssertRC(vrc2);
     331                    if (RT_SUCCESS(vrc))
     332                        vrc = vrc2;
     333
     334                    break;
     335                }
     336
     337                default:
     338                    /* Note: Audio data already is encoded. */
     339                    break;
    331340            }
    332341
     
    410419    LogFlowFuncLeaveRC(vrc);
    411420    return vrc;
     421}
     422
     423/**
     424 * Sends a raw (e.g. not yet encoded) audio frame to the recording stream.
     425 *
     426 * @returns VBox status code.
     427 * @param   pvData              Pointer to audio data.
     428 * @param   cbData              Size (in bytes) of \a pvData.
     429 * @param   msTimestamp         Absolute PTS timestamp (in ms).
     430 */
     431int RecordingStream::SendAudioFrame(const void *pvData, size_t cbData, uint64_t msTimestamp)
     432{
     433    /* As audio data is common across all streams, re-route this to the recording context, where
     434     * the data is being encoded and stored in the common blocks queue. */
     435    return m_pCtx->SendAudioFrame(pvData, cbData, msTimestamp);
    412436}
    413437
Note: See TracChangeset for help on using the changeset viewer.

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