VirtualBox

忽略:
時間撮記:
2013-6-14 上午10:08:20 (11 年 以前)
作者:
vboxsync
訊息:

Main/VPX: propery handle concurrency during termination

檔案:
修改 1 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/Main/src-client/VideoRec.cpp

    r45962 r46549  
    4040static int videoRecRGBToYUV(PVIDEORECSTREAM pStrm);
    4141
    42 /* encoding */
     42/* state to synchronized between threads */
    4343enum
    4444{
    4545    VIDREC_UNINITIALIZED = 0,
    46     /* initialized */
    47     VIDREC_INITIALIZED = 1,
     46    /* initialized, idle */
     47    VIDREC_IDLE = 1,
     48    /* currently in VideoRecCopyToIntBuf(), delay termination */
     49    VIDREC_COPYING = 2,
    4850    /* signal that we are terminating */
    49     VIDREC_TERMINATING = 2,
    50     /* confirmation that the worker thread terminated */
    51     VIDREC_TERMINATED = 3
     51    VIDREC_TERMINATING = 2
    5252};
     53static uint32_t g_enmState = VIDREC_UNINITIALIZED;
     54
    5355
    5456typedef struct VIDEORECSTREAM
     
    9294typedef struct VIDEORECCONTEXT
    9395{
    94     /* semaphore */
     96    /* semaphore to signal the encoding worker thread */
    9597    RTSEMEVENT          WaitEvent;
     98    /* semaphore required during termination */
     99    RTSEMEVENT          TermEvent;
    96100    /* true if video recording is enabled */
    97101    bool                fEnabled;
    98102    /* worker thread */
    99103    RTTHREAD            Thread;
    100     /* see VIDREC_xxx */
    101     uint32_t            uState;
    102104    /* number of stream contexts */
    103105    uint32_t            cScreens;
     
    387389        AssertRCBreak(rc);
    388390
    389         if (ASMAtomicReadU32(&pCtx->uState) == VIDREC_TERMINATING)
     391        if (ASMAtomicReadU32(&g_enmState) == VIDREC_TERMINATING)
    390392            break;
    391393        for (unsigned uScreen = 0; uScreen < pCtx->cScreens; uScreen++)
     
    411413    }
    412414
    413     ASMAtomicWriteU32(&pCtx->uState, VIDREC_TERMINATED);
    414415    return VINF_SUCCESS;
    415416}
     
    424425int VideoRecContextCreate(PVIDEORECCONTEXT *ppCtx, uint32_t cScreens)
    425426{
     427    Assert(ASMAtomicReadU32(&g_enmState) == VIDREC_UNINITIALIZED);
     428
    426429    PVIDEORECCONTEXT pCtx = (PVIDEORECCONTEXT)RTMemAllocZ(RT_OFFSETOF(VIDEORECCONTEXT, Strm[cScreens]));
    427430    *ppCtx = pCtx;
     
    435438    AssertRCReturn(rc, rc);
    436439
     440    rc = RTSemEventCreate(&pCtx->TermEvent);
     441    AssertRCReturn(rc, rc);
     442
    437443    rc = RTThreadCreate(&pCtx->Thread, videoRecThread, (void*)pCtx, 0,
    438444                        RTTHREADTYPE_MAIN_WORKER, RTTHREADFLAGS_WAITABLE, "VideoRec");
    439445    AssertRCReturn(rc, rc);
    440446
    441     ASMAtomicWriteU32(&pCtx->uState, VIDREC_INITIALIZED);
     447    ASMAtomicWriteU32(&g_enmState, VIDREC_IDLE);
    442448    return VINF_SUCCESS;
    443449}
     
    527533        return;
    528534
    529     if (ASMAtomicReadU32(&pCtx->uState) != VIDREC_INITIALIZED)
    530         return;
    531 
    532     ASMAtomicWriteU32(&pCtx->uState, VIDREC_TERMINATING);
     535    uint32_t enmState = VIDREC_IDLE;
     536    for (;;)
     537    {
     538        if (ASMAtomicCmpXchgExU32(&g_enmState, VIDREC_TERMINATING, enmState, &enmState))
     539            break;
     540        if (enmState == VIDREC_UNINITIALIZED)
     541            return;
     542    }
     543    if (enmState == VIDREC_COPYING)
     544    {
     545        int rc = RTSemEventWait(pCtx->TermEvent, RT_INDEFINITE_WAIT);
     546        AssertRC(rc);
     547    }
     548
    533549    RTSemEventSignal(pCtx->WaitEvent);
    534550    RTThreadWait(pCtx->Thread, 10000, NULL);
    535551    RTSemEventDestroy(pCtx->WaitEvent);
     552    RTSemEventDestroy(pCtx->TermEvent);
    536553
    537554    for (unsigned uScreen = 0; uScreen < pCtx->cScreens; uScreen++)
     
    560577    }
    561578
    562     ASMAtomicWriteU32(&pCtx->uState, VIDREC_UNINITIALIZED);
     579    RTMemFree(pCtx);
     580
     581    ASMAtomicWriteU32(&g_enmState, VIDREC_UNINITIALIZED);
    563582}
    564583
     
    665684
    666685/**
    667  * VideoRec utility function to copy source image (FrameBuf) to
    668  * intermediate RGB buffer.
     686 * VideoRec utility function to copy a source image (FrameBuf) to the intermediate
     687 * RGB buffer. This function is executed only once per time.
     688 *
     689 * @thread  EMT
    669690 *
    670691 * @returns IPRT status code.
     
    686707                         uint64_t u64TimeStamp)
    687708{
    688     AssertPtrReturn(pu8BufAddr, VERR_INVALID_PARAMETER);
    689     AssertReturn(uSourceWidth, VERR_INVALID_PARAMETER);
    690     AssertReturn(uSourceHeight, VERR_INVALID_PARAMETER);
    691     AssertReturn(uScreen < pCtx->cScreens, VERR_INVALID_PARAMETER);
    692     AssertReturn(pCtx->uState == VIDREC_INITIALIZED, VERR_INVALID_STATE);
    693 
    694     PVIDEORECSTREAM pStrm = &pCtx->Strm[uScreen];
    695 
    696     if (u64TimeStamp < pStrm->u64LastTimeStamp + pStrm->uDelay)
    697         return VINF_TRY_AGAIN; /* respect maximum frames per second */
    698 
    699     if (ASMAtomicReadBool(&pStrm->fRgbFilled))
    700         return VERR_TRY_AGAIN; /* previous frame not yet encoded */
    701 
    702     pStrm->u64LastTimeStamp = u64TimeStamp;
    703 
    704     int xDiff = ((int)pStrm->uTargetWidth - (int)uSourceWidth) / 2;
    705     uint32_t w = uSourceWidth;
    706     if ((int)w + xDiff + (int)x <= 0)  /* nothing visible */
    707         return VERR_INVALID_PARAMETER;
    708 
    709     uint32_t destX;
    710     if ((int)x < -xDiff)
    711     {
    712         w += xDiff + x;
    713         x = -xDiff;
    714         destX = 0;
    715     }
    716     else
    717         destX = x + xDiff;
    718 
    719     uint32_t h = uSourceHeight;
    720     int yDiff = ((int)pStrm->uTargetHeight - (int)uSourceHeight) / 2;
    721     if ((int)h + yDiff + (int)y <= 0)  /* nothing visible */
    722         return VERR_INVALID_PARAMETER;
    723 
    724     uint32_t destY;
    725     if ((int)y < -yDiff)
    726     {
    727         h += yDiff + (int)y;
    728         y = -yDiff;
    729         destY = 0;
    730     }
    731     else
    732         destY = y + yDiff;
    733 
    734     if (   destX > pStrm->uTargetWidth
    735         || destY > pStrm->uTargetHeight)
    736         return VERR_INVALID_PARAMETER;  /* nothing visible */
    737 
    738     if (destX + w > pStrm->uTargetWidth)
    739         w = pStrm->uTargetWidth - destX;
    740 
    741     if (destY + h > pStrm->uTargetHeight)
    742         h = pStrm->uTargetHeight - destY;
    743 
    744     /* Calculate bytes per pixel */
    745     uint32_t bpp = 1;
    746     if (uPixelFormat == FramebufferPixelFormat_FOURCC_RGB)
    747     {
    748         switch (uBitsPerPixel)
    749         {
    750             case 32:
    751                 pStrm->u32PixelFormat = VPX_IMG_FMT_RGB32;
    752                 bpp = 4;
    753                 break;
    754             case 24:
    755                 pStrm->u32PixelFormat = VPX_IMG_FMT_RGB24;
    756                 bpp = 3;
    757                 break;
    758             case 16:
    759                 pStrm->u32PixelFormat = VPX_IMG_FMT_RGB565;
    760                 bpp = 2;
    761                 break;
    762             default:
    763                 AssertMsgFailed(("Unknown color depth! mBitsPerPixel=%d\n", uBitsPerPixel));
    764                 break;
    765         }
    766     }
    767     else
    768         AssertMsgFailed(("Unknown pixel format! mPixelFormat=%d\n", uPixelFormat));
    769 
    770     /* One of the dimensions of the current frame is smaller than before so
    771      * clear the entire buffer to prevent artifacts from the previous frame */
    772     if (   uSourceWidth  < pStrm->uLastSourceWidth
    773         || uSourceHeight < pStrm->uLastSourceHeight)
    774         memset(pStrm->pu8RgbBuf, 0, pStrm->uTargetWidth * pStrm->uTargetHeight * 4);
    775 
    776     pStrm->uLastSourceWidth  = uSourceWidth;
    777     pStrm->uLastSourceHeight = uSourceHeight;
    778 
    779     /* Calculate start offset in source and destination buffers */
    780     uint32_t offSrc = y * uBytesPerLine + x * bpp;
    781     uint32_t offDst = (destY * pStrm->uTargetWidth + destX) * bpp;
    782     /* do the copy */
    783     for (unsigned int i = 0; i < h; i++)
    784     {
    785         /* Overflow check */
    786         Assert(offSrc + w * bpp <= uSourceHeight * uBytesPerLine);
    787         Assert(offDst + w * bpp <= pStrm->uTargetHeight * pStrm->uTargetWidth * bpp);
    788         memcpy(pStrm->pu8RgbBuf + offDst, pu8BufAddr + offSrc, w * bpp);
    789         offSrc += uBytesPerLine;
    790         offDst += pStrm->uTargetWidth * bpp;
    791     }
    792 
    793     pStrm->u64TimeStamp = u64TimeStamp;
    794 
    795     ASMAtomicWriteBool(&pStrm->fRgbFilled, true);
    796     RTSemEventSignal(pCtx->WaitEvent);
    797 
    798     return VINF_SUCCESS;
    799 }
     709    /* Do not execute during termination and guard against termination */
     710    if (!ASMAtomicCmpXchgU32(&g_enmState, VIDREC_COPYING, VIDREC_IDLE))
     711        return VINF_TRY_AGAIN;
     712
     713    int rc = VINF_SUCCESS;
     714    do
     715    {
     716        AssertPtrBreakStmt(pu8BufAddr, rc = VERR_INVALID_PARAMETER);
     717        AssertBreakStmt(uSourceWidth, rc = VERR_INVALID_PARAMETER);
     718        AssertBreakStmt(uSourceHeight, rc = VERR_INVALID_PARAMETER);
     719        AssertBreakStmt(uScreen < pCtx->cScreens, rc = VERR_INVALID_PARAMETER);
     720
     721        PVIDEORECSTREAM pStrm = &pCtx->Strm[uScreen];
     722
     723        if (u64TimeStamp < pStrm->u64LastTimeStamp + pStrm->uDelay)
     724        {
     725            rc = VINF_TRY_AGAIN; /* respect maximum frames per second */
     726            break;
     727        }
     728
     729        if (ASMAtomicReadBool(&pStrm->fRgbFilled))
     730        {
     731            rc = VERR_TRY_AGAIN; /* previous frame not yet encoded */
     732            break;
     733        }
     734
     735        pStrm->u64LastTimeStamp = u64TimeStamp;
     736
     737        int xDiff = ((int)pStrm->uTargetWidth - (int)uSourceWidth) / 2;
     738        uint32_t w = uSourceWidth;
     739        if ((int)w + xDiff + (int)x <= 0)  /* nothing visible */
     740        {
     741            rc = VERR_INVALID_PARAMETER;
     742            break;
     743        }
     744
     745        uint32_t destX;
     746        if ((int)x < -xDiff)
     747        {
     748            w += xDiff + x;
     749            x = -xDiff;
     750            destX = 0;
     751        }
     752        else
     753            destX = x + xDiff;
     754
     755        uint32_t h = uSourceHeight;
     756        int yDiff = ((int)pStrm->uTargetHeight - (int)uSourceHeight) / 2;
     757        if ((int)h + yDiff + (int)y <= 0)  /* nothing visible */
     758        {
     759            rc = VERR_INVALID_PARAMETER;
     760            break;
     761        }
     762
     763        uint32_t destY;
     764        if ((int)y < -yDiff)
     765        {
     766            h += yDiff + (int)y;
     767            y = -yDiff;
     768            destY = 0;
     769        }
     770        else
     771            destY = y + yDiff;
     772
     773        if (   destX > pStrm->uTargetWidth
     774            || destY > pStrm->uTargetHeight)
     775        {
     776            rc = VERR_INVALID_PARAMETER;  /* nothing visible */
     777            break;
     778        }
     779
     780        if (destX + w > pStrm->uTargetWidth)
     781            w = pStrm->uTargetWidth - destX;
     782
     783        if (destY + h > pStrm->uTargetHeight)
     784            h = pStrm->uTargetHeight - destY;
     785
     786        /* Calculate bytes per pixel */
     787        uint32_t bpp = 1;
     788        if (uPixelFormat == FramebufferPixelFormat_FOURCC_RGB)
     789        {
     790            switch (uBitsPerPixel)
     791            {
     792                case 32:
     793                    pStrm->u32PixelFormat = VPX_IMG_FMT_RGB32;
     794                    bpp = 4;
     795                    break;
     796                case 24:
     797                    pStrm->u32PixelFormat = VPX_IMG_FMT_RGB24;
     798                    bpp = 3;
     799                    break;
     800                case 16:
     801                    pStrm->u32PixelFormat = VPX_IMG_FMT_RGB565;
     802                    bpp = 2;
     803                    break;
     804                default:
     805                    AssertMsgFailed(("Unknown color depth! mBitsPerPixel=%d\n", uBitsPerPixel));
     806                    break;
     807            }
     808        }
     809        else
     810            AssertMsgFailed(("Unknown pixel format! mPixelFormat=%d\n", uPixelFormat));
     811
     812        /* One of the dimensions of the current frame is smaller than before so
     813         * clear the entire buffer to prevent artifacts from the previous frame */
     814        if (   uSourceWidth  < pStrm->uLastSourceWidth
     815            || uSourceHeight < pStrm->uLastSourceHeight)
     816            memset(pStrm->pu8RgbBuf, 0, pStrm->uTargetWidth * pStrm->uTargetHeight * 4);
     817
     818        pStrm->uLastSourceWidth  = uSourceWidth;
     819        pStrm->uLastSourceHeight = uSourceHeight;
     820
     821        /* Calculate start offset in source and destination buffers */
     822        uint32_t offSrc = y * uBytesPerLine + x * bpp;
     823        uint32_t offDst = (destY * pStrm->uTargetWidth + destX) * bpp;
     824        /* do the copy */
     825        for (unsigned int i = 0; i < h; i++)
     826        {
     827            /* Overflow check */
     828            Assert(offSrc + w * bpp <= uSourceHeight * uBytesPerLine);
     829            Assert(offDst + w * bpp <= pStrm->uTargetHeight * pStrm->uTargetWidth * bpp);
     830            memcpy(pStrm->pu8RgbBuf + offDst, pu8BufAddr + offSrc, w * bpp);
     831            offSrc += uBytesPerLine;
     832            offDst += pStrm->uTargetWidth * bpp;
     833        }
     834
     835        pStrm->u64TimeStamp = u64TimeStamp;
     836
     837        ASMAtomicWriteBool(&pStrm->fRgbFilled, true);
     838        RTSemEventSignal(pCtx->WaitEvent);
     839    } while (0);
     840
     841    if (!ASMAtomicCmpXchgU32(&g_enmState, VIDREC_IDLE, VIDREC_COPYING))
     842    {
     843        rc = RTSemEventSignal(pCtx->TermEvent);
     844        AssertRC(rc);
     845    }
     846
     847    return rc;
     848}
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

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