VirtualBox

Changeset 68453 in vbox for trunk/src/VBox/Main/src-client


Ignore:
Timestamp:
Aug 17, 2017 8:18:11 PM (8 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
117596
Message:

Main/VideoRec: Restructured a lot of code to better adapt when it comes to also muxing the audio data (not enabled by default yet).

File:
1 edited

Legend:

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

    r68431 r68453  
    2525#include <iprt/asm.h>
    2626#include <iprt/assert.h>
     27#include <iprt/critsect.h>
    2728#include <iprt/semaphore.h>
    2829#include <iprt/thread.h>
     
    4546#endif /* VBOX_WITH_LIBVPX */
    4647
    47 static int videoRecEncodeAndWrite(PVIDEORECSTREAM pStrm);
    48 static int videoRecRGBToYUV(PVIDEORECSTREAM pStrm);
     48struct VIDEORECVIDEOFRAME;
     49typedef struct VIDEORECVIDEOFRAME *PVIDEORECVIDEOFRAME;
     50
     51static int videoRecEncodeAndWrite(PVIDEORECSTREAM pStream, PVIDEORECVIDEOFRAME pFrame);
     52static int videoRecRGBToYUV(uint32_t uPixelFormat,
     53                            uint8_t *paDst, uint32_t uDstWidth, uint32_t uDstHeight,
     54                            uint8_t *paSrc, uint32_t uSrcWidth, uint32_t uSrcHeight);
     55
     56int videoRecStreamLock(PVIDEORECSTREAM pStream);
     57int videoRecStreamUnlock(PVIDEORECSTREAM pStream);
    4958
    5059using namespace com;
     60
     61#if 0
     62/** Enables support for encoding multiple audio / video data frames at once. */
     63#define VBOX_VIDEOREC_WITH_QUEUE
     64#endif
     65#ifdef DEBUG_andy
     66/** Enables dumping audio / video data for debugging reasons. */
     67# define VBOX_VIDEOREC_DUMP
     68#endif
    5169
    5270/**
     
    5775    /** Not initialized. */
    5876    VIDEORECSTS_UNINITIALIZED = 0,
    59     /** Initialized, idle. */
    60     VIDEORECSTS_IDLE          = 1,
    61     /** Currently busy, delay termination. */
    62     VIDEORECSTS_BUSY          = 2,
     77    /** Initialized. */
     78    VIDEORECSTS_INITIALIZED   = 1,
    6379    /** The usual 32-bit hack. */
    6480    VIDEORECSTS_32BIT_HACK    = 0x7fffffff
     
    7187{
    7288    /** Unknown pixel format. */
    73     VIDEORECPIXELFMT_UNKNOWN = 0,
     89    VIDEORECPIXELFMT_UNKNOWN    = 0,
    7490    /** RGB 24. */
    75     VIDEORECPIXELFMT_RGB24   = 1,
     91    VIDEORECPIXELFMT_RGB24      = 1,
    7692    /** RGB 24. */
    77     VIDEORECPIXELFMT_RGB32   = 2,
     93    VIDEORECPIXELFMT_RGB32      = 2,
    7894    /** RGB 565. */
    79     VIDEORECPIXELFMT_RGB565  = 3
     95    VIDEORECPIXELFMT_RGB565     = 3,
     96    /** The usual 32-bit hack. */
     97    VIDEORECPIXELFMT_32BIT_HACK = 0x7fffffff
    8098};
    8199
     
    83101 * Structure for keeping specific video recording codec data.
    84102 */
    85 typedef struct VIDEORECCODEC
     103typedef struct VIDEORECVIDEOCODEC
    86104{
    87105    union
     
    91109        {
    92110            /** VPX codec context. */
    93             vpx_codec_ctx_t     CodecCtx;
     111            vpx_codec_ctx_t     Ctx;
    94112            /** VPX codec configuration. */
    95             vpx_codec_enc_cfg_t Config;
     113            vpx_codec_enc_cfg_t Cfg;
    96114            /** VPX image context. */
    97115            vpx_image_t         RawImage;
     116            /** Encoder deadline. */
     117            unsigned int        uEncoderDeadline;
    98118        } VPX;
    99119#endif /* VBOX_WITH_LIBVPX */
    100120    };
    101 } VIDEORECCODEC, *PVIDEORECCODEC;
     121} VIDEORECVIDEOCODEC, *PVIDEORECVIDEOCODEC;
     122
     123/**
     124 * Structure for keeping a single video recording video frame.
     125 */
     126typedef struct VIDEORECVIDEOFRAME
     127{
     128    /** X resolution of this frame. */
     129    uint32_t            uWidth;
     130    /** Y resolution of this frame. */
     131    uint32_t            uHeight;
     132    /** Pixel format of this frame. */
     133    uint32_t            uPixelFormat;
     134    /** Time stamp (in ms). */
     135    uint64_t            uTimeStampMs;
     136    /** RGB buffer containing the unmodified frame buffer data from Main's display. */
     137    uint8_t            *pu8RGBBuf;
     138    /** Size (in bytes) of the RGB buffer. */
     139    size_t              cbRGBBuf;
     140} VIDEORECVIDEOFRAME, *PVIDEORECVIDEOFRAME;
     141
     142#ifdef VBOX_WITH_AUDIO_VIDEOREC
     143/**
     144 * Structure for keeping a single video recording audio frame.
     145 */
     146typedef struct VIDEORECAUDIOFRAME
     147{
     148    uint8_t             abBuf[_64K]; /** @todo Fix! */
     149    uint32_t            cbBuf;
     150    /** Time stamp (in ms). */
     151    uint64_t            uTimeStampMs;
     152} VIDEORECAUDIOFRAME, *PVIDEORECAUDIOFRAME;
     153#endif
    102154
    103155/**
     
    114166    /** Track number of video stream. */
    115167    uint8_t             uTrackVideo;
    116     /** Codec data. */
    117     VIDEORECCODEC       Codec;
    118168    /** Screen ID. */
    119     uint16_t            uScreen;
     169    uint16_t            uScreenID;
    120170    /** Whether video recording is enabled or not. */
    121171    bool                fEnabled;
    122     /** Time stamp (in ms) of the last frame we encoded. */
    123     uint64_t            uLastTimeStampMs;
    124     /** Time stamp (in ms) of the current frame. */
    125     uint64_t            uCurTimeStampMs;
    126 
    127     /** Whether the RGB buffer is filled or not. */
    128     bool                fHasVideoData;
     172    /** Critical section to serialize access. */
     173    RTCRITSECT          CritSect;
    129174
    130175    struct
    131176    {
    132         /** Target X resolution (in pixels). */
    133         uint32_t            uDstWidth;
    134         /** Target Y resolution (in pixels). */
    135         uint32_t            uDstHeight;
    136         /** X resolution of the last encoded frame. */
    137         uint32_t            uSrcLastWidth;
    138         /** Y resolution of the last encoded frame. */
    139         uint32_t            uSrcLastHeight;
    140         /** RGB buffer containing the most recent frame of Main's framebuffer. */
    141         uint8_t            *pu8RgbBuf;
    142         /** YUV buffer the encode function fetches the frame from. */
    143         uint8_t            *pu8YuvBuf;
    144         /** Pixel format of the current frame. */
    145         uint32_t            uPixelFormat;
     177        /** Codec-specific data. */
     178        VIDEORECVIDEOCODEC  Codec;
    146179        /** Minimal delay (in ms) between two frames. */
    147180        uint32_t            uDelayMs;
    148         /** Encoder deadline. */
    149         unsigned int        uEncoderDeadline;
     181        /** Target X resolution (in pixels). */
     182        uint32_t            uWidth;
     183        /** Target Y resolution (in pixels). */
     184        uint32_t            uHeight;
     185        /** Time stamp (in ms) of the last video frame we encoded. */
     186        uint64_t            uLastTimeStampMs;
     187        /** Pointer to the codec's internal YUV buffer. */
     188        uint8_t            *pu8YuvBuf;
     189#ifdef VBOX_VIDEOREC_WITH_QUEUE
     190# error "Implement me!"
     191#else
     192        VIDEORECVIDEOFRAME  Frame;
     193        bool                fHasVideoData;
     194#endif
    150195    } Video;
    151196} VIDEORECSTREAM, *PVIDEORECSTREAM;
    152197
    153 #ifdef VBOX_WITH_AUDIO_VIDEOREC
    154 typedef struct VIDEORECAUDIOFRAME
    155 {
    156     uint8_t             abBuf[_64K]; /** @todo Fix! */
    157     uint32_t            cbBuf;
    158     /** Time stamp (in ms). */
    159     uint64_t            uTimeStampMs;
    160 } VIDEORECAUDIOFRAME, *PVIDEORECAUDIOFRAME;
    161 #endif
    162 
    163198/** Vector of video recording streams. */
    164199typedef std::vector <PVIDEORECSTREAM> VideoRecStreams;
     
    171206    /** The current state. */
    172207    uint32_t            enmState;
     208    /** Critical section to serialize access. */
     209    RTCRITSECT          CritSect;
    173210    /** Semaphore to signal the encoding worker thread. */
    174211    RTSEMEVENT          WaitEvent;
    175     /** Whether video recording is enabled or not. */
     212    /** Whether recording is enabled or not. */
    176213    bool                fEnabled;
    177214    /** Shutdown indicator. */
     
    183220    /** Maximal file size (in MB) to record. */
    184221    uint32_t            uMaxSizeMB;
    185     /** Vector of current video recording stream contexts. */
     222    /** Vector of current recording stream contexts. */
    186223    VideoRecStreams     vecStreams;
    187224#ifdef VBOX_WITH_AUDIO_VIDEOREC
    188     bool                fHasAudioData;
    189     VIDEORECAUDIOFRAME  Audio;
     225    struct
     226    {
     227        bool                fHasAudioData;
     228        VIDEORECAUDIOFRAME  Frame;
     229    } Audio;
    190230#endif
    191231} VIDEORECCONTEXT, *PVIDEORECCONTEXT;
    192232
     233#ifdef VBOX_VIDEOREC_DUMP
     234#pragma pack(push)
     235#pragma pack(1)
     236typedef struct
     237{
     238    uint16_t u16Magic;
     239    uint32_t u32Size;
     240    uint16_t u16Reserved1;
     241    uint16_t u16Reserved2;
     242    uint32_t u32OffBits;
     243} VIDEORECBMPHDR, *PVIDEORECBMPHDR;
     244AssertCompileSize(VIDEORECBMPHDR, 14);
     245
     246typedef struct
     247{
     248    uint32_t u32Size;
     249    uint32_t u32Width;
     250    uint32_t u32Height;
     251    uint16_t u16Planes;
     252    uint16_t u16BitCount;
     253    uint32_t u32Compression;
     254    uint32_t u32SizeImage;
     255    uint32_t u32XPelsPerMeter;
     256    uint32_t u32YPelsPerMeter;
     257    uint32_t u32ClrUsed;
     258    uint32_t u32ClrImportant;
     259} VIDEORECBMPDIBHDR, *PVIDEORECBMPDIBHDR;
     260AssertCompileSize(VIDEORECBMPDIBHDR, 40);
     261
     262#pragma pack(pop)
     263#endif /* VBOX_VIDEOREC_DUMP */
    193264
    194265/**
     
    355426
    356427/**
    357  * Convert an image to YUV420p format
    358  * @returns true on success, false on failure
    359  * @param aWidth    width of image
    360  * @param aHeight   height of image
    361  * @param aDestBuf  an allocated memory buffer large enough to hold the
    362  *                  destination image (i.e. width * height * 12bits)
    363  * @param aSrcBuf   the source image as an array of bytes
     428 * Convert an image to YUV420p format.
     429 *
     430 * @return true on success, false on failure.
     431 * @param  aDstBuf              The destination image buffer.
     432 * @param  aDstWidth            Width (in pixel) of destination buffer.
     433 * @param  aDstHeight           Height (in pixel) of destination buffer.
     434 * @param  aSrcBuf              The source image buffer.
     435 * @param  aSrcWidth            Width (in pixel) of source buffer.
     436 * @param  aSrcHeight           Height (in pixel) of source buffer.
    364437 */
    365438template <class T>
    366 inline bool colorConvWriteYUV420p(unsigned aWidth, unsigned aHeight, uint8_t *aDestBuf, uint8_t *aSrcBuf)
    367 {
    368     AssertReturn(!(aWidth & 1), false);
    369     AssertReturn(!(aHeight & 1), false);
     439inline bool colorConvWriteYUV420p(uint8_t *aDstBuf, unsigned aDstWidth, unsigned aDstHeight,
     440                                  uint8_t *aSrcBuf, unsigned aSrcWidth, unsigned aSrcHeight)
     441{
     442    RT_NOREF(aDstWidth, aDstHeight);
     443
     444    AssertReturn(!(aSrcWidth & 1),  false);
     445    AssertReturn(!(aSrcHeight & 1), false);
     446
    370447    bool fRc = true;
    371     T iter1(aWidth, aHeight, aSrcBuf);
     448    T iter1(aSrcWidth, aSrcHeight, aSrcBuf);
    372449    T iter2 = iter1;
    373     iter2.skip(aWidth);
    374     unsigned cPixels = aWidth * aHeight;
     450    iter2.skip(aSrcWidth);
     451    unsigned cPixels = aSrcWidth * aSrcHeight;
    375452    unsigned offY = 0;
    376453    unsigned offU = cPixels;
    377454    unsigned offV = cPixels + cPixels / 4;
    378     unsigned const cyHalf = aHeight / 2;
    379     unsigned const cxHalf = aWidth  / 2;
     455    unsigned const cyHalf = aSrcHeight / 2;
     456    unsigned const cxHalf = aSrcWidth  / 2;
    380457    for (unsigned i = 0; i < cyHalf && fRc; ++i)
    381458    {
     
    385462            fRc = iter1.getRGB(&red, &green, &blue);
    386463            AssertReturn(fRc, false);
    387             aDestBuf[offY] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
     464            aDstBuf[offY] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
    388465            unsigned u = (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
    389466            unsigned v = (((112 * red - 94 * green -  18 * blue + 128) >> 8) + 128) / 4;
     
    391468            fRc = iter1.getRGB(&red, &green, &blue);
    392469            AssertReturn(fRc, false);
    393             aDestBuf[offY + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
     470            aDstBuf[offY + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
    394471            u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
    395472            v += (((112 * red - 94 * green -  18 * blue + 128) >> 8) + 128) / 4;
     
    397474            fRc = iter2.getRGB(&red, &green, &blue);
    398475            AssertReturn(fRc, false);
    399             aDestBuf[offY + aWidth] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
     476            aDstBuf[offY + aSrcWidth] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
    400477            u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
    401478            v += (((112 * red - 94 * green -  18 * blue + 128) >> 8) + 128) / 4;
     
    403480            fRc = iter2.getRGB(&red, &green, &blue);
    404481            AssertReturn(fRc, false);
    405             aDestBuf[offY + aWidth + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
     482            aDstBuf[offY + aSrcWidth + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
    406483            u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
    407484            v += (((112 * red - 94 * green -  18 * blue + 128) >> 8) + 128) / 4;
    408485
    409             aDestBuf[offU] = u;
    410             aDestBuf[offV] = v;
     486            aDstBuf[offU] = u;
     487            aDstBuf[offV] = v;
    411488            offY += 2;
    412489            ++offU;
     
    414491        }
    415492
    416         iter1.skip(aWidth);
    417         iter2.skip(aWidth);
    418         offY += aWidth;
     493        iter1.skip(aSrcWidth);
     494        iter2.skip(aSrcWidth);
     495        offY += aSrcWidth;
    419496    }
    420497
     
    476553
    477554#ifdef VBOX_WITH_AUDIO_VIDEOREC
    478         const bool fHasAudioData = ASMAtomicReadBool(&pCtx->fHasAudioData);
    479 #endif
     555        PVIDEORECAUDIOFRAME pAudioFrame;
     556
     557        int rc2 = RTCritSectEnter(&pCtx->CritSect);
     558        AssertRC(rc2);
     559
     560        const bool fEncodeAudio = pCtx->Audio.fHasAudioData;
     561        if (fEncodeAudio)
     562        {
     563            /*
     564             * Every recording stream needs to get the same audio data at a certain point in time.
     565             * Do the multiplexing here to not block EMT for too long.
     566             *
     567             * For now just doing a simple copy of the current audio frame should be good enough.
     568             */
     569            VIDEORECAUDIOFRAME audioFrame;
     570            memcpy(&audioFrame, &pCtx->Audio.Frame, sizeof(VIDEORECAUDIOFRAME));
     571            pAudioFrame = &audioFrame;
     572
     573            pCtx->Audio.fHasAudioData = false;
     574        }
     575
     576        rc2 = RTCritSectLeave(&pCtx->CritSect);
     577        AssertRC(rc2);
     578#endif
     579
    480580        /** @todo r=andy This is inefficient -- as we already wake up this thread
    481581         *               for every screen from Main, we here go again (on every wake up) through
     
    485585            PVIDEORECSTREAM pStream = (*it);
    486586
     587            videoRecStreamLock(pStream);
     588
    487589            if (!pStream->fEnabled)
     590            {
     591                videoRecStreamUnlock(pStream);
    488592                continue;
    489 
    490             if (ASMAtomicReadBool(&pStream->fHasVideoData))
    491             {
    492                 rc = videoRecRGBToYUV(pStream);
    493 
    494                 ASMAtomicWriteBool(&pStream->fHasVideoData, false);
    495 
    496                 if (RT_SUCCESS(rc))
    497                     rc = videoRecEncodeAndWrite(pStream);
    498 
    499                 if (RT_FAILURE(rc))
     593            }
     594
     595            PVIDEORECVIDEOFRAME pVideoFrame = &pStream->Video.Frame;
     596            const bool fEncodeVideo = pStream->Video.fHasVideoData;
     597
     598            if (fEncodeVideo)
     599            {
     600                pStream->Video.fHasVideoData = false;
     601
     602                rc = videoRecRGBToYUV(pVideoFrame->uPixelFormat,
     603                                      /* Destination */
     604                                      pStream->Video.pu8YuvBuf, pVideoFrame->uWidth, pVideoFrame->uHeight,
     605                                      /* Source */
     606                                      pVideoFrame->pu8RGBBuf, pStream->Video.uWidth, pStream->Video.uHeight);
     607            }
     608
     609            if (   fEncodeVideo
     610                && RT_SUCCESS(rc))
     611            {
     612                rc = videoRecEncodeAndWrite(pStream, pVideoFrame);
     613            }
     614
     615            videoRecStreamUnlock(pStream);
     616
     617            if (RT_FAILURE(rc))
     618            {
     619                static unsigned s_cErrEnc = 100;
     620                if (s_cErrEnc > 0)
    500621                {
    501                     static unsigned s_cErrEnc = 100;
    502                     if (s_cErrEnc > 0)
    503                     {
    504                         LogRel(("VideoRec: Error %Rrc encoding / writing video frame\n", rc));
    505                         s_cErrEnc--;
    506                     }
     622                    LogRel(("VideoRec: Error %Rrc encoding / writing video frame\n", rc));
     623                    s_cErrEnc--;
    507624                }
    508625            }
    509626
    510627#ifdef VBOX_WITH_AUDIO_VIDEOREC
    511             /* Each (enabled) screen has to get the audio data. */
    512             if (fHasAudioData)
    513             {
    514                 WebMWriter::BlockData_Opus blockData = { pCtx->Audio.abBuf, pCtx->Audio.cbBuf, pCtx->Audio.uTimeStampMs };
     628            /* Each (enabled) screen has to get the same audio data. */
     629            if (fEncodeAudio)
     630            {
     631                WebMWriter::BlockData_Opus blockData = { pAudioFrame->abBuf, pAudioFrame->cbBuf, pAudioFrame->uTimeStampMs };
    515632                rc = pStream->pEBML->WriteBlock(pStream->uTrackAudio, &blockData, sizeof(blockData));
    516633            }
    517634#endif
    518         } /* for */
    519 
    520 #ifdef VBOX_WITH_AUDIO_VIDEOREC
    521         if (fHasAudioData)
    522             ASMAtomicWriteBool(&pCtx->fHasAudioData, false);
    523 #endif
     635        }
    524636    }
    525637
     
    539651    AssertPtrReturn(ppCtx, VERR_INVALID_POINTER);
    540652
    541     int rc = VINF_SUCCESS;
    542 
    543653    PVIDEORECCONTEXT pCtx = (PVIDEORECCONTEXT)RTMemAllocZ(sizeof(VIDEORECCONTEXT));
    544654    if (!pCtx)
    545655        return VERR_NO_MEMORY;
    546656
     657    int rc = RTCritSectInit(&pCtx->CritSect);
     658    if (RT_FAILURE(rc))
     659        return rc;
     660
    547661    for (uint32_t uScreen = 0; uScreen < cScreens; uScreen++)
    548662    {
     
    554668        }
    555669
     670        rc = RTCritSectInit(&pStream->CritSect);
     671        if (RT_FAILURE(rc))
     672            break;
     673
    556674        try
    557675        {
    558             pStream->uScreen = uScreen;
     676            pStream->uScreenID = uScreen;
    559677
    560678            pCtx->vecStreams.push_back(pStream);
     
    585703        if (RT_SUCCESS(rc))
    586704        {
    587             pCtx->enmState = VIDEORECSTS_IDLE;
     705            pCtx->enmState = VIDEORECSTS_INITIALIZED;
    588706            pCtx->fEnabled = true;
    589707
     
    651769            pStream->pEBML->Close();
    652770
    653             vpx_img_free(&pStream->Codec.VPX.RawImage);
    654             vpx_codec_err_t rcv = vpx_codec_destroy(&pStream->Codec.VPX.CodecCtx);
     771            vpx_img_free(&pStream->Video.Codec.VPX.RawImage);
     772            vpx_codec_err_t rcv = vpx_codec_destroy(&pStream->Video.Codec.VPX.Ctx);
    655773            Assert(rcv == VPX_CODEC_OK); RT_NOREF(rcv);
    656774
    657             if (pStream->Video.pu8RgbBuf)
    658             {
    659                 RTMemFree(pStream->Video.pu8RgbBuf);
    660                 pStream->Video.pu8RgbBuf = NULL;
    661             }
    662 
    663             LogRel(("VideoRec: Recording screen #%u stopped\n", pStream->uScreen));
     775#ifdef VBOX_VIDEOREC_WITH_QUEUE
     776# error "Implement me!"
     777#else
     778            PVIDEORECVIDEOFRAME pFrame = &pStream->Video.Frame;
     779#endif
     780            if (pFrame->pu8RGBBuf)
     781            {
     782                Assert(pFrame->cbRGBBuf);
     783
     784                RTMemFree(pFrame->pu8RGBBuf);
     785                pFrame->pu8RGBBuf = NULL;
     786            }
     787
     788            pFrame->cbRGBBuf = 0;
     789
     790            LogRel(("VideoRec: Recording screen #%u stopped\n", pStream->uScreenID));
    664791        }
    665792
     
    672799        it = pCtx->vecStreams.erase(it);
    673800
     801        RTCritSectDelete(&pStream->CritSect);
     802
    674803        RTMemFree(pStream);
    675804        pStream = NULL;
     
    677806
    678807    Assert(pCtx->vecStreams.empty());
     808
     809    RTCritSectDelete(&pCtx->CritSect);
    679810
    680811    RTMemFree(pCtx);
     
    707838
    708839    return pStream;
     840}
     841
     842/**
     843 * Locks a recording stream.
     844 *
     845 * @returns IPRT status code.
     846 * @param   pStream             Recording stream to lock.
     847 */
     848int videoRecStreamLock(PVIDEORECSTREAM pStream)
     849{
     850    int rc = RTCritSectEnter(&pStream->CritSect);
     851    AssertRC(rc);
     852
     853    return rc;
     854}
     855
     856/**
     857 * Unlocks a locked recording stream.
     858 *
     859 * @returns IPRT status code.
     860 * @param   pStream             Recording stream to unlock.
     861 */
     862int videoRecStreamUnlock(PVIDEORECSTREAM pStream)
     863{
     864    int rc = RTCritSectLeave(&pStream->CritSect);
     865    AssertRC(rc);
     866
     867    return rc;
    709868}
    710869
     
    743902    pCtx->uMaxSizeMB = uMaxSizeMB;
    744903
    745     pStream->Video.uDstWidth  = uWidth;
    746     pStream->Video.uDstHeight = uHeight;
    747     pStream->Video.pu8RgbBuf = (uint8_t *)RTMemAllocZ(uWidth * uHeight * 4);
    748     AssertReturn(pStream->Video.pu8RgbBuf, VERR_NO_MEMORY);
    749 
    750     /* Play safe: the file must not exist, overwriting is potentially
    751      * hazardous as nothing prevents the user from picking a file name of some
    752      * other important file, causing unintentional data loss. */
     904    pStream->Video.uWidth  = uWidth;
     905    pStream->Video.uHeight = uHeight;
     906
     907#ifndef VBOX_VIDEOREC_WITH_QUEUE
     908    /* When not using a queue, we only use one frame per stream at once.
     909     * So do the initialization here. */
     910    PVIDEORECVIDEOFRAME pFrame = &pStream->Video.Frame;
     911
     912    const size_t cbRGBBuf =   pStream->Video.uWidth
     913                            * pStream->Video.uHeight
     914                            * 4 /* 32 BPP maximum */;
     915    AssertReturn(cbRGBBuf, VERR_INVALID_PARAMETER);
     916
     917    pFrame->pu8RGBBuf = (uint8_t *)RTMemAllocZ(cbRGBBuf);
     918    AssertReturn(pFrame->pu8RGBBuf, VERR_NO_MEMORY);
     919    pFrame->cbRGBBuf  = cbRGBBuf;
     920#endif
     921
     922    PVIDEORECVIDEOCODEC pVC = &pStream->Video.Codec;
    753923
    754924#ifdef VBOX_WITH_LIBVPX
    755     pStream->Video.uEncoderDeadline = VPX_DL_REALTIME;
    756 
    757     vpx_codec_err_t rcv = vpx_codec_enc_config_default(DEFAULTCODEC, &pStream->Codec.VPX.Config, 0);
     925    pVC->VPX.uEncoderDeadline = VPX_DL_REALTIME;
     926
     927    vpx_codec_err_t rcv = vpx_codec_enc_config_default(DEFAULTCODEC, &pVC->VPX.Cfg, 0);
    758928    if (rcv != VPX_CODEC_OK)
    759929    {
     
    767937
    768938    /* By default we enable everything (if available). */
    769     bool fHasVideoTrack = true;
     939    bool     fHasVideoTrack = true;
    770940#ifdef VBOX_WITH_AUDIO_VIDEOREC
    771941    bool     fHasAudioTrack = true;
     
    784954            {
    785955#ifdef VBOX_WITH_LIBVPX
    786                 pStream->Video.uEncoderDeadline = VPX_DL_REALTIME;
     956                pVC->VPX.uEncoderDeadline = VPX_DL_REALTIME;
    787957#endif
    788958            }
    789959            else if (value.compare("good", Utf8Str::CaseInsensitive) == 0)
    790960            {
    791                 pStream->Video.uEncoderDeadline = 1000000 / uFPS;
     961                pVC->VPX.uEncoderDeadline = 1000000 / uFPS;
    792962            }
    793963            else if (value.compare("best", Utf8Str::CaseInsensitive) == 0)
    794964            {
    795965#ifdef VBOX_WITH_LIBVPX
    796                 pStream->Video.uEncoderDeadline = VPX_DL_BEST_QUALITY;
     966                pVC->VPX.uEncoderDeadline = VPX_DL_BEST_QUALITY;
    797967#endif
    798968            }
     
    800970            {
    801971                LogRel(("VideoRec: Setting quality deadline to '%s'\n", value.c_str()));
    802                 pStream->Video.uEncoderDeadline = value.toUInt32();
     972                pVC->VPX.uEncoderDeadline = value.toUInt32();
    803973            }
    804974        }
     
    806976        {
    807977#ifdef VBOX_WITH_AUDIO_VIDEOREC
    808             if (value.compare("false", Utf8Str::CaseInsensitive) == 0) /* Disable audio. */
     978            if (value.compare("false", Utf8Str::CaseInsensitive) == 0)
    809979            {
    810980                fHasVideoTrack = false;
     
    816986        {
    817987#ifdef VBOX_WITH_AUDIO_VIDEOREC
    818             if (value.compare("false", Utf8Str::CaseInsensitive)) /* Disable audio. */
     988            if (value.compare("false", Utf8Str::CaseInsensitive))
    819989            {
    820990                fHasAudioTrack = false;
     
    8531023    fOpen |= RTFILE_O_CREATE_REPLACE;
    8541024#else
     1025    /* Play safe: the file must not exist, overwriting is potentially
     1026     * hazardous as nothing prevents the user from picking a file name of some
     1027     * other important file, causing unintentional data loss. */
    8551028    fOpen |= RTFILE_O_CREATE;
    8561029#endif
    8571030
    858     int rc = pStream->pEBML->Create(pszFile, fOpen, WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_VP8);
     1031    int rc = pStream->pEBML->Create(pszFile, fOpen,
     1032#ifdef VBOX_WITH_AUDIO_VIDEOREC
     1033                                    fHasAudioTrack ? WebMWriter::AudioCodec_Opus : WebMWriter::AudioCodec_None,
     1034#else
     1035                                    WebMWriter::AudioCodec_None,
     1036#endif
     1037                                    fHasVideoTrack ? WebMWriter::VideoCodec_VP8 : WebMWriter::VideoCodec_None);
    8591038    if (RT_FAILURE(rc))
    8601039    {
     
    9151094#ifdef VBOX_WITH_LIBVPX
    9161095    /* Target bitrate in kilobits per second. */
    917     pStream->Codec.VPX.Config.rc_target_bitrate = uRate;
     1096    pVC->VPX.Cfg.rc_target_bitrate = uRate;
    9181097    /* Frame width. */
    919     pStream->Codec.VPX.Config.g_w = uWidth;
     1098    pVC->VPX.Cfg.g_w = uWidth;
    9201099    /* Frame height. */
    921     pStream->Codec.VPX.Config.g_h = uHeight;
     1100    pVC->VPX.Cfg.g_h = uHeight;
    9221101    /* 1ms per frame. */
    923     pStream->Codec.VPX.Config.g_timebase.num = 1;
    924     pStream->Codec.VPX.Config.g_timebase.den = 1000;
     1102    pVC->VPX.Cfg.g_timebase.num = 1;
     1103    pVC->VPX.Cfg.g_timebase.den = 1000;
    9251104    /* Disable multithreading. */
    926     pStream->Codec.VPX.Config.g_threads = 0;
     1105    pVC->VPX.Cfg.g_threads = 0;
    9271106
    9281107    /* Initialize codec. */
    929     rcv = vpx_codec_enc_init(&pStream->Codec.VPX.CodecCtx, DEFAULTCODEC, &pStream->Codec.VPX.Config, 0);
     1108    rcv = vpx_codec_enc_init(&pVC->VPX.Ctx, DEFAULTCODEC, &pVC->VPX.Cfg, 0);
    9301109    if (rcv != VPX_CODEC_OK)
    9311110    {
     
    9341113    }
    9351114
    936     if (!vpx_img_alloc(&pStream->Codec.VPX.RawImage, VPX_IMG_FMT_I420, uWidth, uHeight, 1))
     1115    if (!vpx_img_alloc(&pVC->VPX.RawImage, VPX_IMG_FMT_I420, uWidth, uHeight, 1))
    9371116    {
    9381117        LogFlow(("Failed to allocate image %dx%d", uWidth, uHeight));
     
    9401119    }
    9411120
    942     pStream->Video.pu8YuvBuf = pStream->Codec.VPX.RawImage.planes[0];
     1121    /* Save a pointer to the first raw YUV plane. */
     1122    pStream->Video.pu8YuvBuf = pVC->VPX.RawImage.planes[0];
    9431123#endif
    9441124    pStream->fEnabled = true;
     
    9581138        return false;
    9591139
    960     uint32_t enmState = ASMAtomicReadU32(&pCtx->enmState);
    961 
    962     return (   enmState == VIDEORECSTS_IDLE
    963             || enmState == VIDEORECSTS_BUSY);
     1140    return ASMAtomicReadBool(&pCtx->fEnabled);
    9641141}
    9651142
     
    9771154    AssertPtrReturn(pCtx, false);
    9781155
    979     uint32_t enmState = ASMAtomicReadU32(&pCtx->enmState);
    980     if (enmState != VIDEORECSTS_IDLE)
     1156    if (ASMAtomicReadU32(&pCtx->enmState) != VIDEORECSTS_INITIALIZED)
    9811157        return false;
    9821158
     
    9881164    }
    9891165
    990     if (uTimeStampMs < pStream->uLastTimeStampMs + pStream->Video.uDelayMs)
     1166    PVIDEORECVIDEOFRAME pLastFrame = &pStream->Video.Frame;
     1167
     1168    if (uTimeStampMs < pLastFrame->uTimeStampMs + pStream->Video.uDelayMs)
    9911169        return false;
    992 
    993     if (   ASMAtomicReadBool(&pStream->fHasVideoData)
    994 #ifdef VBOX_WITH_AUDIO_VIDEOREC
    995         /* Check if we have audio data left for the current frame. */
    996         || ASMAtomicReadBool(&pCtx->fHasAudioData)
    997 #endif
    998        )
    999     {
    1000         return false;
    1001     }
    10021170
    10031171    return true;
     
    10351203            return true;
    10361204    }
     1205
    10371206    /* Check for available free disk space */
    1038     if (pStream->pEBML->GetAvailableSpace() < 0x100000)
     1207    if (   pStream->pEBML
     1208        && pStream->pEBML->GetAvailableSpace() < 0x100000) /**@todo r=andy WTF? Fix this. */
    10391209    {
    10401210        LogRel(("VideoRec: Not enough free storage space available, stopping video capture\n"));
     
    10501220 *
    10511221 * @returns IPRT status code.
    1052  * @param   pStream             Stream to encode and write.
    1053  */
    1054 static int videoRecEncodeAndWrite(PVIDEORECSTREAM pStream)
     1222 * @param   pStream             Stream to encode and submit to.
     1223 * @param   pFrame              Frame to encode and submit.
     1224 */
     1225static int videoRecEncodeAndWrite(PVIDEORECSTREAM pStream, PVIDEORECVIDEOFRAME pFrame)
    10551226{
    10561227    int rc;
     1228
     1229    PVIDEORECVIDEOCODEC pVC = &pStream->Video.Codec;
    10571230
    10581231#ifdef VBOX_WITH_LIBVPX
    10591232    /* Presentation Time Stamp (PTS). */
    1060     vpx_codec_pts_t pts = pStream->uCurTimeStampMs;
    1061     vpx_codec_err_t rcv = vpx_codec_encode(&pStream->Codec.VPX.CodecCtx,
    1062                                            &pStream->Codec.VPX.RawImage,
    1063                                            pts                           /* Time stamp */,
    1064                                            pStream->Video.uDelayMs               /* How long to show this frame */,
    1065                                            0                             /* Flags */,
    1066                                            pStream->Video.uEncoderDeadline    /* Quality setting */);
     1233    vpx_codec_pts_t pts = pFrame->uTimeStampMs;
     1234    vpx_codec_err_t rcv = vpx_codec_encode(&pVC->VPX.Ctx,
     1235                                           &pVC->VPX.RawImage,
     1236                                           pts                       /* Time stamp */,
     1237                                           pStream->Video.uDelayMs   /* How long to show this frame */,
     1238                                           0                         /* Flags */,
     1239                                           pVC->VPX.uEncoderDeadline /* Quality setting */);
    10671240    if (rcv != VPX_CODEC_OK)
    10681241    {
     
    10751248    for (;;)
    10761249    {
    1077         const vpx_codec_cx_pkt_t *pPacket = vpx_codec_get_cx_data(&pStream->Codec.VPX.CodecCtx, &iter);
     1250        const vpx_codec_cx_pkt_t *pPacket = vpx_codec_get_cx_data(&pVC->VPX.Ctx, &iter);
    10781251        if (!pPacket)
    10791252            break;
     
    10831256            case VPX_CODEC_CX_FRAME_PKT:
    10841257            {
    1085                 WebMWriter::BlockData_VP8 blockData = { &pStream->Codec.VPX.Config, pPacket };
     1258                WebMWriter::BlockData_VP8 blockData = { &pVC->VPX.Cfg, pPacket };
    10861259                rc = pStream->pEBML->WriteBlock(pStream->uTrackVideo, &blockData, sizeof(blockData));
    10871260                break;
     
    11051278 *
    11061279 * @returns IPRT status code.
    1107  * @param   pStream             Recording stream to convert RGB to YUV video frame buffer for.
    1108  */
    1109 static int videoRecRGBToYUV(PVIDEORECSTREAM pStream)
    1110 {
    1111     switch (pStream->Video.uPixelFormat)
     1280 * TODO
     1281 */
     1282static int videoRecRGBToYUV(uint32_t uPixelFormat,
     1283                            uint8_t *paDst, uint32_t uDstWidth, uint32_t uDstHeight,
     1284                            uint8_t *paSrc, uint32_t uSrcWidth, uint32_t uSrcHeight)
     1285{
     1286    switch (uPixelFormat)
    11121287    {
    11131288        case VIDEORECPIXELFMT_RGB32:
    1114             LogFlow(("32 bit\n"));
    1115             if (!colorConvWriteYUV420p<ColorConvBGRA32Iter>(pStream->Video.uDstWidth,
    1116                                                             pStream->Video.uDstHeight,
    1117                                                             pStream->Video.pu8YuvBuf,
    1118                                                             pStream->Video.pu8RgbBuf))
     1289            if (!colorConvWriteYUV420p<ColorConvBGRA32Iter>(paDst, uDstWidth, uDstHeight,
     1290                                                            paSrc, uSrcWidth, uSrcHeight))
    11191291                return VERR_INVALID_PARAMETER;
    11201292            break;
    11211293        case VIDEORECPIXELFMT_RGB24:
    1122             LogFlow(("24 bit\n"));
    1123             if (!colorConvWriteYUV420p<ColorConvBGR24Iter>(pStream->Video.uDstWidth,
    1124                                                            pStream->Video.uDstHeight,
    1125                                                            pStream->Video.pu8YuvBuf,
    1126                                                            pStream->Video.pu8RgbBuf))
     1294            if (!colorConvWriteYUV420p<ColorConvBGR24Iter>(paDst, uDstWidth, uDstHeight,
     1295                                                           paSrc, uSrcWidth, uSrcHeight))
    11271296                return VERR_INVALID_PARAMETER;
    11281297            break;
    11291298        case VIDEORECPIXELFMT_RGB565:
    1130             LogFlow(("565 bit\n"));
    1131             if (!colorConvWriteYUV420p<ColorConvBGR565Iter>(pStream->Video.uDstWidth,
    1132                                                             pStream->Video.uDstHeight,
    1133                                                             pStream->Video.pu8YuvBuf,
    1134                                                             pStream->Video.pu8RgbBuf))
     1299            if (!colorConvWriteYUV420p<ColorConvBGR565Iter>(paDst, uDstWidth, uDstHeight,
     1300                                                            paSrc, uSrcWidth, uSrcHeight))
    11351301                return VERR_INVALID_PARAMETER;
    11361302            break;
    11371303        default:
     1304            AssertFailed();
    11381305            return VERR_NOT_SUPPORTED;
    11391306    }
     
    11571324    AssertReturn(cbData <= _64K, VERR_INVALID_PARAMETER);
    11581325
    1159     /* Do not execute during termination and guard against termination. */
    1160     if (!ASMAtomicCmpXchgU32(&pCtx->enmState, VIDEORECSTS_BUSY, VIDEORECSTS_IDLE))
    1161         return VINF_TRY_AGAIN;
     1326    int rc = RTCritSectEnter(&pCtx->CritSect);
     1327    if (RT_FAILURE(rc))
     1328        return rc;
    11621329
    11631330    /* To save time spent in EMT, do the required audio multiplexing in the encoding thread.
     
    11661333     * audio data at the same given point in time.
    11671334     */
    1168 
    1169     if (ASMAtomicReadBool(&pCtx->fHasAudioData))
    1170         return VERR_TRY_AGAIN; /* Previous frame not yet encoded. */
    1171 
    1172     memcpy(pCtx->Audio.abBuf, pvData, RT_MIN(_64K, cbData));
    1173 
    1174     pCtx->Audio.cbBuf        = cbData;
    1175     pCtx->Audio.uTimeStampMs = uTimeStampMs;
    1176 
    1177     ASMAtomicWriteBool(&pCtx->fHasAudioData, true);
    1178     RTSemEventSignal(pCtx->WaitEvent);
     1335    PVIDEORECAUDIOFRAME pFrame = &pCtx->Audio.Frame;
     1336
     1337    memcpy(pFrame->abBuf, pvData, RT_MIN(_64K /** @todo Fix! */, cbData));
     1338
     1339    pFrame->cbBuf        = cbData;
     1340    pFrame->uTimeStampMs = uTimeStampMs;
     1341
     1342    pCtx->Audio.fHasAudioData = true;
     1343
     1344    rc = RTCritSectLeave(&pCtx->CritSect);
     1345    if (RT_SUCCESS(rc))
     1346        rc = RTSemEventSignal(pCtx->WaitEvent);
     1347
     1348    return rc;
    11791349#else
    11801350    RT_NOREF(pCtx, pvData, cbData, uTimeStampMs);
    1181 #endif
    11821351    return VINF_SUCCESS;
     1352#endif
    11831353}
    11841354
     
    12071377                           uint64_t uTimeStampMs)
    12081378{
    1209     /* Do not execute during termination and guard against termination. */
    1210     if (!ASMAtomicCmpXchgU32(&pCtx->enmState, VIDEORECSTS_BUSY, VIDEORECSTS_IDLE))
    1211         return VINF_TRY_AGAIN;
    1212 
    1213     int rc = VINF_SUCCESS;
     1379    AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
     1380    AssertReturn(uSrcWidth,  VERR_INVALID_PARAMETER);
     1381    AssertReturn(uSrcHeight, VERR_INVALID_PARAMETER);
     1382    AssertReturn(puSrcData,  VERR_INVALID_POINTER);
     1383
     1384    PVIDEORECSTREAM pStream = videoRecStreamGet(pCtx, uScreen);
     1385    if (!pStream)
     1386        return VERR_NOT_FOUND;
     1387
     1388    int rc = RTCritSectEnter(&pStream->CritSect);
     1389    if (RT_FAILURE(rc))
     1390        return rc;
     1391
    12141392    do
    12151393    {
    1216         AssertPtrBreakStmt(pCtx,      rc = VERR_INVALID_POINTER);
    1217         AssertBreakStmt(uSrcWidth,    rc = VERR_INVALID_PARAMETER);
    1218         AssertBreakStmt(uSrcHeight,   rc = VERR_INVALID_PARAMETER);
    1219         AssertPtrBreakStmt(puSrcData, rc = VERR_INVALID_POINTER);
    1220 
    1221         PVIDEORECSTREAM pStream = videoRecStreamGet(pCtx, uScreen);
    1222         if (!pStream)
    1223         {
    1224             rc = VERR_NOT_FOUND;
    1225             break;
    1226         }
    1227 
    12281394        if (!pStream->fEnabled)
    12291395        {
     
    12321398        }
    12331399
    1234         if (uTimeStampMs < pStream->uLastTimeStampMs + pStream->Video.uDelayMs)
     1400        if (uTimeStampMs < pStream->Video.uLastTimeStampMs + pStream->Video.uDelayMs)
    12351401        {
    12361402            rc = VINF_TRY_AGAIN; /* Respect maximum frames per second. */
     
    12381404        }
    12391405
    1240         if (ASMAtomicReadBool(&pStream->fHasVideoData))
    1241         {
    1242             rc = VERR_TRY_AGAIN; /* Previous frame not yet encoded. */
    1243             break;
    1244         }
    1245 
    1246         pStream->uLastTimeStampMs = uTimeStampMs;
    1247 
    1248         int xDiff = ((int)pStream->Video.uDstWidth - (int)uSrcWidth) / 2;
     1406        pStream->Video.uLastTimeStampMs = uTimeStampMs;
     1407
     1408        int xDiff = ((int)pStream->Video.uWidth - (int)uSrcWidth) / 2;
    12491409        uint32_t w = uSrcWidth;
    12501410        if ((int)w + xDiff + (int)x <= 0)  /* Nothing visible. */
     
    12651425
    12661426        uint32_t h = uSrcHeight;
    1267         int yDiff = ((int)pStream->Video.uDstHeight - (int)uSrcHeight) / 2;
     1427        int yDiff = ((int)pStream->Video.uHeight - (int)uSrcHeight) / 2;
    12681428        if ((int)h + yDiff + (int)y <= 0)  /* Nothing visible. */
    12691429        {
     
    12821442            destY = y + yDiff;
    12831443
    1284         if (   destX > pStream->Video.uDstWidth
    1285             || destY > pStream->Video.uDstHeight)
     1444        if (   destX > pStream->Video.uWidth
     1445            || destY > pStream->Video.uHeight)
    12861446        {
    12871447            rc = VERR_INVALID_PARAMETER;  /* Nothing visible. */
     
    12891449        }
    12901450
    1291         if (destX + w > pStream->Video.uDstWidth)
    1292             w = pStream->Video.uDstWidth - destX;
    1293 
    1294         if (destY + h > pStream->Video.uDstHeight)
    1295             h = pStream->Video.uDstHeight - destY;
    1296 
    1297         /* Calculate bytes per pixel. */
    1298         uint32_t bpp = 1;
     1451        if (destX + w > pStream->Video.uWidth)
     1452            w = pStream->Video.uWidth - destX;
     1453
     1454        if (destY + h > pStream->Video.uHeight)
     1455            h = pStream->Video.uHeight - destY;
     1456
     1457#ifdef VBOX_VIDEOREC_WITH_QUEUE
     1458# error "Implement me!"
     1459#else
     1460        PVIDEORECVIDEOFRAME pFrame = &pStream->Video.Frame;
     1461#endif
     1462        /* Calculate bytes per pixel and set pixel format. */
     1463        const unsigned uBytesPerPixel = uBPP / 8;
    12991464        if (uPixelFormat == BitmapFormat_BGR)
    13001465        {
     
    13021467            {
    13031468                case 32:
    1304                     pStream->Video.uPixelFormat = VIDEORECPIXELFMT_RGB32;
    1305                     bpp = 4;
     1469                    pFrame->uPixelFormat = VIDEORECPIXELFMT_RGB32;
    13061470                    break;
    13071471                case 24:
    1308                     pStream->Video.uPixelFormat = VIDEORECPIXELFMT_RGB24;
    1309                     bpp = 3;
     1472                    pFrame->uPixelFormat = VIDEORECPIXELFMT_RGB24;
    13101473                    break;
    13111474                case 16:
    1312                     pStream->Video.uPixelFormat = VIDEORECPIXELFMT_RGB565;
    1313                     bpp = 2;
     1475                    pFrame->uPixelFormat = VIDEORECPIXELFMT_RGB565;
    13141476                    break;
    13151477                default:
    1316                     AssertMsgFailed(("Unknown color depth! mBitsPerPixel=%d\n", uBPP));
     1478                    AssertMsgFailed(("Unknown color depth (%RU32)\n", uBPP));
    13171479                    break;
    13181480            }
    13191481        }
    13201482        else
    1321             AssertMsgFailed(("Unknown pixel format! mPixelFormat=%d\n", pStream->Video.uPixelFormat));
    1322 
    1323         /* One of the dimensions of the current frame is smaller than before so
    1324          * clear the entire buffer to prevent artifacts from the previous frame. */
    1325         if (   uSrcWidth  < pStream->Video.uSrcLastWidth
    1326             || uSrcHeight < pStream->Video.uSrcLastHeight)
    1327             memset(pStream->Video.pu8RgbBuf, 0, pStream->Video.uDstWidth * pStream->Video.uDstHeight * 4);
    1328 
    1329         pStream->Video.uSrcLastWidth  = uSrcWidth;
    1330         pStream->Video.uSrcLastHeight = uSrcHeight;
    1331 
     1483            AssertMsgFailed(("Unknown pixel format (%RU32)\n", uPixelFormat));
     1484
     1485#ifndef VBOX_VIDEOREC_WITH_QUEUE
     1486        /* If we don't use a queue then we have to compare the dimensions
     1487         * of the current frame with the previous frame:
     1488         *
     1489         * If it's smaller than before then clear the entire buffer to prevent artifacts
     1490         * from the previous frame. */
     1491        if (   uSrcWidth  < pFrame->uWidth
     1492            || uSrcHeight < pFrame->uHeight)
     1493        {
     1494            /** @todo r=andy Only clear dirty areas. */
     1495            RT_BZERO(pFrame->pu8RGBBuf, pFrame->cbRGBBuf);
     1496        }
     1497#endif
    13321498        /* Calculate start offset in source and destination buffers. */
    1333         uint32_t offSrc = y * uBytesPerLine + x * bpp;
    1334         uint32_t offDst = (destY * pStream->Video.uDstWidth + destX) * bpp;
     1499        uint32_t offSrc = y * uBytesPerLine + x * uBytesPerPixel;
     1500        uint32_t offDst = (destY * pStream->Video.uWidth + destX) * uBytesPerPixel;
     1501
     1502#ifdef VBOX_VIDEOREC_DUMP
     1503        VIDEORECBMPHDR bmpHdr;
     1504        RT_ZERO(bmpHdr);
     1505
     1506        VIDEORECBMPDIBHDR bmpDIBHdr;
     1507        RT_ZERO(bmpDIBHdr);
     1508
     1509        bmpHdr.u16Magic   = 0x4d42; /* Magic */
     1510        bmpHdr.u32Size    = (uint32_t)(sizeof(VIDEORECBMPHDR) + sizeof(VIDEORECBMPDIBHDR) + (w * h * uBytesPerPixel));
     1511        bmpHdr.u32OffBits = (uint32_t)(sizeof(VIDEORECBMPHDR) + sizeof(VIDEORECBMPDIBHDR));
     1512
     1513        bmpDIBHdr.u32Size          = sizeof(VIDEORECBMPDIBHDR);
     1514        bmpDIBHdr.u32Width         = w;
     1515        bmpDIBHdr.u32Height        = h;
     1516        bmpDIBHdr.u16Planes        = 1;
     1517        bmpDIBHdr.u16BitCount      = uBPP;
     1518        bmpDIBHdr.u32XPelsPerMeter = 5000;
     1519        bmpDIBHdr.u32YPelsPerMeter = 5000;
     1520
     1521        RTFILE fh;
     1522        int rc2 = RTFileOpen(&fh, "/tmp/VideoRecFrame.bmp",
     1523                             RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
     1524        if (RT_SUCCESS(rc2))
     1525        {
     1526            RTFileWrite(fh, &bmpHdr,    sizeof(bmpHdr),    NULL);
     1527            RTFileWrite(fh, &bmpDIBHdr, sizeof(bmpDIBHdr), NULL);
     1528        }
     1529#endif
     1530        Assert(pFrame->cbRGBBuf >= w * h * uBytesPerPixel);
    13351531
    13361532        /* Do the copy. */
     
    13381534        {
    13391535            /* Overflow check. */
    1340             Assert(offSrc + w * bpp <= uSrcHeight * uBytesPerLine);
    1341             Assert(offDst + w * bpp <= pStream->Video.uDstHeight * pStream->Video.uDstWidth * bpp);
    1342 
    1343             memcpy(pStream->Video.pu8RgbBuf + offDst, puSrcData + offSrc, w * bpp);
    1344 
     1536            Assert(offSrc + w * uBytesPerPixel <= uSrcHeight * uBytesPerLine);
     1537            Assert(offDst + w * uBytesPerPixel <= pStream->Video.uHeight * pStream->Video.uWidth * uBytesPerPixel);
     1538
     1539            memcpy(pFrame->pu8RGBBuf + offDst, puSrcData + offSrc, w * uBytesPerPixel);
     1540
     1541#ifdef VBOX_VIDEOREC_DUMP
     1542            if (RT_SUCCESS(rc2))
     1543                RTFileWrite(fh, pFrame->pu8RGBBuf + offDst, w * uBytesPerPixel, NULL);
     1544#endif
    13451545            offSrc += uBytesPerLine;
    1346             offDst += pStream->Video.uDstWidth * bpp;
    1347         }
    1348 
    1349         pStream->uCurTimeStampMs = uTimeStampMs;
    1350 
    1351         ASMAtomicWriteBool(&pStream->fHasVideoData, true);
    1352         RTSemEventSignal(pCtx->WaitEvent);
     1546            offDst += pStream->Video.uWidth * uBytesPerPixel;
     1547        }
     1548
     1549#ifdef VBOX_VIDEOREC_DUMP
     1550        if (RT_SUCCESS(rc2))
     1551            RTFileClose(fh);
     1552#endif
     1553        pFrame->uTimeStampMs = uTimeStampMs;
     1554        pFrame->uWidth       = uSrcWidth;
     1555        pFrame->uHeight      = uSrcHeight;
     1556
     1557        pStream->Video.fHasVideoData = true;
    13531558
    13541559    } while (0);
    13551560
    1356     ASMAtomicCmpXchgU32(&pCtx->enmState, VIDEORECSTS_IDLE, VIDEORECSTS_BUSY);
     1561    int rc2 = RTCritSectLeave(&pStream->CritSect);
     1562    if (RT_SUCCESS(rc2))
     1563    {
     1564        if (   RT_SUCCESS(rc)
     1565            && rc != VINF_TRY_AGAIN) /* Only signal the thread if operation was successful. */
     1566        {
     1567            rc2 = RTSemEventSignal(pCtx->WaitEvent);
     1568        }
     1569    }
     1570
     1571    if (RT_SUCCESS(rc))
     1572        rc = rc2;
    13571573
    13581574    return rc;
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