VirtualBox

Changeset 105095 in vbox


Ignore:
Timestamp:
Jul 2, 2024 10:06:48 AM (5 months ago)
Author:
vboxsync
Message:

Video Recording/Main: More optimizations for recording older guests which have a slightly different screen update logic. bugref:10650

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

Legend:

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

    r105006 r105095  
    205205    int i_recordingStop(util::AutoWriteLock *pAutoLock = NULL);
    206206    int i_recordingCursorShapeChange(bool fVisible, bool fAlpha, uint32_t xHot, uint32_t yHot, uint32_t uWidth, uint32_t uHeight, const uint8_t *pu8Shape, uint32_t cbShape);
     207    static DECLCALLBACK(void) s_recordingOnStateChangedCallback(RecordingContext *pCtx, RECORDINGSTS enmSts, uint32_t uScreen, int vrc, void *pvUser);
    207208# ifdef VBOX_WITH_AUDIO_RECORDING
    208209    AudioVideoRec *i_recordingGetAudioDrv(void) const { return mRecording.mAudioRec; }
  • trunk/src/VBox/Main/include/DisplayImpl.h

    r105006 r105095  
    4646#ifdef VBOX_WITH_RECORDING
    4747# include "RecordingInternals.h"
     48class RecordingContext;
    4849#endif
    4950
     
    188189    int i_recordingStart(void);
    189190    int i_recordingStop(void);
    190     int i_recordingInvalidate(bool fForce = false);
     191    int i_recordingInvalidate(void);
    191192    int i_recordingScreenChanged(unsigned uScreenId, const DISPLAYFBINFO *pFBInfo);
    192     int i_recordingScreenUpdate(unsigned uScreenId, PRECORDINGVIDEOFRAME pFrame);
     193    int i_recordingScreenUpdate(unsigned uScreenId, uint8_t *pauFramebuffer, size_t cbFramebuffer, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t uBytesPerLine);
     194    int i_recordingScreenUpdate(unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h);
    193195    int i_recordingCursorPositionChange(unsigned uScreenId, uint32_t fFlags, int32_t x, int32_t y);
    194196#endif
     
    414416
    415417#ifdef VBOX_WITH_RECORDING
    416     /* Serializes access to video recording source bitmaps. */
    417     RTCRITSECT           mVideoRecLock;
    418     /** Array which defines which screens are being enabled for recording. */
    419     bool                 maRecordingEnabled[SchemaDefs::MaxGuestMonitors];
     418    /** Struct which holds information and state about (video) recording. */
     419    struct Recording
     420    {
     421        Recording()
     422            : pCtx(NULL) { }
     423
     424        /** Recording context. Constant across lifetime.
     425         *  Might be NULL if not being used. */
     426        RecordingContext * const pCtx;
     427    } Recording;
    420428#endif
    421429
    422430#ifdef VBOX_WITH_STATISTICS
     431    /** Struct for keeping STAM values. */
    423432    struct
    424433    {
  • trunk/src/VBox/Main/include/Recording.h

    r105006 r105095  
    7171
    7272/**
     73 * Enumeration for a recording context state.
     74 */
     75enum RECORDINGSTS
     76{
     77    /** Recording not initialized. */
     78    RECORDINGSTS_UNINITIALIZED = 0,
     79    /** Recording was created. */
     80    RECORDINGSTS_CREATED       = 1,
     81    /** Recording was started. */
     82    RECORDINGSTS_STARTED       = 2,
     83    /** Recording was stopped. */
     84    RECORDINGSTS_STOPPED       = 3,
     85    /** Limit has been reached. */
     86    RECORDINGSTS_LIMIT_REACHED = 4,
     87    /** Recording experienced an error. */
     88    RECORDINGSTS_FAILURE       = 5,
     89    /** The usual 32-bit hack. */
     90    RECORDINGSTS_32BIT_HACK    = 0x7fffffff
     91};
     92
     93/**
    7394 * Class for managing a recording context.
    7495 */
    7596class RecordingContext
    7697{
     98    friend RecordingStream;
     99
     100public:
     101
     102    /** Recording context callback table. */
     103    struct CALLBACKS
     104    {
     105       /**
     106        * Recording state got changed. Optional.
     107        *
     108        * @param   pCtx                 Recording context.
     109        * @param   enmSts               New status.
     110        * @param   uScreen              Screen ID.
     111        *                               Set to UINT32_MAX if the limit of all streams was reached.
     112        * @param   vrc                  Result code of state change.
     113        * @param   pvUser               User-supplied pointer. Might be NULL.
     114        */
     115        DECLCALLBACKMEMBER(void, pfnStateChanged, (RecordingContext *pCtx, RECORDINGSTS enmSts, uint32_t uScreen, int vrc, void *pvUser));
     116
     117        /** User-supplied pointer. Might be NULL. */
     118        void *pvUser;
     119    };
     120
    77121public:
    78122
     
    108152    uint64_t GetCurrentPTS(void) const;
    109153    bool IsFeatureEnabled(RecordingFeature_T enmFeature);
     154    bool IsFeatureEnabled(uint32_t uScreen, RecordingFeature_T enmFeature);
    110155    bool IsReady(void);
    111     bool IsReady(uint32_t uScreen, uint64_t msTimestamp);
    112156    bool IsStarted(void);
    113157    bool IsLimitReached(void);
    114158    bool IsLimitReached(uint32_t uScreen, uint64_t msTimestamp);
    115159    bool NeedsUpdate(uint32_t uScreen, uint64_t msTimestamp);
    116 
    117     DECLCALLBACK(int) OnLimitReached(uint32_t uScreen, int vrc);
     160    void SetCallbacks(RecordingContext::CALLBACKS *pCallbacks, void *pvUser);
    118161
    119162    /** The state mouse cursor state.
     
    138181    int unlock(void);
    139182
     183    int onLimitReached(uint32_t uScreen, int vrc);
     184
    140185    static DECLCALLBACK(int) threadMain(RTTHREAD hThreadSelf, void *pvUser);
    141186
     
    149194
    150195protected:
    151 
    152     /**
    153      * Enumeration for a recording context state.
    154      */
    155     enum RECORDINGSTS
    156     {
    157         /** Context not initialized. */
    158         RECORDINGSTS_UNINITIALIZED = 0,
    159         /** Context was created. */
    160         RECORDINGSTS_CREATED       = 1,
    161         /** Context was started. */
    162         RECORDINGSTS_STARTED       = 2,
    163         /** The usual 32-bit hack. */
    164         RECORDINGSTS_32BIT_HACK    = 0x7fffffff
    165     };
    166196
    167197    /** Pointer to the console object. */
     
    171201    /** The current state. */
    172202    RECORDINGSTS                 m_enmState;
     203    /** Callback table. */
     204    CALLBACKS                    m_Callbacks;
    173205    /** Critical section to serialize access. */
    174206    RTCRITSECT                   m_CritSect;
  • trunk/src/VBox/Main/include/RecordingInternals.h

    r105006 r105095  
    101101    /** Pixel format. */
    102102    RECORDINGPIXELFMT enmPixelFmt;
    103     /** Bytes per scan line (stride). */
     103    /** Bytes per scan line (stride).
     104     *  Note: Does not necessarily match \a uWidth * (\a uBPP / 8). */
    104105    uint32_t          uBytesPerLine;
    105106} RECORDINGSURFACEINFO;
     
    539540PRECORDINGVIDEOFRAME RecordingVideoFrameDup(PRECORDINGVIDEOFRAME pFrame);
    540541void RecordingVideoFrameClear(PRECORDINGVIDEOFRAME pFrame);
    541 int RecordingVideoFrameBlitRawAlpha(PRECORDINGVIDEOFRAME pFrame, uint32_t uDstX, uint32_t uDstY, const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight, uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmFmt);
    542 int RecordingVideoFrameBlitRaw(PRECORDINGVIDEOFRAME pFrame, uint32_t uDstX, uint32_t uDstY, const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight, uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmFmt);
     542int RecordingVideoFrameBlitRawAlpha(PRECORDINGVIDEOFRAME pDstFrame, uint32_t uDstX, uint32_t uDstY, const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight, uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmFmt);
     543int RecordingVideoBlitRaw(uint8_t *pu8Dst, size_t cbDst, uint32_t uDstX, uint32_t uDstY, uint32_t uDstBytesPerLine, uint8_t uDstBPP, RECORDINGPIXELFMT enmDstFmt, const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight, uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmSrcFmt);
     544int RecordingVideoFrameBlitRaw(PRECORDINGVIDEOFRAME pDstFrame, uint32_t uDstX, uint32_t uDstY, const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight, uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmFmt);
    543545int RecordingVideoFrameBlitFrame(PRECORDINGVIDEOFRAME pDstFrame, uint32_t uDstX, uint32_t uDstY, PRECORDINGVIDEOFRAME pSrcFrame, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight);
    544546
  • trunk/src/VBox/Main/include/RecordingStream.h

    r105006 r105095  
    144144
    145145    bool IsLimitReached(uint64_t msTimestamp) const;
    146     bool IsReady(void) const;
     146    bool IsFeatureEnabled(RecordingFeature_T enmFeature) const;
    147147    bool NeedsUpdate(uint64_t msTimestamp) const;
    148148
  • trunk/src/VBox/Main/src-client/ConsoleImpl.cpp

    r105087 r105095  
    76097609    int vrc = i_recordingGetSettings(recordingSettings);
    76107610    if (RT_SUCCESS(vrc))
     7611    {
    76117612        vrc = mRecording.mCtx.Create(this, recordingSettings);
     7613        if (RT_SUCCESS(vrc))
     7614        {
     7615            RecordingContext::CALLBACKS Callbacks;
     7616            RT_ZERO(Callbacks);
     7617            Callbacks.pfnStateChanged = Console::s_recordingOnStateChangedCallback;
     7618
     7619            mRecording.mCtx.SetCallbacks(&Callbacks, this /* pvUser */);
     7620        }
     7621    }
    76127622
    76137623    LogFlowFuncLeaveRC(vrc);
     
    76237633}
    76247634
    7625 /**
    7626  * Starts recording. Does nothing if recording is already active.
     7635/** @copydoc RecordingContext::CALLBACKS::pfnStateChanged */
     7636DECLCALLBACK(void) Console::s_recordingOnStateChangedCallback(RecordingContext *pCtx,
     7637                                                              RECORDINGSTS enmSts, uint32_t uScreen, int vrc, void *pvUser)
     7638{
     7639    RT_NOREF(pCtx, vrc);
     7640
     7641    Console *pThis = (Console *)pvUser;
     7642    AssertPtrReturnVoid(pThis);
     7643
     7644    switch (enmSts)
     7645    {
     7646        case RECORDINGSTS_LIMIT_REACHED:
     7647        {
     7648            if (uScreen == UINT32_MAX) /* Limit for all screens reached? Disable recording. */
     7649                pThis->i_onRecordingChange(FALSE /* Disable */);
     7650            break;
     7651        }
     7652
     7653        default:
     7654            break;
     7655    }
     7656}
     7657
     7658/**
     7659 * Starts recording. Does nothing if recording is already started.
    76277660 *
    76287661 * @returns VBox status code.
     
    76467679
    76477680/**
    7648  * Stops recording. Does nothing if recording is not active.
     7681 * Stops recording. Does nothing if recording is not in started state.
    76497682 *
    76507683 * Note: This does *not* disable recording for a VM, in other words,
  • trunk/src/VBox/Main/src-client/DisplayImpl.cpp

    r105065 r105095  
    130130#endif
    131131
    132 #ifdef VBOX_WITH_RECORDING
    133     vrc = RTCritSectInit(&mVideoRecLock);
    134     AssertRC(vrc);
    135 
    136     for (unsigned i = 0; i < RT_ELEMENTS(maRecordingEnabled); i++)
    137         maRecordingEnabled[i] = false;
    138 #endif
    139 
    140132    return BaseFinalConstruct();
    141133}
     
    144136{
    145137    uninit();
    146 
    147 #ifdef VBOX_WITH_RECORDING
    148     if (RTCritSectIsInitialized(&mVideoRecLock))
    149     {
    150         RTCritSectDelete(&mVideoRecLock);
    151         RT_ZERO(mVideoRecLock);
    152     }
    153 #endif
    154138
    155139    videoAccelDestroy(&mVideoAccelLegacy);
     
    565549    }
    566550
     551#ifdef VBOX_WITH_RECORDING
     552    unconst(Recording.pCtx) = mParent->i_recordingGetContext();
     553#endif
     554
    567555    /* Confirm a successful initialization */
    568556    autoInitSpan.setSucceeded();
     
    796784    const bool fDisabled = pFBInfo->fDisabled;
    797785
     786    alock.release(); /* Release lock before recording code gets involved below. */
     787
    798788#ifdef VBOX_WITH_RECORDING
    799789    /* Recording needs to be called before releasing the display's lock below. */
    800790    i_recordingScreenChanged(uScreenId, pFBInfo);
    801791#endif
    802 
    803     alock.release();
    804792
    805793    if (!pFramebuffer.isNull())
     
    834822    LogRelFlowFunc(("[%d]: default format %d\n", uScreenId, pFBInfo->fDefaultFormat));
    835823
     824    LogFlowFuncLeave();
    836825    return VINF_SUCCESS;
    837826}
     
    911900
    912901#ifdef VBOX_WITH_RECORDING
    913                 RECORDINGVIDEOFRAME Frame =
    914                 {
    915                     { (uint32_t)w, (uint32_t)h,
    916                       (uint8_t )pFBInfo->u16BitsPerPixel, RECORDINGPIXELFMT_BRGA32, pFBInfo->u32LineSize },
    917                     pFBInfo->pu8FramebufferVRAM + (y * pFBInfo->u32LineSize + x * (pFBInfo->u16BitsPerPixel / 8)),
    918                     pFBInfo->w * pFBInfo->u32LineSize,
    919                     { (uint32_t)x, (uint32_t)y }
    920                 };
    921                 i_recordingScreenUpdate(uScreenId, &Frame);
     902                i_recordingScreenUpdate(uScreenId, x, y, w, h);
    922903#endif
    923904            }
     
    955936                            pFBInfo->updateImage.pu8Address = pAddress;
    956937                            pFBInfo->updateImage.cbLine = ulBytesPerLine;
    957 #ifdef VBOX_WITH_RECORDING
    958                             RECORDINGVIDEOFRAME Frame =
    959                             {
    960                                 { (uint32_t)ulWidth, (uint32_t)ulHeight,
    961                                   (uint8_t )ulBitsPerPixel, RECORDINGPIXELFMT_BRGA32, ulBytesPerLine },
    962                                 pAddress, ulHeight * ulBytesPerLine,
    963                                 { 0, 0 }
    964                             };
    965 
    966                             i_recordingScreenUpdate(uScreenId, &Frame);
    967 #endif
    968938                        }
    969939
     
    1006976                        const uint8_t *pu8Src = pbAddress + ulBytesPerLine * y + x * uBytesPerPixel;
    1007977
    1008                         for (int i = y; i < y + h; ++i)
     978                        for (int i = 0; i < h; ++i)
    1009979                        {
    1010980                            memcpy(pu8Dst, pu8Src, w * uBytesPerPixel);
     
    1016986
    1017987#ifdef VBOX_WITH_RECORDING
    1018                         RECORDINGVIDEOFRAME Frame =
    1019                         {
    1020                             { (uint32_t)w, (uint32_t)h,
    1021                               (uint8_t)ulBitsPerPixel, RECORDINGPIXELFMT_BRGA32, ulBytesPerLine },
    1022                             pu8Dst, h * ulBytesPerLine,
    1023                             { (uint32_t)x, (uint32_t)y }
    1024                         };
    1025 
    1026                         i_recordingScreenUpdate(uScreenId, &Frame);
     988                        i_recordingScreenUpdate(uScreenId,
     989                                                image.raw(), ulBytesPerLine * h,
     990                                                x, y, w, h, ulBytesPerLine);
    1027991#endif
    1028992                    }
     
    11701134    bool fMoveCursor = mcVRDPRefs == 0;
    11711135#ifdef VBOX_WITH_RECORDING
    1172     RecordingContext *pCtx = mParent->i_recordingGetContext();
    1173 
    1174     if (   pCtx
    1175         && pCtx->IsStarted()
     1136    RecordingContext *pCtx = Recording.pCtx;
     1137    if (   pCtx->IsStarted()
    11761138        && pCtx->IsFeatureEnabled(RecordingFeature_Video))
    11771139        fRenderCursor = fMoveCursor = false;
     
    21572119#endif
    21582120
    2159     return i_recordingInvalidate(true /* fForce */);
     2121    return i_recordingInvalidate();
    21602122}
    21612123
     
    21792141#endif
    21802142
    2181     return i_recordingInvalidate(true /* fForce */);
     2143    return i_recordingInvalidate();
    21822144}
    21832145
     
    21862148 *
    21872149 * @returns VBox status code.
    2188  * @param   fForce              Whether to force invalidation or not. Default is @c false.
    21892150 *
    2190  * @note    Takes the display's read lock.
     2151 * @note    Takes the display's write lock.
    21912152 */
    2192 int Display::i_recordingInvalidate(bool fForce /* = false */)
    2193 {
    2194     RecordingContext *pCtx = mParent->i_recordingGetContext();
    2195     if (!pCtx)
    2196         return VINF_SUCCESS;
    2197 
     2153int Display::i_recordingInvalidate(void)
     2154{
    21982155    LogFlowFuncEnter();
    21992156
    2200     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     2157    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    22012158
    22022159    /*
     
    22052162    for (unsigned uScreen = 0; uScreen < mcMonitors; uScreen++)
    22062163    {
    2207         const RecordingStream *pRecordingStream = pCtx->GetStream(uScreen);
    2208 
    2209         bool const fStreamEnabled = pRecordingStream->IsReady();
    2210         bool const fChanged       = (maRecordingEnabled[uScreen] != fStreamEnabled) || fForce;
    2211 
    2212         maRecordingEnabled[uScreen] = fStreamEnabled;
    2213 
    2214         if (   fStreamEnabled
    2215             && fChanged)
    2216         {
    2217             DISPLAYFBINFO const *pFBInfo = &maFramebuffers[uScreen];
    2218             /* ignore rc */ i_recordingScreenChanged(uScreen, pFBInfo);
    2219         }
     2164        DISPLAYFBINFO const *pFBInfo = &maFramebuffers[uScreen];
     2165        /* ignore rc */ i_recordingScreenChanged(uScreen, pFBInfo);
    22202166    }
    22212167
     
    22322178int Display::i_recordingScreenChanged(unsigned uScreenId, const DISPLAYFBINFO *pFBInfo)
    22332179{
    2234     AssertReturn(uScreenId < mcMonitors, VERR_INVALID_PARAMETER);
    2235 
    2236     RecordingContext *pCtx = mParent->i_recordingGetContext();
    2237 
    2238     i_updateDeviceCursorCapabilities();
    2239     if (   RT_LIKELY(!maRecordingEnabled[uScreenId])
    2240         || !pCtx || !pCtx->IsStarted())
     2180    RecordingContext *pCtx = Recording.pCtx;
     2181
     2182    Log2Func(("uScreenId=%u\n", uScreenId));
     2183
     2184    if (uScreenId == 0xFFFFFFFF /* SVGA_ID_INVALID -- The old register interface is single screen only */)
     2185        uScreenId = VBOX_VIDEO_PRIMARY_SCREEN;
     2186
     2187    if (!pCtx->IsFeatureEnabled(uScreenId, RecordingFeature_Video))
    22412188    {
    22422189        /* Skip recording this screen. */
     
    22442191    }
    22452192
    2246     LogFlowFuncEnter();
     2193    AssertReturn(uScreenId < mcMonitors, VERR_INVALID_PARAMETER);
     2194
     2195    RT_NOREF(pFBInfo);
     2196
     2197    /* We have to go the official way of querying the source bitmap, as this function creates it if it does not exist yet. */
     2198    ComPtr<IDisplaySourceBitmap> sourceBitmap;
     2199    HRESULT hrc = querySourceBitmap(uScreenId, sourceBitmap);
     2200    if (FAILED(hrc)) /* Blank, skip. */
     2201        return VINF_SUCCESS;
     2202
     2203    BYTE *pbAddress;
     2204    ULONG ulWidth;
     2205    ULONG ulHeight;
     2206    ULONG ulBitsPerPixel;
     2207    ULONG ulBytesPerLine;
     2208    BitmapFormat_T bitmapFormat = BitmapFormat_Opaque;
     2209    hrc = sourceBitmap->QueryBitmapInfo(&pbAddress,
     2210                                        &ulWidth,
     2211                                        &ulHeight,
     2212                                        &ulBitsPerPixel,
     2213                                        &ulBytesPerLine,
     2214                                        &bitmapFormat);
     2215    AssertComRC(hrc);
     2216
     2217    Log2Func(("pbAddress=%p, ulWidth=%RU32, ulHeight=%RU32, ulBitsPerPixel=%RU32\n",
     2218              pbAddress, ulWidth, ulHeight, ulBitsPerPixel));
     2219
     2220    Assert(ulWidth);
     2221    Assert(ulHeight);
     2222    Assert(ulBitsPerPixel);
     2223    Assert(ulBytesPerLine);
     2224
     2225    if (!pbAddress)
     2226    {
     2227        AssertFailed();
     2228        return VINF_SUCCESS;
     2229    }
     2230
     2231    i_updateDeviceCursorCapabilities();
    22472232
    22482233    RECORDINGSURFACEINFO ScreenInfo;
    2249     ScreenInfo.uWidth      = pFBInfo->w;
    2250     ScreenInfo.uHeight     = pFBInfo->h;
    2251     ScreenInfo.uBPP        = (uint8_t)pFBInfo->u16BitsPerPixel;
     2234    ScreenInfo.uWidth      = ulWidth;
     2235    ScreenInfo.uHeight     = ulHeight;
     2236    ScreenInfo.uBPP        = ulBitsPerPixel;
    22522237    ScreenInfo.enmPixelFmt = RECORDINGPIXELFMT_BRGA32; /** @todo Does this apply everywhere? */
    22532238
     
    22572242    if (RT_SUCCESS(vrc))
    22582243    {
    2259         /** @todo BUGBUG For whatever reason pFBInfo contains a wrong pFBInfo->u32LineSize
    2260          *        when shutting down a VM. So (re-)calculate the line size based on the framebuffer's
    2261          *        BPP + width parameters.
    2262          *
    2263          *        So fend off any requests here which look fishy before sending a full screen update. */
    2264         if (   !pFBInfo->u16BitsPerPixel
    2265             ||  pFBInfo->u16BitsPerPixel % 2 != 0
    2266             || !pFBInfo->w
    2267             || !pFBInfo->h
    2268             ||  pFBInfo->u32LineSize != pFBInfo->w * (pFBInfo->u16BitsPerPixel / 8))
    2269         {
    2270             vrc = VERR_INVALID_PARAMETER;
    2271         }
    2272         else
    2273         {
    2274             /* Make sure that we get the latest mouse pointer shape required for recording. */
    2275             MousePointerData pointerData;
    2276             mParent->i_getMouse()->i_getPointerShape(pointerData);
    2277             mParent->i_recordingCursorShapeChange(pointerData.fVisible, pointerData.fAlpha,
    2278                                                   pointerData.hotX, pointerData.hotY,
    2279                                                   pointerData.width, pointerData.height,
    2280                                                   pointerData.pu8Shape, pointerData.cbShape);
    2281             /* Send the full screen update. */
    2282             RECORDINGVIDEOFRAME Frame =
    2283             {
    2284                 { (uint32_t)pFBInfo->w, (uint32_t)pFBInfo->h,
    2285                   (uint8_t)pFBInfo->u16BitsPerPixel, RECORDINGPIXELFMT_BRGA32, pFBInfo->u32LineSize },
    2286                 pFBInfo->pu8FramebufferVRAM, pFBInfo->h * pFBInfo->u32LineSize,
    2287                 { 0, 0 }
    2288             };
    2289 
    2290             vrc = i_recordingScreenUpdate(uScreenId, &Frame);
    2291         }
    2292     }
    2293 
    2294     LogFlowFuncLeaveRC(vrc);
     2244        /* Make sure that we get the latest mouse pointer shape required for recording. */
     2245        MousePointerData pointerData;
     2246        mParent->i_getMouse()->i_getPointerShape(pointerData);
     2247        mParent->i_recordingCursorShapeChange(pointerData.fVisible, pointerData.fAlpha,
     2248                                              pointerData.hotX, pointerData.hotY,
     2249                                              pointerData.width, pointerData.height,
     2250                                              pointerData.pu8Shape, pointerData.cbShape);
     2251        /* Send the full screen update. */
     2252        vrc = i_recordingScreenUpdate(uScreenId, pbAddress, ulHeight * ulBytesPerLine,
     2253                                      0, 0, ulWidth, ulHeight, ulBytesPerLine);
     2254    }
     2255
    22952256    return vrc;
    22962257}
    22972258
    22982259/**
    2299  * Called when a part of a screen got updated.
     2260 * Sends a screen update to the recording facility.
    23002261 *
    23012262 * @returns VBox status code.
    2302  * @param   uScreenId           ID of screen which got updated.
    2303  * @param   pFrame              Video frama to send.
     2263 * @param   uScreenId           ID of screen.
     2264 * @param   pauFramebuffer      Pointer to start of framebuffer.
     2265 * @param   cbFramebuffer       Size (in bytes) of \a pauFramebuffer.
     2266 * @param   x                   Absolute X starting position (in pixel) within current framebuffer.
     2267 * @param   y                   Absolute Y starting position (in pixel) within current framebuffer.
     2268 * @param   w                   Width (in pixel) of the changed area.
     2269 * @param   h                   Height (in pixel) of the changed area.
     2270 * @param   uBytesPerLine       Bytes per line of current framebuffer.
    23042271 */
    2305 int Display::i_recordingScreenUpdate(unsigned uScreenId, PRECORDINGVIDEOFRAME pFrame)
    2306 {
    2307     if (   uScreenId >= mcMonitors /* Might be SVGA_ID_INVALID. */
    2308         || !maRecordingEnabled[uScreenId])
     2272int Display::i_recordingScreenUpdate(unsigned uScreenId, uint8_t *pauFramebuffer, size_t cbFramebuffer,
     2273                                     uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t uBytesPerLine)
     2274{
     2275    RT_NOREF(cbFramebuffer);
     2276
     2277    RecordingContext *pCtx = Recording.pCtx;
     2278
     2279    Log2Func(("uScreenId=%u, pauFramebuffer=%p, cbFramebuffer=%zu, x=%RU32, y=%RU32, w=%RU32, h=%RU32, uBytesPerLine=%RU32\n",
     2280              uScreenId, pauFramebuffer, cbFramebuffer, x, y, w, h, uBytesPerLine));
     2281
     2282    if (uScreenId == 0xFFFFFFFF /* SVGA_ID_INVALID -- The old register interface is single screen only */)
     2283        uScreenId = VBOX_VIDEO_PRIMARY_SCREEN;
     2284
     2285    if (!pCtx->IsFeatureEnabled(uScreenId, RecordingFeature_Video))
    23092286        return VINF_SUCCESS;
    23102287
    2311     RecordingContext *pCtx = mParent->i_recordingGetContext();
    2312     if (!pCtx)
    2313         return VINF_SUCCESS;
    2314 
    2315     /* If the recording context has reached the configured recording
    2316      * limit, disable recording. */
    2317     if (pCtx->IsLimitReached())
    2318     {
    2319         mParent->i_onRecordingChange(FALSE /* Disable */);
    2320         return VINF_SUCCESS;
    2321     }
     2288#ifdef VBOX_STRICT /* Skipped in release build for speed reasons. */
     2289    AssertPtrReturn(pauFramebuffer, VERR_INVALID_POINTER);
     2290    AssertReturn   (cbFramebuffer,  VERR_INVALID_PARAMETER);
     2291    AssertReturn   (uBytesPerLine,  VERR_INVALID_PARAMETER);
     2292    AssertReturn   (w,              VERR_INVALID_PARAMETER);
     2293    AssertReturn   (h,              VERR_INVALID_PARAMETER);
     2294#endif
    23222295
    23232296    uint64_t const tsNowMs = pCtx->GetCurrentPTS();
    23242297
    2325     int vrc = VINF_NO_CHANGE;
    2326 
    2327     if (   pCtx->IsStarted()
    2328         && pCtx->IsFeatureEnabled(RecordingFeature_Video))
    2329     {
    2330         STAM_PROFILE_START(&Stats.Monitor[uScreenId].Recording.profileRecording, a);
    2331 
    2332         vrc = pCtx->SendVideoFrame(uScreenId, pFrame, tsNowMs);
    2333 
    2334         STAM_PROFILE_STOP(&Stats.Monitor[uScreenId].Recording.profileRecording, a);
    2335     }
     2298    STAM_PROFILE_START(&Stats.Monitor[uScreenId].Recording.profileRecording, a);
     2299
     2300    uint8_t const uBytesPerPixel = 4;
     2301    size_t  const offFrame = (y * uBytesPerLine) + (x * uBytesPerPixel);
     2302    size_t  const cbFrame  = w * h * uBytesPerPixel;
     2303
     2304    RECORDINGVIDEOFRAME Frame =
     2305    {
     2306        { w, h, 32 /* BPP */, RECORDINGPIXELFMT_BRGA32, uBytesPerLine },
     2307        pauFramebuffer + offFrame, cbFrame,
     2308        { x, y }
     2309    };
     2310
     2311#if 0
     2312    RecordingUtilsDbgDumpImageData(pauFramebuffer + offFrame, cbFramebuffer,
     2313                                   "/tmp/recording", "display-screen-update", w, h, uBytesPerLine, 32 /* BPP */);
     2314#endif
     2315
     2316    int vrc = pCtx->SendVideoFrame(uScreenId, &Frame, tsNowMs);
     2317
     2318    STAM_PROFILE_STOP(&Stats.Monitor[uScreenId].Recording.profileRecording, a);
    23362319
    23372320    return vrc;
     2321}
     2322
     2323/**
     2324 * Sends a screen upate to the recording facility using the current framebuffer.
     2325 *
     2326 * @returns VBox status code.
     2327 * @param   uScreenId           ID of screen.
     2328 * @param   x                   Absolute X starting position (in pixel) within current framebuffer.
     2329 * @param   y                   Absolute Y starting position (in pixel) within current framebuffer.
     2330 * @param   w                   Width (in pixel) of the changed area.
     2331 * @param   h                   Height (in pixel) of the changed area.
     2332 */
     2333int Display::i_recordingScreenUpdate(unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
     2334{
     2335    BYTE *pbAddress;
     2336    ULONG ulWidth;
     2337    ULONG ulHeight;
     2338    ULONG ulBitsPerPixel;
     2339    ULONG ulBytesPerLine;
     2340
     2341    if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN) /* Take a shortcut for the primary screen. */
     2342    {
     2343        pbAddress      = mpDrv->IConnector.pbData;
     2344        ulWidth        = mpDrv->IConnector.cx;
     2345        ulHeight       = mpDrv->IConnector.cy;
     2346        ulBitsPerPixel = mpDrv->IConnector.cBits;
     2347        ulBytesPerLine = mpDrv->IConnector.cbScanline;
     2348    }
     2349    else
     2350    {
     2351        BitmapFormat_T bitmapFormat = BitmapFormat_Opaque;
     2352        maFramebuffers[uScreenId].pSourceBitmap->QueryBitmapInfo(&pbAddress,
     2353                                                                 &ulWidth,
     2354                                                                 &ulHeight,
     2355                                                                 &ulBitsPerPixel,
     2356                                                                 &ulBytesPerLine,
     2357                                                                 &bitmapFormat);
     2358    }
     2359
     2360    Log2Func(("uScreenId=%u, pbAddress=%p, ulWidth=%RU32, ulHeight=%RU32, ulBitsPerPixel=%RU32\n",
     2361              uScreenId, pbAddress, ulWidth, ulHeight, ulBitsPerPixel));
     2362
     2363    AssertPtr(pbAddress);
     2364    Assert(ulWidth);
     2365    Assert(ulHeight);
     2366    Assert(ulBitsPerPixel);
     2367    Assert(ulBytesPerLine);
     2368
     2369    return i_recordingScreenUpdate(uScreenId,
     2370                                   pbAddress, ulHeight * ulBytesPerLine,
     2371                                   x, y, w, h, ulBytesPerLine);
    23382372}
    23392373
     
    23532387    RT_NOREF(fFlags);
    23542388
    2355     if (   uScreenId >= mcMonitors /* Might be SVGA_ID_INVALID. */
    2356         || !maRecordingEnabled[uScreenId])
     2389    RecordingContext *pCtx = Recording.pCtx;
     2390
     2391    Log2Func(("uScreenId=%u, fFlags=%#x, x=%RI32, y=%RI32\n", uScreenId, fFlags, x, y));
     2392
     2393    if (uScreenId == 0xFFFFFFFF /* SVGA_ID_INVALID -- The old register interface is single screen only */)
     2394        uScreenId = VBOX_VIDEO_PRIMARY_SCREEN;
     2395
     2396    if (!pCtx->IsFeatureEnabled(uScreenId, RecordingFeature_Video))
    23572397        return VINF_SUCCESS;
    23582398
    2359     RecordingContext *pCtx = mParent->i_recordingGetContext();
    2360     if (!pCtx)
    2361         return VINF_SUCCESS;
    2362 
    2363     /* If the recording context has reached the configured recording
    2364      * limit, disable recording. */
    2365     if (pCtx->IsLimitReached())
    2366     {
    2367         mParent->i_onRecordingChange(FALSE /* Disable */);
    2368         return VINF_SUCCESS;
    2369     }
    2370 
    2371     if (   pCtx->IsStarted()
    2372         && pCtx->IsFeatureEnabled(RecordingFeature_Video))
    2373     {
    2374         return pCtx->SendCursorPositionChange(uScreenId, x, y, pCtx->GetCurrentPTS());
    2375     }
    2376 
    2377     return VINF_SUCCESS;
     2399    return pCtx->SendCursorPositionChange(uScreenId, x, y, pCtx->GetCurrentPTS());
    23782400}
    23792401#endif /* VBOX_WITH_RECORDING */
  • trunk/src/VBox/Main/src-client/Recording.cpp

    r105010 r105095  
    137137        vrc = RecordingVideoFrameBlitRaw(&m_Shape, 0, 0, &pu8Shape[offShape], cbShape - offShape, 0, 0, uWidth, uHeight, uWidth * 4 /* BPP */, uBPP,
    138138                                         m_Shape.Info.enmPixelFmt);
    139 #ifdef DEBUG_andy_disabled
     139#if 0
    140140    RecordingUtilsDbgDumpVideoFrameEx(&m_Shape, "/tmp/recording", "cursor-update");
    141141#endif
     
    530530
    531531    m_pConsole = ptrConsole;
     532    RT_ZERO(m_Callbacks);
    532533
    533534    settings::RecordingScreenSettingsMap::const_iterator itScreen = m_Settings.mapScreens.begin();
     
    537538        try
    538539        {
    539             pStream = new RecordingStream(this, itScreen->first /* Screen ID */, itScreen->second);
    540             m_vecStreams.push_back(pStream);
    541540            if (itScreen->second.fEnabled)
     541            {
     542                pStream = new RecordingStream(this, itScreen->first /* Screen ID */, itScreen->second);
     543                m_vecStreams.push_back(pStream);
    542544                m_cStreamsEnabled++;
    543             LogFlowFunc(("pStream=%p\n", pStream));
     545                LogFlowFunc(("pStream=%p\n", pStream));
     546            }
    544547        }
    545548        catch (std::bad_alloc &)
     
    565568        vrc = RTSemEventCreate(&m_WaitEvent);
    566569        AssertRCReturn(vrc, vrc);
     570
     571        RT_ZERO(m_Callbacks);
    567572    }
    568573
     
    571576
    572577    return vrc;
     578}
     579
     580/**
     581 * Sets the callback table for a recording context.
     582 *
     583 * @param   pCallbacks          Callback table to set.
     584 * @param   pvUser              User-supplied pointer.
     585 */
     586void RecordingContext::SetCallbacks(RecordingContext::CALLBACKS *pCallbacks, void *pvUser)
     587{
     588    lock();
     589
     590    memcpy(&m_Callbacks, pCallbacks, sizeof(RecordingContext::CALLBACKS));
     591    m_Callbacks.pvUser = pvUser;
     592
     593    unlock();
    573594}
    574595
     
    857878
    858879/**
    859  * Returns if this recording context is ready to accept new recording data for a given screen.
    860  *
    861  * @returns @c true if the specified screen is ready, @c false if not.
     880 * Returns if a feature for a given stream is enabled or not.
     881 *
     882 * @returns @c true if the specified feature is enabled (running), @c false if not.
    862883 * @param   uScreen             Screen ID.
    863  * @param   msTimestamp         Timestamp (PTS, in ms). Currently not being used.
    864  */
    865 bool RecordingContext::IsReady(uint32_t uScreen, uint64_t msTimestamp)
    866 {
    867     RT_NOREF(msTimestamp);
    868 
     884 * @param   enmFeature          Feature of stream to check for.
     885 *
     886 * @note    Implies that the stream is enabled (i.e. active).
     887 */
     888bool RecordingContext::IsFeatureEnabled(uint32_t uScreen, RecordingFeature_T enmFeature)
     889{
    869890    lock();
    870891
    871892    bool fIsReady = false;
    872893
    873     if (m_enmState != RECORDINGSTS_STARTED)
     894    if (m_enmState == RECORDINGSTS_STARTED)
    874895    {
    875896        const RecordingStream *pStream = getStreamInternal(uScreen);
    876897        if (pStream)
    877             fIsReady = pStream->IsReady();
     898            fIsReady = pStream->IsFeatureEnabled(enmFeature);
    878899
    879900        /* Note: Do not check for other constraints like the video FPS rate here,
     
    890911 * Returns whether a given recording context has been started or not.
    891912 *
    892  * @returns true if active, false if not.
     913 * @returns @c true if started, @c false if not.
    893914 */
    894915bool RecordingContext::IsStarted(void)
     
    906927 * Checks if a specified limit for recording has been reached.
    907928 *
    908  * @returns true if any limit has been reached.
     929 * @returns @c true if any limit has been reached, @c false if not.
    909930 */
    910931bool RecordingContext::IsLimitReached(void)
     
    924945 * Checks if a specified limit for recording has been reached.
    925946 *
    926  * @returns true if any limit has been reached.
     947 * @returns @c true if any limit has been reached, @c false if not.
    927948 * @param   uScreen             Screen ID.
    928949 * @param   msTimestamp         Timestamp (PTS, in ms) to check for.
     
    9821003}
    9831004
    984 DECLCALLBACK(int) RecordingContext::OnLimitReached(uint32_t uScreen, int vrc)
    985 {
    986     RT_NOREF(uScreen, vrc);
     1005/**
     1006 * Gets called by a stream if its limit has been reached.
     1007 *
     1008 * @returns VBox status code.
     1009 * @param   uScreen             The stream's ID (Screen ID).
     1010 * @param   vrc                 Result code of the limit operation.
     1011 */
     1012DECLCALLBACK(int) RecordingContext::onLimitReached(uint32_t uScreen, int vrc)
     1013{
    9871014    LogFlowThisFunc(("Stream %RU32 has reached its limit (%Rrc)\n", uScreen, vrc));
    9881015
     
    9901017
    9911018    Assert(m_cStreamsEnabled);
    992     m_cStreamsEnabled--;
     1019    if (m_cStreamsEnabled)
     1020        m_cStreamsEnabled--;
     1021
     1022    bool const fAllDisabled = m_cStreamsEnabled == 0;
    9931023
    9941024    LogFlowThisFunc(("cStreamsEnabled=%RU16\n", m_cStreamsEnabled));
    9951025
    996     unlock();
     1026    unlock(); /* Leave the lock before invoking callbacks. */
     1027
     1028    if (m_Callbacks.pfnStateChanged)
     1029        m_Callbacks.pfnStateChanged(this, RECORDINGSTS_LIMIT_REACHED,
     1030                                    fAllDisabled ? UINT32_MAX : uScreen, vrc, m_Callbacks.pvUser);
    9971031
    9981032    return VINF_SUCCESS;
     
    10321066    AssertPtrReturn(pFrame, VERR_INVALID_POINTER);
    10331067
    1034     LogFlowFunc(("uScreen=%RU32, offX=%RU32, offY=%RU32, w=%RU32, h=%RU32, msTimestamp=%RU64\n",
    1035                  uScreen, pFrame->Pos.x, pFrame->Pos.y, pFrame->Info.uWidth, pFrame->Info.uHeight, msTimestamp));
     1068    LogFlowFunc(("uScreen=%RU32, offX=%RU32, offY=%RU32, w=%RU32, h=%RU32 (%zu bytes), msTimestamp=%RU64\n",
     1069                 uScreen, pFrame->Pos.x, pFrame->Pos.y, pFrame->Info.uWidth, pFrame->Info.uHeight,
     1070                 pFrame->Info.uHeight * pFrame->Info.uWidth * (pFrame->Info.uBPP / 8), msTimestamp));
    10361071
    10371072    if (!pFrame->pau8Buf) /* Empty / invalid frame, skip. */
     
    10391074
    10401075    /* Sanity. */
     1076    AssertReturn(pFrame->Info.uBPP, VERR_INVALID_PARAMETER);
     1077    AssertReturn(pFrame->cbBuf, VERR_INVALID_PARAMETER);
    10411078    AssertReturn(pFrame->Info.uWidth  * pFrame->Info.uHeight * (pFrame->Info.uBPP / 8) <= pFrame->cbBuf, VERR_INVALID_PARAMETER);
    1042     AssertReturn(pFrame->Info.uHeight * pFrame->Info.uBytesPerLine <= pFrame->cbBuf, VERR_INVALID_PARAMETER);
    10431079
    10441080    lock();
     
    10481084    {
    10491085        unlock();
    1050 
    1051         AssertFailed();
    1052         return VERR_NOT_FOUND;
    1053     }
     1086        return VINF_SUCCESS;
     1087    }
     1088
     1089    unlock();
    10541090
    10551091    int vrc = pStream->SendVideoFrame(pFrame, msTimestamp);
    1056 
    1057     unlock();
    1058 
    1059     if (   RT_SUCCESS(vrc)
    1060         && vrc != VINF_RECORDING_THROTTLED) /* Only signal the thread if operation was successful. */
    1061     {
     1092    if (vrc == VINF_SUCCESS) /* Might be VINF_RECORDING_THROTTLED or VINF_RECORDING_LIMIT_REACHED. */
    10621093        threadNotify();
    1063     }
    10641094
    10651095    return vrc;
     
    10831113        return VINF_SUCCESS;
    10841114
    1085     if (uScreen == 0xFFFFFFFF /* SVGA_ID_INVALID */)
    1086         uScreen = 0;
    1087 
    10881115    int vrc = m_Cursor.Move(x, y);
    10891116    if (RT_SUCCESS(vrc))
     
    10951122        {
    10961123            unlock();
    1097 
    1098             AssertFailed();
    1099             return VERR_NOT_FOUND;
     1124            return VINF_SUCCESS;
    11001125        }
    11011126
     1127        unlock();
     1128
    11021129        vrc = pStream->SendCursorPos(0 /* idCursor */, &m_Cursor.m_Shape.Pos, msTimestamp);
    1103 
    1104         unlock();
    1105 
    1106         if (   RT_SUCCESS(vrc)
    1107             && vrc != VINF_RECORDING_THROTTLED) /* Only signal the thread if operation was successful. */
    1108         {
     1130        if (vrc == VINF_SUCCESS) /* Might be VINF_RECORDING_THROTTLED or VINF_RECORDING_LIMIT_REACHED. */
    11091131            threadNotify();
    1110         }
    11111132    }
    11121133
     
    11601181    unlock();
    11611182
    1162     if (RT_SUCCESS(vrc))
     1183    if (vrc == VINF_SUCCESS) /* Might be VINF_RECORDING_THROTTLED or VINF_RECORDING_LIMIT_REACHED. */
    11631184        threadNotify();
    11641185
     
    11821203    {
    11831204        unlock();
    1184 
    1185         AssertFailed();
    1186         return VERR_NOT_FOUND;
    1187     }
     1205        return VINF_SUCCESS;
     1206    }
     1207
     1208    unlock();
    11881209
    11891210    int const vrc = pStream->SendScreenChange(pInfo, msTimestamp);
    11901211
    1191     unlock();
    1192 
    11931212    return vrc;
    11941213}
  • trunk/src/VBox/Main/src-client/RecordingCodec.cpp

    r105067 r105095  
    374374     * - if available (through mouse integration via Guest Additions): the guest's mouse cursor via a (software) overlay
    375375     *
    376      * So composing is done the folowing way:
     376     * So composing is done the following way:
    377377     *
    378378     *  - always store the plain framebuffer updates in our back buffer first
     
    388388            PRECORDINGVIDEOFRAME pSrc = &pFrame->u.Video;
    389389
    390             vrc = RecordingVideoFrameBlitFrame(pFront, pSrc->Pos.x, pSrc->Pos.y,
    391                                                pSrc, 0 /* uSrcX */, 0 /* uSrcY */, pSrc->Info.uWidth, pSrc->Info.uHeight);
     390            vrc = RecordingVideoBlitRaw(pFront->pau8Buf, pFront->cbBuf, pSrc->Pos.x, pSrc->Pos.y,
     391                                        pFront->Info.uBytesPerLine, pFront->Info.uBPP, pFront->Info.enmPixelFmt,
     392                                        pSrc->pau8Buf, pSrc->cbBuf, 0 /* uSrcX */, 0 /* uSrcY */, pSrc->Info.uWidth, pSrc->Info.uHeight,
     393                                        pSrc->Info.uBytesPerLine, pSrc->Info.uBPP, pSrc->Info.enmPixelFmt);
    392394#if 0
    393395            RecordingUtilsDbgDumpVideoFrameEx(pFront, "/tmp/recording", "encode-front");
    394             RecordingUtilsDbgDumpVideoFrameEx(pSrc, "/tmp/recording", "encode-src");
     396            RecordingUtilsDbgDumpImageData(pSrc->pau8Buf, pSrc->cbBuf,
     397                                           "/tmp/recording", "encode-src",
     398                                           pSrc->Info.uWidth, pSrc->Info.uHeight, pSrc->Info.uBytesPerLine, pSrc->Info.uBPP);
    395399#endif
    396400            vrc = RecordingVideoFrameBlitFrame(pBack, pSrc->Pos.x, pSrc->Pos.y,
     
    499503              pCodec->Parms.u.Video.Scaling.u.Crop.m_iOriginX, pCodec->Parms.u.Video.Scaling.u.Crop.m_iOriginY));
    500504
    501     int32_t sx_b = sx; /* X origin within the source frame. */
    502     int32_t sy_b = sy; /* Y origin within the source frame. */
    503     int32_t sw_b = sw; /* Width of the source frame (starting at X origin). */
    504     int32_t sh_b = sh; /* Height of the source frame (starting at Y origin). */
    505     int32_t dx_b = dx; /* X destination of the source frame within the destination frame. */
    506     int32_t dy_b = dy; /* Y destination of the source frame within the destination frame. */
    507 
    508     RT_NOREF(sx_b);
    509     RT_NOREF(sy_b);
    510     RT_NOREF(sw_b);
    511     RT_NOREF(sh_b);
    512     RT_NOREF(dx_b);
    513     RT_NOREF(dy_b);
    514 
    515505    vrc = RecordingUtilsCoordsCropCenter(&pCodec->Parms, &sx, &sy, &sw, &sh, &dx, &dy);
    516506    if (vrc == VINF_SUCCESS) /* vrc might be VWRN_RECORDING_ENCODING_SKIPPED to skip encoding. */
     
    546536static DECLCALLBACK(int) recordingCodecVPXScreenChange(PRECORDINGCODEC pCodec, PRECORDINGSURFACEINFO pInfo)
    547537{
    548     LogRel2(("Recording: Codec got screen change notification (%RU16x%RU16, %RU8 BPP)\n",
    549              pInfo->uWidth, pInfo->uHeight, pInfo->uBPP));
    550 
    551     /* Fend-off bogus reports. */
    552     if (   !pInfo->uWidth
    553         || !pInfo->uHeight)
    554         return VERR_INVALID_PARAMETER;
    555 
    556      /** @todo BUGBUG Not sure why we sometimes get 0 BPP for a display change from Main.
    557       *               For now we ASSUME 32 BPP. */
    558     if (!pInfo->uBPP)
    559         pInfo->uBPP = 32;
    560 
    561538    /* The VPX encoder only understands even frame sizes. */
    562539    if (   (pInfo->uWidth  % 2) != 0
     
    12061183int recordingCodecScreenChange(PRECORDINGCODEC pCodec, PRECORDINGSURFACEINFO pInfo)
    12071184{
     1185    LogRel2(("Recording: Codec got screen change notification (%RU16x%RU16, %RU8 BPP)\n",
     1186             pInfo->uWidth, pInfo->uHeight, pInfo->uBPP));
     1187
    12081188    if (!pCodec->Ops.pfnScreenChange)
    12091189        return VINF_SUCCESS;
     1190
     1191    /* Fend-off bogus reports. */
     1192    if (   !pInfo->uWidth
     1193        || !pInfo->uHeight)
     1194        return VERR_INVALID_PARAMETER;
     1195    AssertReturn(pInfo->uBPP % 8 == 0, VERR_INVALID_PARAMETER);
    12101196
    12111197    return pCodec->Ops.pfnScreenChange(pCodec, pInfo);
  • trunk/src/VBox/Main/src-client/RecordingInternals.cpp

    r105011 r105095  
    248248 * @param   enmSrcFmt           Pixel format of source data. Must match \a pFrame.
    249249 */
    250 DECLINLINE(int) recordingVideoFrameBlitRaw(uint8_t *pu8Dst, size_t cbDst, uint32_t uDstX, uint32_t uDstY,
    251                                            uint32_t uDstBytesPerLine, uint8_t uDstBPP, RECORDINGPIXELFMT enmDstFmt,
    252                                            const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight,
    253                                            uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmSrcFmt)
     250DECLINLINE(int) recordingVideoBlitRaw(uint8_t *pu8Dst, size_t cbDst, uint32_t uDstX, uint32_t uDstY,
     251                                      uint32_t uDstBytesPerLine, uint8_t uDstBPP, RECORDINGPIXELFMT enmDstFmt,
     252                                      const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight,
     253                                      uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmSrcFmt)
    254254{
    255255    RT_NOREF(enmDstFmt, enmSrcFmt);
     
    275275
    276276    return VINF_SUCCESS;
     277}
     278
     279int RecordingVideoBlitRaw(uint8_t *pu8Dst, size_t cbDst, uint32_t uDstX, uint32_t uDstY,
     280                          uint32_t uDstBytesPerLine, uint8_t uDstBPP, RECORDINGPIXELFMT enmDstFmt,
     281                          const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight,
     282                          uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmSrcFmt)
     283{
     284    return recordingVideoBlitRaw(pu8Dst, cbDst, uDstX, uDstY, uDstBytesPerLine,uDstBPP, enmDstFmt,
     285                                 pu8Src, cbSrc, uSrcX, uSrcY, uSrcWidth, uSrcHeight,uSrcBytesPerLine, uSrcBPP, enmSrcFmt);
    277286}
    278287
     
    366375                               uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmFmt)
    367376{
    368     return recordingVideoFrameBlitRaw(/* Destination */
    369                                       pDstFrame->pau8Buf, pDstFrame->cbBuf, uDstX, uDstY,
    370                                       pDstFrame->Info.uBytesPerLine, pDstFrame->Info.uBPP, pDstFrame->Info.enmPixelFmt,
    371                                       /* Source */
    372                                       pu8Src, cbSrc, uSrcX, uSrcY, uSrcWidth, uSrcHeight, uSrcBytesPerLine, uSrcBPP, enmFmt);
     377    return recordingVideoBlitRaw(/* Destination */
     378                                pDstFrame->pau8Buf, pDstFrame->cbBuf, uDstX, uDstY,
     379                                pDstFrame->Info.uBytesPerLine, pDstFrame->Info.uBPP, pDstFrame->Info.enmPixelFmt,
     380                                /* Source */
     381                                pu8Src, cbSrc, uSrcX, uSrcY, uSrcWidth, uSrcHeight, uSrcBytesPerLine, uSrcBPP, enmFmt);
    373382}
    374383
     
    377386 *
    378387 * @returns VBox status code.
    379  * @param   pFrame              Destination frame.
     388 * @param   pDstFrame           Destination frame.
    380389 * @param   uDstX               X destination (in pixel) within destination frame.
    381390 * @param   uDstY               Y destination (in pixel) within destination frame.
     
    390399 * @param   enmFmt              Pixel format of source data. Must match \a pFrame.
    391400 */
    392 int RecordingVideoFrameBlitRawAlpha(PRECORDINGVIDEOFRAME pFrame, uint32_t uDstX, uint32_t uDstY,
     401int RecordingVideoFrameBlitRawAlpha(PRECORDINGVIDEOFRAME pDstFrame, uint32_t uDstX, uint32_t uDstY,
    393402                                    const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight,
    394403                                    uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmFmt)
    395404{
    396     return recordingVideoFrameBlitRawAlpha(pFrame, uDstX, uDstY,
     405    return recordingVideoFrameBlitRawAlpha(pDstFrame, uDstX, uDstY,
    397406                                           pu8Src, cbSrc, uSrcX, uSrcY, uSrcWidth, uSrcHeight, uSrcBytesPerLine, uSrcBPP, enmFmt);
    398407}
     
    416425                                 PRECORDINGVIDEOFRAME pSrcFrame, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight)
    417426{
    418     return recordingVideoFrameBlitRaw(/* Dest */
    419                                       pDstFrame->pau8Buf, pDstFrame->cbBuf, uDstX, uDstY,
    420                                       pDstFrame->Info.uBytesPerLine, pDstFrame->Info.uBPP, pDstFrame->Info.enmPixelFmt,
    421                                       /* Source */
    422                                       pSrcFrame->pau8Buf, pSrcFrame->cbBuf, uSrcX, uSrcY, uSrcWidth, uSrcHeight,
    423                                       pSrcFrame->Info.uBytesPerLine, pSrcFrame->Info.uBPP, pSrcFrame->Info.enmPixelFmt);
     427    return recordingVideoBlitRaw(/* Dest */
     428                                 pDstFrame->pau8Buf, pDstFrame->cbBuf, uDstX, uDstY,
     429                                 pDstFrame->Info.uBytesPerLine, pDstFrame->Info.uBPP, pDstFrame->Info.enmPixelFmt,
     430                                 /* Source */
     431                                 pSrcFrame->pau8Buf, pSrcFrame->cbBuf, uSrcX, uSrcY, uSrcWidth, uSrcHeight,
     432                                 pSrcFrame->Info.uBytesPerLine, pSrcFrame->Info.uBPP, pSrcFrame->Info.enmPixelFmt);
    424433}
    425434
  • trunk/src/VBox/Main/src-client/RecordingStream.cpp

    r105006 r105095  
    148148
    149149    if (   m_ScreenSettings.ulMaxTimeS
    150         && msTimestamp >= m_tsStartMs + (m_ScreenSettings.ulMaxTimeS * RT_MS_1SEC))
     150        && msTimestamp >= m_ScreenSettings.ulMaxTimeS * RT_MS_1SEC)
    151151    {
    152152        LogRel(("Recording: Time limit for stream #%RU16 has been reached (%RU32s)\n",
     
    185185 *
    186186 * @returns VBox status code.
     187 * @retval  VINF_RECORDING_LIMIT_REACHED if the stream's recording limit has been reached.
    187188 * @param   msTimestamp         Timestamp (PTS, in ms).
     189 *
     190 * @note    Caller must *not* have the stream's lock (callbacks involved).
    188191 */
    189192int RecordingStream::iterateInternal(uint64_t msTimestamp)
    190193{
     194    AssertReturn(!RTCritSectIsOwner(&m_CritSect), VERR_WRONG_ORDER);
     195
    191196    if (!m_fEnabled)
    192197        return VINF_SUCCESS;
     
    209214            m_fEnabled = false;
    210215
    211             int vrc2 = m_pCtx->OnLimitReached(m_uScreenID, VINF_SUCCESS /* vrc */);
     216            int vrc2 = m_pCtx->onLimitReached(m_uScreenID, VINF_SUCCESS /* vrc */);
    212217            AssertRC(vrc2);
    213218            break;
     
    230235bool RecordingStream::IsLimitReached(uint64_t msTimestamp) const
    231236{
    232     if (!IsReady())
     237    if (!m_fEnabled)
    233238        return true;
    234239
     
    237242
    238243/**
    239  * Returns whether a recording stream is ready (e.g. enabled and active) or not.
     244 * Returns whether a feature for a recording stream is enabled or not.
    240245 *
    241246 * @returns @c true if ready, @c false if not.
    242  */
    243 bool RecordingStream::IsReady(void) const
    244 {
    245     return m_fEnabled;
     247 * @param   enmFeature          Feature of stream to check enabled status for.
     248 */
     249bool RecordingStream::IsFeatureEnabled(RecordingFeature_T enmFeature) const
     250{
     251    return m_fEnabled && m_ScreenSettings.isFeatureEnabled(enmFeature);
    246252}
    247253
     
    392398 *
    393399 * @returns VBox status code.
     400 * @retval  VINF_RECORDING_LIMIT_REACHED if the stream's recording limit has been reached.
    394401 * @param   rcWait              Result of the encoding thread's wait operation.
    395402 *                              Can be used for figuring out if the encoder has to perform some
     
    401408int RecordingStream::ThreadMain(int rcWait, RecordingBlockMap &commonBlocks)
    402409{
    403     Log3Func(("rcWait=%Rrc\n", rcWait));
     410    Log3Func(("uScreenID=%RU16, rcWait=%Rrc\n", m_uScreenID, rcWait));
     411
     412    uint64_t const msTimestamp = m_pCtx->GetCurrentPTS();
    404413
    405414    /* No new data arrived within time? Feed the encoder with the last frame we built.
     
    410419        && m_ScreenSettings.isFeatureEnabled(RecordingFeature_Video))
    411420    {
    412         return recordingCodecEncodeCurrent(&m_CodecVideo, m_pCtx->GetCurrentPTS());
     421        return recordingCodecEncodeCurrent(&m_CodecVideo, msTimestamp);
    413422    }
    414423
     
    528537    AssertPtrReturn(pPos, VERR_INVALID_POINTER);
    529538
    530     lock();
    531 
    532539    int vrc = iterateInternal(msTimestamp);
    533540    if (vrc != VINF_SUCCESS) /* Can return VINF_RECORDING_LIMIT_REACHED. */
    534     {
    535         unlock();
    536541        return vrc;
    537     }
    538542
    539543    PRECORDINGFRAME pFrame = (PRECORDINGFRAME)RTMemAlloc(sizeof(RECORDINGFRAME));
     
    544548    pFrame->u.Cursor.Pos = *pPos;
    545549
     550    lock();
     551
    546552    vrc = addFrame(pFrame, msTimestamp);
    547553
     
    568574    AssertPtrReturn(m_pCtx, VERR_WRONG_ORDER);
    569575
    570     lock();
    571 
    572576    int vrc = iterateInternal(msTimestamp);
    573577    if (vrc != VINF_SUCCESS) /* Can return VINF_RECORDING_LIMIT_REACHED. */
    574     {
    575         unlock();
    576578        return vrc;
    577     }
    578579
    579580    PRECORDINGFRAME pFrame = (PRECORDINGFRAME)RTMemAlloc(sizeof(RECORDINGFRAME));
     
    589590    pFrame->msTimestamp = msTimestamp;
    590591
     592    lock();
     593
    591594    vrc = addFrame(pFrame, msTimestamp);
     595
     596    unlock();
    592597
    593598    if (RT_FAILURE(vrc))
     
    596601        RecordingFrameFree(pFrame);
    597602    }
    598 
    599     unlock();
    600603
    601604    LogFlowFuncLeaveRC(vrc);
     
    620623    AssertPtrReturn(m_pCtx, VERR_WRONG_ORDER);
    621624
    622     lock();
    623 
    624625    int vrc = iterateInternal(msTimestamp);
    625626    if (vrc != VINF_SUCCESS) /* Can return VINF_RECORDING_LIMIT_REACHED. */
    626     {
    627         unlock();
    628627        return vrc;
    629     }
    630628
    631629    PRECORDINGFRAME pFrame = (PRECORDINGFRAME)RTMemAlloc(sizeof(RECORDINGFRAME));
     
    633631
    634632    pFrame->u.Video = *pVideoFrame;
     633
    635634    /* Make a deep copy of the pixel data. */
    636     pFrame->u.Video.pau8Buf = (uint8_t *)RTMemDup(pVideoFrame->pau8Buf, pVideoFrame->cbBuf);
     635    pFrame->u.Video.pau8Buf = (uint8_t *)RTMemAlloc(pVideoFrame->cbBuf);
    637636    AssertPtrReturnStmt(pFrame->u.Video.pau8Buf, RTMemFree(pFrame), VERR_NO_MEMORY);
    638     pFrame->u.Video.cbBuf   = pVideoFrame->cbBuf;
     637    size_t       offDst            = 0;
     638    size_t       offSrc            = 0;
     639    size_t const cbDstBytesPerLine = pVideoFrame->Info.uWidth * (pVideoFrame->Info.uBPP / 8);
     640    for (uint32_t h = 0; h < pFrame->u.Video.Info.uHeight; h++)
     641    {
     642        memcpy(pFrame->u.Video.pau8Buf + offDst, pVideoFrame->pau8Buf + offSrc, cbDstBytesPerLine);
     643        offDst += cbDstBytesPerLine;
     644        offSrc += pVideoFrame->Info.uBytesPerLine;
     645    }
     646    pFrame->u.Video.Info.uBytesPerLine = cbDstBytesPerLine;
    639647
    640648    pFrame->enmType     = RECORDINGFRAME_TYPE_VIDEO;
    641649    pFrame->msTimestamp = msTimestamp;
    642650
     651    lock();
     652
    643653    vrc = addFrame(pFrame, msTimestamp);
     654
     655    unlock();
    644656
    645657    if (RT_FAILURE(vrc))
     
    648660        RecordingFrameFree(pFrame);
    649661    }
    650 
    651     unlock();
    652662
    653663    LogFlowFuncLeaveRC(vrc);
  • trunk/src/VBox/Main/src-client/RecordingUtils.cpp

    r105010 r105095  
    4242#endif
    4343
     44#define LOG_GROUP LOG_GROUP_RECORDING
    4445#include <VBox/log.h>
    4546
     
    370371 * @returns VBox status code.
    371372 * @param   pu8RGBBuf           Pointer to actual RGB image data.
     373 *                              Must point right to the beginning of the pixel data (offset, if any).
    372374 * @param   cbRGBBuf            Size (in bytes) of \a pu8RGBBuf.
    373375 * @param   pszPath             Absolute path to dump file to. Must exist.
     
    383385                                   uint32_t uWidth, uint32_t uHeight, uint32_t uBytesPerLine, uint8_t uBPP)
    384386{
    385     RT_NOREF(cbRGBBuf);
    386 
    387387    const uint8_t  uBytesPerPixel = uBPP / 8 /* Bits */;
    388388    const size_t   cbData         = uWidth * uHeight * uBytesPerPixel;
     
    390390    if (!cbData) /* No data to write? Bail out early. */
    391391        return VINF_SUCCESS;
     392
     393    AssertReturn(cbData <= cbRGBBuf, VERR_INVALID_PARAMETER);
     394
     395    Log3Func(("pu8RGBBuf=%p, cbRGBBuf=%zu, uWidth=%RU32, uHeight=%RU32, uBytesPerLine=%RU32, uBPP=%RU8\n",
     396              pu8RGBBuf, cbRGBBuf, uWidth, uHeight, uBytesPerLine, uBPP));
    392397
    393398    BMPFILEHDR fileHdr;
     
    409414    coreHdr.uYPelsPerMeter = 5000;
    410415
    411     static uint64_t s_iCount = 0;
     416    static uint64_t s_cRecordingUtilsBmpsDumped = 0;
    412417
    413418    /* Hardcoded path for now. */
     
    421426
    422427    char szFileName[RTPATH_MAX];
    423     if (RTStrPrintf2(szFileName, sizeof(szFileName), "%s/RecDump-%04RU64-%s-w%RU16h%RU16.bmp",
    424                      pszPath ? pszPath : szPath, s_iCount, pszWhat ? pszWhat : "Frame", uWidth, uHeight) <= 0)
     428    if (RTStrPrintf2(szFileName, sizeof(szFileName), "%s/RecDump-%04RU64-%s-w%RU32h%RU32bpp%RU8.bmp",
     429                     pszPath ? pszPath : szPath, s_cRecordingUtilsBmpsDumped, pszWhat ? pszWhat : "Frame", uWidth, uHeight, uBPP) <= 0)
    425430        return VERR_BUFFER_OVERFLOW;
    426431
    427     s_iCount++;
     432    s_cRecordingUtilsBmpsDumped++;
    428433
    429434    RTFILE fh;
     
    436441
    437442        /* Bitmaps (DIBs) are stored upside-down (thanks, OS/2), so work from the bottom up. */
    438         size_t offSrc = cbRGBBuf - uBytesPerLine;
     443        size_t offSrc = uBytesPerLine * (uHeight - 1);
     444        Assert(offSrc <= cbRGBBuf);
    439445
    440446        /* Do the copy. */
    441         for (unsigned int i = 0; i < uHeight; i++)
    442         {
    443             RTFileWrite(fh, pu8RGBBuf + offSrc, uBytesPerLine, NULL);
     447        while (offSrc)
     448        {
     449            LogFunc(("offSrc=%zu\n", offSrc));
     450            vrc = RTFileWrite(fh, pu8RGBBuf + offSrc, uWidth * uBytesPerPixel, NULL);
     451            AssertRCBreak(vrc);
     452            Assert(offSrc >= uBytesPerLine);
    444453            offSrc -= uBytesPerLine;
    445         }
    446 
    447         RTFileClose(fh);
     454
     455        }
     456
     457        int vrc2 = RTFileClose(fh);
     458        if (RT_SUCCESS(vrc))
     459            vrc = vrc2;
    448460    }
    449461
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