VirtualBox

Changeset 65435 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jan 24, 2017 4:53:55 PM (8 years ago)
Author:
vboxsync
Message:

VideoRec: Got rid of busy waiting and unnecessary termination event; more audio work.

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

Legend:

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

    r65392 r65435  
    585585        CurSeg.mapTracks[uTrack] = pTrack;
    586586
    587         Assert(uTrack == 0);
    588 
    589587        if (puTrack)
    590588            *puTrack = uTrack;
     
    784782        uint64_t tcPTSRaw = lround((CurSeg.uTimecodeScaleFactor * 1000 * Cluster.cbData) / a_pTrack->Audio.uHz);
    785783
    786         uint64_t tcPTS = /*Cluster.tcStart +*/ lround(tcPTSRaw / CurSeg.uTimecodeScaleFactor);
     784        /* Calculate the absolute PTS. */
     785        uint64_t tcPTS = lround(tcPTSRaw / CurSeg.uTimecodeScaleFactor);
    787786
    788787        if (Cluster.tcStart == UINT64_MAX)
  • trunk/src/VBox/Main/src-client/EbmlWriter.h

    r65362 r65435  
    8282        /** Size (in bytes) of encoded Opus audio data. */
    8383        size_t      cbData;
     84        /** Timestamp (in ms). */
     85        uint64_t    uTimestampMs;
    8486    };
    8587#endif /* VBOX_WITH_LIBOPUS */
  • trunk/src/VBox/Main/src-client/VideoRec.cpp

    r65429 r65435  
    6060    /** Currently busy, delay termination. */
    6161    VIDEORECSTS_BUSY          = 2,
    62     /** Signal that we are terminating. */
    63     VIDEORECSTS_TERMINATING   = 3
     62    /** The usual 32-bit hack. */
     63    VIDEORECSTS_32BIT_HACK    = 0x7fffffff
    6464};
    6565
     
    7878    VIDEORECPIXELFMT_RGB565  = 3
    7979};
    80 
    81 /* Must be always accessible and therefore cannot be part of VIDEORECCONTEXT */
    82 static uint32_t g_enmState = VIDEORECSTS_UNINITIALIZED; /** @todo r=andy Make this part of VIDEORECCONTEXT + remove busy waiting. */
    8380
    8481/**
     
    153150} VIDEORECSTREAM, *PVIDEORECSTREAM;
    154151
     152#ifdef VBOX_WITH_AUDIO_VIDEOREC
     153typedef struct VIDEORECAUDIOFRAME
     154{
     155    uint8_t             abBuf[_64K]; /** @todo Fix! */
     156    uint32_t            cbBuf;
     157    /** Time stamp (in ms). */
     158    uint64_t            uTimeStampMs;
     159} VIDEORECAUDIOFRAME, *PVIDEORECAUDIOFRAME;
     160#endif
     161
    155162/** Vector of video recording streams. */
    156163typedef std::vector <PVIDEORECSTREAM> VideoRecStreams;
     
    161168typedef struct VIDEORECCONTEXT
    162169{
     170    /** The current state. */
     171    uint32_t            enmState;
    163172    /** Semaphore to signal the encoding worker thread. */
    164173    RTSEMEVENT          WaitEvent;
    165     /** Semaphore required during termination. */
    166     RTSEMEVENT          TermEvent;
    167174    /** Whether video recording is enabled or not. */
    168175    bool                fEnabled;
     176    /** Shutdown indicator. */
     177    bool                fShutdown;
    169178    /** Worker thread. */
    170179    RTTHREAD            Thread;
     
    177186#ifdef VBOX_WITH_AUDIO_VIDEOREC
    178187    bool                fHasAudioData;
    179     struct
    180     {
    181         uint8_t         buf[_64K];
    182     } Audio;
     188    VIDEORECAUDIOFRAME  Audio;
    183189#endif
    184190} VIDEORECCONTEXT, *PVIDEORECCONTEXT;
     
    455461static DECLCALLBACK(int) videoRecThread(RTTHREAD hThreadSelf, void *pvUser)
    456462{
    457     RT_NOREF(hThreadSelf);
    458463    PVIDEORECCONTEXT pCtx = (PVIDEORECCONTEXT)pvUser;
     464
     465    /* Signal that we're up and rockin'. */
     466    RTThreadUserSignal(hThreadSelf);
    459467
    460468    for (;;)
     
    463471        AssertRCBreak(rc);
    464472
    465         if (ASMAtomicReadU32(&g_enmState) == VIDEORECSTS_TERMINATING)
     473        if (ASMAtomicReadBool(&pCtx->fShutdown))
    466474            break;
    467475
     
    503511            if (fHasAudioData)
    504512            {
    505                 WebMWriter::BlockData_Opus blockData = { pCtx->Audio.buf, };
     513                WebMWriter::BlockData_Opus blockData = { pCtx->Audio.abBuf, pCtx->Audio.cbBuf, pCtx->Audio.uTimeStampMs };
    506514                rc = pStream->pEBML->WriteBlock(pStream->uTrackAudio, &blockData, sizeof(blockData));
    507515            }
     
    529537    AssertPtrReturn(ppCtx, VERR_INVALID_POINTER);
    530538
    531     Assert(ASMAtomicReadU32(&g_enmState) == VIDEORECSTS_UNINITIALIZED);
    532 
    533539    int rc = VINF_SUCCESS;
    534540
     
    563569    if (RT_SUCCESS(rc))
    564570    {
     571        pCtx->enmState  = VIDEORECSTS_UNINITIALIZED;
     572        pCtx->fShutdown = false;
     573
    565574        rc = RTSemEventCreate(&pCtx->WaitEvent);
    566575        AssertRCReturn(rc, rc);
    567576
    568         rc = RTSemEventCreate(&pCtx->TermEvent);
    569         AssertRCReturn(rc, rc);
    570 
    571         rc = RTThreadCreate(&pCtx->Thread, videoRecThread, (void*)pCtx, 0,
     577        rc = RTThreadCreate(&pCtx->Thread, videoRecThread, (void *)pCtx, 0,
    572578                            RTTHREADTYPE_MAIN_WORKER, RTTHREADFLAGS_WAITABLE, "VideoRec");
    573         AssertRCReturn(rc, rc);
    574 
    575         ASMAtomicWriteU32(&g_enmState, VIDEORECSTS_IDLE);
    576 
    577         if (ppCtx)
    578             *ppCtx = pCtx;
    579     }
    580     else
     579
     580        if (RT_SUCCESS(rc)) /* Wait for the thread to start. */
     581            rc = RTThreadUserWait(pCtx->Thread, 30 * 1000 /* 30s timeout */);
     582
     583        if (RT_SUCCESS(rc))
     584        {
     585            pCtx->enmState = VIDEORECSTS_IDLE;
     586            pCtx->fEnabled = true;
     587
     588            if (ppCtx)
     589                *ppCtx = pCtx;
     590        }
     591    }
     592
     593    if (RT_FAILURE(rc))
    581594    {
    582595        /* Roll back allocations on error. */
     
    606619 * @param pCtx                  Video recording context to destroy.
    607620 */
    608 void VideoRecContextDestroy(PVIDEORECCONTEXT pCtx)
     621int VideoRecContextDestroy(PVIDEORECCONTEXT pCtx)
    609622{
    610623    if (!pCtx)
    611         return;
    612 
    613     uint32_t enmState = VIDEORECSTS_IDLE;
    614 
    615     for (;;) /** @todo r=andy Remove busy waiting! */
    616     {
    617         if (ASMAtomicCmpXchgExU32(&g_enmState, VIDEORECSTS_TERMINATING, enmState, &enmState))
    618             break;
    619         if (enmState == VIDEORECSTS_UNINITIALIZED)
    620             return;
    621     }
    622 
    623     if (enmState == VIDEORECSTS_BUSY)
    624     {
    625         int rc = RTSemEventWait(pCtx->TermEvent, RT_INDEFINITE_WAIT);
    626         AssertRC(rc);
    627     }
    628 
     624        return VINF_SUCCESS;
     625
     626    /* Set shutdown indicator. */
     627    ASMAtomicWriteBool(&pCtx->fShutdown, true);
     628
     629    /* Signal the thread. */
    629630    RTSemEventSignal(pCtx->WaitEvent);
    630     RTThreadWait(pCtx->Thread, 10 * 1000, NULL);
    631     RTSemEventDestroy(pCtx->WaitEvent);
    632     RTSemEventDestroy(pCtx->TermEvent);
     631
     632    int rc = RTThreadWait(pCtx->Thread, 10 * 1000 /* 10s timeout */, NULL);
     633    if (RT_FAILURE(rc))
     634        return rc;
     635
     636    rc = RTSemEventDestroy(pCtx->WaitEvent);
     637    AssertRC(rc);
     638
     639    pCtx->WaitEvent = NIL_RTSEMEVENT;
    633640
    634641    VideoRecStreams::iterator it = pCtx->vecStreams.begin();
     
    668675
    669676    Assert(pCtx->vecStreams.empty());
     677
    670678    RTMemFree(pCtx);
    671 
    672     ASMAtomicWriteU32(&g_enmState, VIDEORECSTS_UNINITIALIZED);
     679    pCtx = NULL;
     680
     681    return VINF_SUCCESS;
    673682}
    674683
     
    885894    pStream->Video.pu8YuvBuf = pStream->Codec.VPX.RawImage.planes[0];
    886895#endif
    887 
    888     pCtx->fEnabled = true;
    889896    pStream->fEnabled = true;
    890897
     
    895902 * VideoRec utility function to check if recording is enabled.
    896903 *
    897  * @returns true if recording is enabled
     904 * @returns true if recording is enabled.
    898905 * @param   pCtx                Pointer to video recording context.
    899906 */
     
    901908{
    902909    RT_NOREF(pCtx);
    903     uint32_t enmState = ASMAtomicReadU32(&g_enmState);
     910    uint32_t enmState = ASMAtomicReadU32(&pCtx->enmState);
    904911    return (   enmState == VIDEORECSTS_IDLE
    905912            || enmState == VIDEORECSTS_BUSY);
     
    910917 * for the given screen.
    911918 *
    912  * @returns true if recording engine is ready
     919 * @returns true if recording engine is ready.
    913920 * @param   pCtx                Pointer to video recording context.
    914921 * @param   uScreen             Screen ID.
     
    917924bool VideoRecIsReady(PVIDEORECCONTEXT pCtx, uint32_t uScreen, uint64_t uTimeStampMs)
    918925{
    919     uint32_t enmState = ASMAtomicReadU32(&g_enmState);
     926    uint32_t enmState = ASMAtomicReadU32(&pCtx->enmState);
    920927    if (enmState != VIDEORECSTS_IDLE)
    921928        return false;
     
    931938        return false;
    932939
    933     if (ASMAtomicReadBool(&pStream->fHasVideoData))
     940    if (   ASMAtomicReadBool(&pStream->fHasVideoData)
     941#ifdef VBOX_WITH_AUDIO_VIDEOREC
     942        /* Check if we have audio data left for the current frame. */
     943        || ASMAtomicReadBool(&pCtx->fHasAudioData)
     944#endif
     945       )
     946    {
    934947        return false;
     948    }
    935949
    936950    return true;
     
    10831097 * @param   pvData              Audio frame data to send.
    10841098 * @param   cbData              Size (in bytes) of audio frame data.
    1085  * @param   uTimestampMs        Time stamp (in ms) of audio playback.
    1086  */
    1087 int VideoRecSendAudioFrame(PVIDEORECCONTEXT pCtx, const void *pvData, size_t cbData, uint64_t uTimestampMs)
    1088 {
    1089     RT_NOREF(pCtx, pvData, cbData, uTimestampMs);
     1099 * @param   uTimeStampMs        Time stamp (in ms) of audio playback.
     1100 */
     1101int VideoRecSendAudioFrame(PVIDEORECCONTEXT pCtx, const void *pvData, size_t cbData, uint64_t uTimeStampMs)
     1102{
     1103#ifdef VBOX_WITH_AUDIO_VIDEOREC
     1104    AssertReturn(cbData <= _64K, VERR_INVALID_PARAMETER);
     1105
     1106    /* Do not execute during termination and guard against termination. */
     1107    if (!ASMAtomicCmpXchgU32(&pCtx->enmState, VIDEORECSTS_BUSY, VIDEORECSTS_IDLE))
     1108        return VINF_TRY_AGAIN;
    10901109
    10911110    /* To save time spent in EMT, do the required audio multiplexing in the encoding thread.
     
    10951114     */
    10961115
    1097 
     1116    if (ASMAtomicReadBool(&pCtx->fHasAudioData))
     1117        return VERR_TRY_AGAIN; /* Previous frame not yet encoded. */
     1118
     1119    memcpy(pCtx->Audio.abBuf, pvData, RT_MIN(_64K, cbData));
     1120    pCtx->Audio.uTimeStampMs = uTimeStampMs;
     1121
     1122    ASMAtomicWriteBool(&pCtx->fHasAudioData, true);
     1123    RTSemEventSignal(pCtx->WaitEvent);
     1124#else
     1125    RT_NOREF(pCtx, pvData, cbData, uTimeStampMs);
     1126#endif
    10981127    return VINF_SUCCESS;
    10991128}
     
    11241153{
    11251154    /* Do not execute during termination and guard against termination. */
    1126     if (!ASMAtomicCmpXchgU32(&g_enmState, VIDEORECSTS_BUSY, VIDEORECSTS_IDLE))
     1155    if (!ASMAtomicCmpXchgU32(&pCtx->enmState, VIDEORECSTS_BUSY, VIDEORECSTS_IDLE))
    11271156        return VINF_TRY_AGAIN;
    11281157
     
    12701299    } while (0);
    12711300
    1272     if (!ASMAtomicCmpXchgU32(&g_enmState, VIDEORECSTS_IDLE, VIDEORECSTS_BUSY))
    1273     {
    1274         rc = RTSemEventSignal(pCtx->TermEvent);
    1275         AssertRC(rc);
    1276     }
     1301    ASMAtomicCmpXchgU32(&pCtx->enmState, VIDEORECSTS_IDLE, VIDEORECSTS_BUSY);
    12771302
    12781303    return rc;
  • trunk/src/VBox/Main/src-client/VideoRec.h

    r65429 r65435  
    2525typedef struct VIDEORECSTREAM *PVIDEORECSTREAM;
    2626
    27 int  VideoRecContextCreate(uint32_t cScreens, PVIDEORECCONTEXT *ppCtx);
    28 void VideoRecContextDestroy(PVIDEORECCONTEXT pCtx);
     27int VideoRecContextCreate(uint32_t cScreens, PVIDEORECCONTEXT *ppCtx);
     28int VideoRecContextDestroy(PVIDEORECCONTEXT pCtx);
    2929
    3030int  VideoRecStreamInit(PVIDEORECCONTEXT pCtx, uint32_t uScreen, const char *pszFile,
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