VirtualBox

Changeset 75040 in vbox


Ignore:
Timestamp:
Oct 24, 2018 1:54:50 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
126083
Message:

VideoRec/Main: Factored out the stream processing code into an own function VideoRecStreamProcess() and made it more resilient against errors.

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

Legend:

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

    r74999 r75040  
    169169PVIDEORECSTREAM videoRecStreamGet(PVIDEORECCONTEXT pCtx, uint32_t uScreen);
    170170int videoRecStreamOpen(PVIDEORECSTREAM pStream, PVIDEORECCFG pCfg);
     171int VideoRecStreamProcess(PVIDEORECSTREAM pStream);
    171172int videoRecStreamUninit(PVIDEORECSTREAM pStream);
    172173int videoRecStreamUnitVideo(PVIDEORECSTREAM pStream);
  • trunk/src/VBox/Main/src-client/VideoRec.cpp

    r74992 r75040  
    122122        AssertRCBreak(rc);
    123123
     124        Log2Func(("Processing %zu streams\n", pCtx->vecStreams.size()));
     125
    124126        /** @todo r=andy This is inefficient -- as we already wake up this thread
    125127         *               for every screen from Main, we here go again (on every wake up) through
    126128         *               all screens.  */
    127         for (VideoRecStreams::iterator itStream = pCtx->vecStreams.begin(); itStream != pCtx->vecStreams.end(); itStream++)
     129        VideoRecStreams::iterator itStream = pCtx->vecStreams.begin();
     130        while (itStream != pCtx->vecStreams.end())
    128131        {
    129132            PVIDEORECSTREAM pStream = (*itStream);
    130133
    131             videoRecStreamLock(pStream);
    132 
    133             if (!pStream->fEnabled)
    134             {
    135                 videoRecStreamUnlock(pStream);
    136                 continue;
    137             }
    138 
    139             VideoRecBlockMap::iterator itBlockStream = pStream->Blocks.Map.begin();
    140             while (itBlockStream != pStream->Blocks.Map.end())
    141             {
    142                 const uint64_t        uTimeStampMs = itBlockStream->first;
    143                       VideoRecBlocks *pBlocks      = itBlockStream->second;
    144 
    145                 AssertPtr(pBlocks);
    146 
    147                 while (!pBlocks->List.empty())
    148                 {
    149                     PVIDEORECBLOCK pBlock = pBlocks->List.front();
    150                     AssertPtr(pBlock);
    151 
    152 #ifdef VBOX_WITH_LIBVPX
    153                     if (pBlock->enmType == VIDEORECBLOCKTYPE_VIDEO)
    154                     {
    155                         PVIDEORECVIDEOFRAME pVideoFrame  = (PVIDEORECVIDEOFRAME)pBlock->pvData;
    156 
    157                         rc = videoRecRGBToYUV(pVideoFrame->uPixelFormat,
    158                                               /* Destination */
    159                                               pStream->Video.Codec.VPX.pu8YuvBuf, pVideoFrame->uWidth, pVideoFrame->uHeight,
    160                                               /* Source */
    161                                               pVideoFrame->pu8RGBBuf, pStream->Video.uWidth, pStream->Video.uHeight);
    162                         if (RT_SUCCESS(rc))
    163                             rc = videoRecStreamWriteVideoVPX(pStream, uTimeStampMs, pVideoFrame);
    164                     }
    165 #endif
    166                     VideoRecBlockFree(pBlock);
    167                     pBlock = NULL;
    168 
    169                     pBlocks->List.pop_front();
    170                 }
    171 
    172 #ifdef VBOX_WITH_AUDIO_VIDEOREC
    173                 /* As each (enabled) screen has to get the same audio data, look for common (audio) data which needs to be
    174                  * written to the screen's assigned recording stream. */
    175                 VideoRecBlockMap::iterator itCommon = pCtx->mapBlocksCommon.begin();
    176                 while (itCommon != pCtx->mapBlocksCommon.end())
    177                 {
    178                     VideoRecBlockList::iterator itBlockCommon = itCommon->second->List.begin();
    179                     while (itBlockCommon != itCommon->second->List.end())
    180                     {
    181                         PVIDEORECBLOCK pBlockCommon = (PVIDEORECBLOCK)(*itBlockCommon);
    182                         switch (pBlockCommon->enmType)
    183                         {
    184                             case VIDEORECBLOCKTYPE_AUDIO:
    185                             {
    186                                 PVIDEORECAUDIOFRAME pAudioFrame = (PVIDEORECAUDIOFRAME)pBlockCommon->pvData;
    187                                 AssertPtr(pAudioFrame);
    188                                 AssertPtr(pAudioFrame->pvBuf);
    189                                 Assert(pAudioFrame->cbBuf);
    190 
    191                                 WebMWriter::BlockData_Opus blockData = { pAudioFrame->pvBuf, pAudioFrame->cbBuf,
    192                                                                          pBlockCommon->uTimeStampMs };
    193                                 rc = pStream->File.pWEBM->WriteBlock(pStream->uTrackAudio, &blockData, sizeof(blockData));
    194                                 break;
    195                             }
    196 
    197                             default:
    198                                 AssertFailed();
    199                                 break;
    200                         }
    201 
    202                         Assert(pBlockCommon->cRefs);
    203                         if (--pBlockCommon->cRefs == 0)
    204                         {
    205                             VideoRecBlockFree(pBlockCommon);
    206                             itCommon->second->List.erase(itBlockCommon);
    207                             itBlockCommon = itCommon->second->List.begin();
    208                         }
    209                         else
    210                             ++itBlockCommon;
    211                     }
    212 
    213                     /* If no entries are left over in the block map, remove it altogether. */
    214                     if (itCommon->second->List.empty())
    215                     {
    216                         delete itCommon->second;
    217                         pCtx->mapBlocksCommon.erase(itCommon);
    218                     }
    219 
    220                     itCommon = pCtx->mapBlocksCommon.begin();
    221 
    222                     LogFunc(("Common blocks: %zu\n", pCtx->mapBlocksCommon.size()));
    223                 }
    224 #endif
    225                 ++itBlockStream;
    226             }
    227 
    228             videoRecStreamUnlock(pStream);
    229         }
     134            rc = VideoRecStreamProcess(pStream);
     135            if (RT_FAILURE(rc))
     136                break;
     137
     138            ++itStream;
     139        }
     140
     141        if (RT_FAILURE(rc))
     142            LogRel(("VideoRec: Encoding thread failed with rc=%Rrc\n", rc));
    230143
    231144        /* Keep going in case of errors. */
     
    379292        rc = videoRecThreadNotify(pCtx);
    380293        if (RT_SUCCESS(rc))
    381             rc = RTThreadWait(pCtx->Thread, 10 * 1000 /* 10s timeout */, NULL);
     294            rc = RTThreadWait(pCtx->Thread, 30 * 1000 /* 10s timeout */, NULL);
    382295
    383296        if (RT_SUCCESS(rc))
  • trunk/src/VBox/Main/src-client/VideoRecStream.cpp

    r74999 r75040  
    3838#include "VideoRec.h"
    3939#include "VideoRecStream.h"
     40#include "VideoRecUtils.h"
    4041#include "WebMWriter.h"
    4142
     
    193194
    194195    LogFlowFuncLeaveRC(rc);
     196    return rc;
     197}
     198
     199/**
     200 * Processes a recording stream.
     201 * This function takes care of the actual encoding and writing of a certain stream.
     202 * As this can be very CPU intensive, this function usually is called from a separate thread.
     203 *
     204 * @returns IPRT status code.
     205 * @param   pStream             Recording stream to process.
     206 */
     207int VideoRecStreamProcess(PVIDEORECSTREAM pStream)
     208{
     209    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
     210
     211    videoRecStreamLock(pStream);
     212
     213    if (!pStream->fEnabled)
     214    {
     215        videoRecStreamUnlock(pStream);
     216        return VINF_SUCCESS;
     217    }
     218
     219    int rc = VINF_SUCCESS;
     220
     221    const PVIDEORECCONTEXT pCtx = pStream->pCtx;
     222    AssertPtr(pCtx);
     223
     224    VideoRecBlockMap::iterator itStreamBlocks = pStream->Blocks.Map.begin();
     225    while (itStreamBlocks != pStream->Blocks.Map.end())
     226    {
     227        const uint64_t        uTimeStampMs = itStreamBlocks->first;
     228              VideoRecBlocks *pBlocks      = itStreamBlocks->second;
     229
     230        AssertPtr(pBlocks);
     231
     232        while (!pBlocks->List.empty())
     233        {
     234            PVIDEORECBLOCK pBlock = pBlocks->List.front();
     235            AssertPtr(pBlock);
     236
     237#ifdef VBOX_WITH_LIBVPX
     238            if (pBlock->enmType == VIDEORECBLOCKTYPE_VIDEO)
     239            {
     240                PVIDEORECVIDEOFRAME pVideoFrame  = (PVIDEORECVIDEOFRAME)pBlock->pvData;
     241
     242                rc = videoRecRGBToYUV(pVideoFrame->uPixelFormat,
     243                                      /* Destination */
     244                                      pStream->Video.Codec.VPX.pu8YuvBuf, pVideoFrame->uWidth, pVideoFrame->uHeight,
     245                                      /* Source */
     246                                      pVideoFrame->pu8RGBBuf, pStream->Video.uWidth, pStream->Video.uHeight);
     247                if (RT_SUCCESS(rc))
     248                {
     249                    rc = videoRecStreamWriteVideoVPX(pStream, uTimeStampMs, pVideoFrame);
     250                }
     251                else
     252                    break;
     253            }
     254#endif
     255            VideoRecBlockFree(pBlock);
     256            pBlock = NULL;
     257
     258            pBlocks->List.pop_front();
     259        }
     260
     261        ++itStreamBlocks;
     262    }
     263
     264#ifdef VBOX_WITH_AUDIO_VIDEOREC
     265    /* As each (enabled) screen has to get the same audio data, look for common (audio) data which needs to be
     266     * written to the screen's assigned recording stream. */
     267    VideoRecBlockMap::iterator itCommonBlocks = pCtx->mapBlocksCommon.begin();
     268    while (itCommonBlocks != pCtx->mapBlocksCommon.end())
     269    {
     270        VideoRecBlockList::iterator itBlock = itCommonBlocks->second->List.begin();
     271        while (itBlock != itCommonBlocks->second->List.end())
     272        {
     273            PVIDEORECBLOCK pBlockCommon = (PVIDEORECBLOCK)(*itBlock);
     274            switch (pBlockCommon->enmType)
     275            {
     276                case VIDEORECBLOCKTYPE_AUDIO:
     277                {
     278                    PVIDEORECAUDIOFRAME pAudioFrame = (PVIDEORECAUDIOFRAME)pBlockCommon->pvData;
     279                    AssertPtr(pAudioFrame);
     280                    AssertPtr(pAudioFrame->pvBuf);
     281                    Assert(pAudioFrame->cbBuf);
     282
     283                    WebMWriter::BlockData_Opus blockData = { pAudioFrame->pvBuf, pAudioFrame->cbBuf,
     284                                                             pBlockCommon->uTimeStampMs };
     285                    AssertPtr(pStream->File.pWEBM);
     286                    rc = pStream->File.pWEBM->WriteBlock(pStream->uTrackAudio, &blockData, sizeof(blockData));
     287                    break;
     288                }
     289
     290                default:
     291                    AssertFailed();
     292                    break;
     293            }
     294
     295            if (RT_FAILURE(rc))
     296                break;
     297
     298            Assert(pBlockCommon->cRefs);
     299            pBlockCommon->cRefs--;
     300            if (pBlockCommon->cRefs == 0)
     301            {
     302                VideoRecBlockFree(pBlockCommon);
     303                itCommonBlocks->second->List.erase(itBlock);
     304                itBlock = itCommonBlocks->second->List.begin();
     305            }
     306            else
     307                ++itBlock;
     308        }
     309
     310        /* If no entries are left over in the block map, remove it altogether. */
     311        if (itCommonBlocks->second->List.empty())
     312        {
     313            delete itCommonBlocks->second;
     314            pCtx->mapBlocksCommon.erase(itCommonBlocks);
     315            itCommonBlocks = pCtx->mapBlocksCommon.begin();
     316        }
     317        else
     318            ++itCommonBlocks;
     319
     320        LogFunc(("Common blocks: %zu\n", pCtx->mapBlocksCommon.size()));
     321
     322        if (RT_FAILURE(rc))
     323            break;
     324    }
     325#endif
     326
     327    videoRecStreamUnlock(pStream);
     328
    195329    return rc;
    196330}
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