Changeset 105095 in vbox
- Timestamp:
- Jul 2, 2024 10:06:48 AM (5 months ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/include/ConsoleImpl.h
r105006 r105095 205 205 int i_recordingStop(util::AutoWriteLock *pAutoLock = NULL); 206 206 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); 207 208 # ifdef VBOX_WITH_AUDIO_RECORDING 208 209 AudioVideoRec *i_recordingGetAudioDrv(void) const { return mRecording.mAudioRec; } -
trunk/src/VBox/Main/include/DisplayImpl.h
r105006 r105095 46 46 #ifdef VBOX_WITH_RECORDING 47 47 # include "RecordingInternals.h" 48 class RecordingContext; 48 49 #endif 49 50 … … 188 189 int i_recordingStart(void); 189 190 int i_recordingStop(void); 190 int i_recordingInvalidate( bool fForce = false);191 int i_recordingInvalidate(void); 191 192 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); 193 195 int i_recordingCursorPositionChange(unsigned uScreenId, uint32_t fFlags, int32_t x, int32_t y); 194 196 #endif … … 414 416 415 417 #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; 420 428 #endif 421 429 422 430 #ifdef VBOX_WITH_STATISTICS 431 /** Struct for keeping STAM values. */ 423 432 struct 424 433 { -
trunk/src/VBox/Main/include/Recording.h
r105006 r105095 71 71 72 72 /** 73 * Enumeration for a recording context state. 74 */ 75 enum 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 /** 73 94 * Class for managing a recording context. 74 95 */ 75 96 class RecordingContext 76 97 { 98 friend RecordingStream; 99 100 public: 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 77 121 public: 78 122 … … 108 152 uint64_t GetCurrentPTS(void) const; 109 153 bool IsFeatureEnabled(RecordingFeature_T enmFeature); 154 bool IsFeatureEnabled(uint32_t uScreen, RecordingFeature_T enmFeature); 110 155 bool IsReady(void); 111 bool IsReady(uint32_t uScreen, uint64_t msTimestamp);112 156 bool IsStarted(void); 113 157 bool IsLimitReached(void); 114 158 bool IsLimitReached(uint32_t uScreen, uint64_t msTimestamp); 115 159 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); 118 161 119 162 /** The state mouse cursor state. … … 138 181 int unlock(void); 139 182 183 int onLimitReached(uint32_t uScreen, int vrc); 184 140 185 static DECLCALLBACK(int) threadMain(RTTHREAD hThreadSelf, void *pvUser); 141 186 … … 149 194 150 195 protected: 151 152 /**153 * Enumeration for a recording context state.154 */155 enum RECORDINGSTS156 {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 = 0x7fffffff165 };166 196 167 197 /** Pointer to the console object. */ … … 171 201 /** The current state. */ 172 202 RECORDINGSTS m_enmState; 203 /** Callback table. */ 204 CALLBACKS m_Callbacks; 173 205 /** Critical section to serialize access. */ 174 206 RTCRITSECT m_CritSect; -
trunk/src/VBox/Main/include/RecordingInternals.h
r105006 r105095 101 101 /** Pixel format. */ 102 102 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). */ 104 105 uint32_t uBytesPerLine; 105 106 } RECORDINGSURFACEINFO; … … 539 540 PRECORDINGVIDEOFRAME RecordingVideoFrameDup(PRECORDINGVIDEOFRAME pFrame); 540 541 void 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); 542 int 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); 543 int 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); 544 int 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); 543 545 int RecordingVideoFrameBlitFrame(PRECORDINGVIDEOFRAME pDstFrame, uint32_t uDstX, uint32_t uDstY, PRECORDINGVIDEOFRAME pSrcFrame, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight); 544 546 -
trunk/src/VBox/Main/include/RecordingStream.h
r105006 r105095 144 144 145 145 bool IsLimitReached(uint64_t msTimestamp) const; 146 bool Is Ready(void) const;146 bool IsFeatureEnabled(RecordingFeature_T enmFeature) const; 147 147 bool NeedsUpdate(uint64_t msTimestamp) const; 148 148 -
trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
r105087 r105095 7609 7609 int vrc = i_recordingGetSettings(recordingSettings); 7610 7610 if (RT_SUCCESS(vrc)) 7611 { 7611 7612 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 } 7612 7622 7613 7623 LogFlowFuncLeaveRC(vrc); … … 7623 7633 } 7624 7634 7625 /** 7626 * Starts recording. Does nothing if recording is already active. 7635 /** @copydoc RecordingContext::CALLBACKS::pfnStateChanged */ 7636 DECLCALLBACK(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. 7627 7660 * 7628 7661 * @returns VBox status code. … … 7646 7679 7647 7680 /** 7648 * Stops recording. Does nothing if recording is not active.7681 * Stops recording. Does nothing if recording is not in started state. 7649 7682 * 7650 7683 * Note: This does *not* disable recording for a VM, in other words, -
trunk/src/VBox/Main/src-client/DisplayImpl.cpp
r105065 r105095 130 130 #endif 131 131 132 #ifdef VBOX_WITH_RECORDING133 vrc = RTCritSectInit(&mVideoRecLock);134 AssertRC(vrc);135 136 for (unsigned i = 0; i < RT_ELEMENTS(maRecordingEnabled); i++)137 maRecordingEnabled[i] = false;138 #endif139 140 132 return BaseFinalConstruct(); 141 133 } … … 144 136 { 145 137 uninit(); 146 147 #ifdef VBOX_WITH_RECORDING148 if (RTCritSectIsInitialized(&mVideoRecLock))149 {150 RTCritSectDelete(&mVideoRecLock);151 RT_ZERO(mVideoRecLock);152 }153 #endif154 138 155 139 videoAccelDestroy(&mVideoAccelLegacy); … … 565 549 } 566 550 551 #ifdef VBOX_WITH_RECORDING 552 unconst(Recording.pCtx) = mParent->i_recordingGetContext(); 553 #endif 554 567 555 /* Confirm a successful initialization */ 568 556 autoInitSpan.setSucceeded(); … … 796 784 const bool fDisabled = pFBInfo->fDisabled; 797 785 786 alock.release(); /* Release lock before recording code gets involved below. */ 787 798 788 #ifdef VBOX_WITH_RECORDING 799 789 /* Recording needs to be called before releasing the display's lock below. */ 800 790 i_recordingScreenChanged(uScreenId, pFBInfo); 801 791 #endif 802 803 alock.release();804 792 805 793 if (!pFramebuffer.isNull()) … … 834 822 LogRelFlowFunc(("[%d]: default format %d\n", uScreenId, pFBInfo->fDefaultFormat)); 835 823 824 LogFlowFuncLeave(); 836 825 return VINF_SUCCESS; 837 826 } … … 911 900 912 901 #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); 922 903 #endif 923 904 } … … 955 936 pFBInfo->updateImage.pu8Address = pAddress; 956 937 pFBInfo->updateImage.cbLine = ulBytesPerLine; 957 #ifdef VBOX_WITH_RECORDING958 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 #endif968 938 } 969 939 … … 1006 976 const uint8_t *pu8Src = pbAddress + ulBytesPerLine * y + x * uBytesPerPixel; 1007 977 1008 for (int i = y; i < y +h; ++i)978 for (int i = 0; i < h; ++i) 1009 979 { 1010 980 memcpy(pu8Dst, pu8Src, w * uBytesPerPixel); … … 1016 986 1017 987 #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); 1027 991 #endif 1028 992 } … … 1170 1134 bool fMoveCursor = mcVRDPRefs == 0; 1171 1135 #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() 1176 1138 && pCtx->IsFeatureEnabled(RecordingFeature_Video)) 1177 1139 fRenderCursor = fMoveCursor = false; … … 2157 2119 #endif 2158 2120 2159 return i_recordingInvalidate( true /* fForce */);2121 return i_recordingInvalidate(); 2160 2122 } 2161 2123 … … 2179 2141 #endif 2180 2142 2181 return i_recordingInvalidate( true /* fForce */);2143 return i_recordingInvalidate(); 2182 2144 } 2183 2145 … … 2186 2148 * 2187 2149 * @returns VBox status code. 2188 * @param fForce Whether to force invalidation or not. Default is @c false.2189 2150 * 2190 * @note Takes the display's readlock.2151 * @note Takes the display's write lock. 2191 2152 */ 2192 int Display::i_recordingInvalidate(bool fForce /* = false */) 2193 { 2194 RecordingContext *pCtx = mParent->i_recordingGetContext(); 2195 if (!pCtx) 2196 return VINF_SUCCESS; 2197 2153 int Display::i_recordingInvalidate(void) 2154 { 2198 2155 LogFlowFuncEnter(); 2199 2156 2200 Auto ReadLock alock(this COMMA_LOCKVAL_SRC_POS);2157 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 2201 2158 2202 2159 /* … … 2205 2162 for (unsigned uScreen = 0; uScreen < mcMonitors; uScreen++) 2206 2163 { 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); 2220 2166 } 2221 2167 … … 2232 2178 int Display::i_recordingScreenChanged(unsigned uScreenId, const DISPLAYFBINFO *pFBInfo) 2233 2179 { 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)) 2241 2188 { 2242 2189 /* Skip recording this screen. */ … … 2244 2191 } 2245 2192 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(); 2247 2232 2248 2233 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; 2252 2237 ScreenInfo.enmPixelFmt = RECORDINGPIXELFMT_BRGA32; /** @todo Does this apply everywhere? */ 2253 2238 … … 2257 2242 if (RT_SUCCESS(vrc)) 2258 2243 { 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 2295 2256 return vrc; 2296 2257 } 2297 2258 2298 2259 /** 2299 * Called when a part of a screen got updated.2260 * Sends a screen update to the recording facility. 2300 2261 * 2301 2262 * @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. 2304 2271 */ 2305 int Display::i_recordingScreenUpdate(unsigned uScreenId, PRECORDINGVIDEOFRAME pFrame) 2306 { 2307 if ( uScreenId >= mcMonitors /* Might be SVGA_ID_INVALID. */ 2308 || !maRecordingEnabled[uScreenId]) 2272 int 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)) 2309 2286 return VINF_SUCCESS; 2310 2287 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 2322 2295 2323 2296 uint64_t const tsNowMs = pCtx->GetCurrentPTS(); 2324 2297 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); 2336 2319 2337 2320 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 */ 2333 int 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); 2338 2372 } 2339 2373 … … 2353 2387 RT_NOREF(fFlags); 2354 2388 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)) 2357 2397 return VINF_SUCCESS; 2358 2398 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()); 2378 2400 } 2379 2401 #endif /* VBOX_WITH_RECORDING */ -
trunk/src/VBox/Main/src-client/Recording.cpp
r105010 r105095 137 137 vrc = RecordingVideoFrameBlitRaw(&m_Shape, 0, 0, &pu8Shape[offShape], cbShape - offShape, 0, 0, uWidth, uHeight, uWidth * 4 /* BPP */, uBPP, 138 138 m_Shape.Info.enmPixelFmt); 139 #if def DEBUG_andy_disabled139 #if 0 140 140 RecordingUtilsDbgDumpVideoFrameEx(&m_Shape, "/tmp/recording", "cursor-update"); 141 141 #endif … … 530 530 531 531 m_pConsole = ptrConsole; 532 RT_ZERO(m_Callbacks); 532 533 533 534 settings::RecordingScreenSettingsMap::const_iterator itScreen = m_Settings.mapScreens.begin(); … … 537 538 try 538 539 { 539 pStream = new RecordingStream(this, itScreen->first /* Screen ID */, itScreen->second);540 m_vecStreams.push_back(pStream);541 540 if (itScreen->second.fEnabled) 541 { 542 pStream = new RecordingStream(this, itScreen->first /* Screen ID */, itScreen->second); 543 m_vecStreams.push_back(pStream); 542 544 m_cStreamsEnabled++; 543 LogFlowFunc(("pStream=%p\n", pStream)); 545 LogFlowFunc(("pStream=%p\n", pStream)); 546 } 544 547 } 545 548 catch (std::bad_alloc &) … … 565 568 vrc = RTSemEventCreate(&m_WaitEvent); 566 569 AssertRCReturn(vrc, vrc); 570 571 RT_ZERO(m_Callbacks); 567 572 } 568 573 … … 571 576 572 577 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 */ 586 void 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(); 573 594 } 574 595 … … 857 878 858 879 /** 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. 862 883 * @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 */ 888 bool RecordingContext::IsFeatureEnabled(uint32_t uScreen, RecordingFeature_T enmFeature) 889 { 869 890 lock(); 870 891 871 892 bool fIsReady = false; 872 893 873 if (m_enmState != RECORDINGSTS_STARTED)894 if (m_enmState == RECORDINGSTS_STARTED) 874 895 { 875 896 const RecordingStream *pStream = getStreamInternal(uScreen); 876 897 if (pStream) 877 fIsReady = pStream->Is Ready();898 fIsReady = pStream->IsFeatureEnabled(enmFeature); 878 899 879 900 /* Note: Do not check for other constraints like the video FPS rate here, … … 890 911 * Returns whether a given recording context has been started or not. 891 912 * 892 * @returns true if active,false if not.913 * @returns @c true if started, @c false if not. 893 914 */ 894 915 bool RecordingContext::IsStarted(void) … … 906 927 * Checks if a specified limit for recording has been reached. 907 928 * 908 * @returns true if any limit has been reached.929 * @returns @c true if any limit has been reached, @c false if not. 909 930 */ 910 931 bool RecordingContext::IsLimitReached(void) … … 924 945 * Checks if a specified limit for recording has been reached. 925 946 * 926 * @returns true if any limit has been reached.947 * @returns @c true if any limit has been reached, @c false if not. 927 948 * @param uScreen Screen ID. 928 949 * @param msTimestamp Timestamp (PTS, in ms) to check for. … … 982 1003 } 983 1004 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 */ 1012 DECLCALLBACK(int) RecordingContext::onLimitReached(uint32_t uScreen, int vrc) 1013 { 987 1014 LogFlowThisFunc(("Stream %RU32 has reached its limit (%Rrc)\n", uScreen, vrc)); 988 1015 … … 990 1017 991 1018 Assert(m_cStreamsEnabled); 992 m_cStreamsEnabled--; 1019 if (m_cStreamsEnabled) 1020 m_cStreamsEnabled--; 1021 1022 bool const fAllDisabled = m_cStreamsEnabled == 0; 993 1023 994 1024 LogFlowThisFunc(("cStreamsEnabled=%RU16\n", m_cStreamsEnabled)); 995 1025 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); 997 1031 998 1032 return VINF_SUCCESS; … … 1032 1066 AssertPtrReturn(pFrame, VERR_INVALID_POINTER); 1033 1067 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)); 1036 1071 1037 1072 if (!pFrame->pau8Buf) /* Empty / invalid frame, skip. */ … … 1039 1074 1040 1075 /* Sanity. */ 1076 AssertReturn(pFrame->Info.uBPP, VERR_INVALID_PARAMETER); 1077 AssertReturn(pFrame->cbBuf, VERR_INVALID_PARAMETER); 1041 1078 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);1043 1079 1044 1080 lock(); … … 1048 1084 { 1049 1085 unlock(); 1050 1051 AssertFailed();1052 return VERR_NOT_FOUND; 1053 }1086 return VINF_SUCCESS; 1087 } 1088 1089 unlock(); 1054 1090 1055 1091 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. */ 1062 1093 threadNotify(); 1063 }1064 1094 1065 1095 return vrc; … … 1083 1113 return VINF_SUCCESS; 1084 1114 1085 if (uScreen == 0xFFFFFFFF /* SVGA_ID_INVALID */)1086 uScreen = 0;1087 1088 1115 int vrc = m_Cursor.Move(x, y); 1089 1116 if (RT_SUCCESS(vrc)) … … 1095 1122 { 1096 1123 unlock(); 1097 1098 AssertFailed(); 1099 return VERR_NOT_FOUND; 1124 return VINF_SUCCESS; 1100 1125 } 1101 1126 1127 unlock(); 1128 1102 1129 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. */ 1109 1131 threadNotify(); 1110 }1111 1132 } 1112 1133 … … 1160 1181 unlock(); 1161 1182 1162 if ( RT_SUCCESS(vrc))1183 if (vrc == VINF_SUCCESS) /* Might be VINF_RECORDING_THROTTLED or VINF_RECORDING_LIMIT_REACHED. */ 1163 1184 threadNotify(); 1164 1185 … … 1182 1203 { 1183 1204 unlock(); 1184 1185 AssertFailed();1186 return VERR_NOT_FOUND; 1187 }1205 return VINF_SUCCESS; 1206 } 1207 1208 unlock(); 1188 1209 1189 1210 int const vrc = pStream->SendScreenChange(pInfo, msTimestamp); 1190 1211 1191 unlock();1192 1193 1212 return vrc; 1194 1213 } -
trunk/src/VBox/Main/src-client/RecordingCodec.cpp
r105067 r105095 374 374 * - if available (through mouse integration via Guest Additions): the guest's mouse cursor via a (software) overlay 375 375 * 376 * So composing is done the fol owing way:376 * So composing is done the following way: 377 377 * 378 378 * - always store the plain framebuffer updates in our back buffer first … … 388 388 PRECORDINGVIDEOFRAME pSrc = &pFrame->u.Video; 389 389 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); 392 394 #if 0 393 395 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); 395 399 #endif 396 400 vrc = RecordingVideoFrameBlitFrame(pBack, pSrc->Pos.x, pSrc->Pos.y, … … 499 503 pCodec->Parms.u.Video.Scaling.u.Crop.m_iOriginX, pCodec->Parms.u.Video.Scaling.u.Crop.m_iOriginY)); 500 504 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 515 505 vrc = RecordingUtilsCoordsCropCenter(&pCodec->Parms, &sx, &sy, &sw, &sh, &dx, &dy); 516 506 if (vrc == VINF_SUCCESS) /* vrc might be VWRN_RECORDING_ENCODING_SKIPPED to skip encoding. */ … … 546 536 static DECLCALLBACK(int) recordingCodecVPXScreenChange(PRECORDINGCODEC pCodec, PRECORDINGSURFACEINFO pInfo) 547 537 { 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->uWidth553 || !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 561 538 /* The VPX encoder only understands even frame sizes. */ 562 539 if ( (pInfo->uWidth % 2) != 0 … … 1206 1183 int recordingCodecScreenChange(PRECORDINGCODEC pCodec, PRECORDINGSURFACEINFO pInfo) 1207 1184 { 1185 LogRel2(("Recording: Codec got screen change notification (%RU16x%RU16, %RU8 BPP)\n", 1186 pInfo->uWidth, pInfo->uHeight, pInfo->uBPP)); 1187 1208 1188 if (!pCodec->Ops.pfnScreenChange) 1209 1189 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); 1210 1196 1211 1197 return pCodec->Ops.pfnScreenChange(pCodec, pInfo); -
trunk/src/VBox/Main/src-client/RecordingInternals.cpp
r105011 r105095 248 248 * @param enmSrcFmt Pixel format of source data. Must match \a pFrame. 249 249 */ 250 DECLINLINE(int) recordingVideo FrameBlitRaw(uint8_t *pu8Dst, size_t cbDst, uint32_t uDstX, uint32_t uDstY,251 252 253 250 DECLINLINE(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) 254 254 { 255 255 RT_NOREF(enmDstFmt, enmSrcFmt); … … 275 275 276 276 return VINF_SUCCESS; 277 } 278 279 int 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); 277 286 } 278 287 … … 366 375 uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmFmt) 367 376 { 368 return recordingVideo FrameBlitRaw(/* Destination */369 370 371 372 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); 373 382 } 374 383 … … 377 386 * 378 387 * @returns VBox status code. 379 * @param p FrameDestination frame.388 * @param pDstFrame Destination frame. 380 389 * @param uDstX X destination (in pixel) within destination frame. 381 390 * @param uDstY Y destination (in pixel) within destination frame. … … 390 399 * @param enmFmt Pixel format of source data. Must match \a pFrame. 391 400 */ 392 int RecordingVideoFrameBlitRawAlpha(PRECORDINGVIDEOFRAME p Frame, uint32_t uDstX, uint32_t uDstY,401 int RecordingVideoFrameBlitRawAlpha(PRECORDINGVIDEOFRAME pDstFrame, uint32_t uDstX, uint32_t uDstY, 393 402 const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight, 394 403 uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmFmt) 395 404 { 396 return recordingVideoFrameBlitRawAlpha(p Frame, uDstX, uDstY,405 return recordingVideoFrameBlitRawAlpha(pDstFrame, uDstX, uDstY, 397 406 pu8Src, cbSrc, uSrcX, uSrcY, uSrcWidth, uSrcHeight, uSrcBytesPerLine, uSrcBPP, enmFmt); 398 407 } … … 416 425 PRECORDINGVIDEOFRAME pSrcFrame, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight) 417 426 { 418 return recordingVideo FrameBlitRaw(/* Dest */419 420 421 422 423 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); 424 433 } 425 434 -
trunk/src/VBox/Main/src-client/RecordingStream.cpp
r105006 r105095 148 148 149 149 if ( m_ScreenSettings.ulMaxTimeS 150 && msTimestamp >= m_ tsStartMs + (m_ScreenSettings.ulMaxTimeS * RT_MS_1SEC))150 && msTimestamp >= m_ScreenSettings.ulMaxTimeS * RT_MS_1SEC) 151 151 { 152 152 LogRel(("Recording: Time limit for stream #%RU16 has been reached (%RU32s)\n", … … 185 185 * 186 186 * @returns VBox status code. 187 * @retval VINF_RECORDING_LIMIT_REACHED if the stream's recording limit has been reached. 187 188 * @param msTimestamp Timestamp (PTS, in ms). 189 * 190 * @note Caller must *not* have the stream's lock (callbacks involved). 188 191 */ 189 192 int RecordingStream::iterateInternal(uint64_t msTimestamp) 190 193 { 194 AssertReturn(!RTCritSectIsOwner(&m_CritSect), VERR_WRONG_ORDER); 195 191 196 if (!m_fEnabled) 192 197 return VINF_SUCCESS; … … 209 214 m_fEnabled = false; 210 215 211 int vrc2 = m_pCtx-> OnLimitReached(m_uScreenID, VINF_SUCCESS /* vrc */);216 int vrc2 = m_pCtx->onLimitReached(m_uScreenID, VINF_SUCCESS /* vrc */); 212 217 AssertRC(vrc2); 213 218 break; … … 230 235 bool RecordingStream::IsLimitReached(uint64_t msTimestamp) const 231 236 { 232 if (! IsReady())237 if (!m_fEnabled) 233 238 return true; 234 239 … … 237 242 238 243 /** 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. 240 245 * 241 246 * @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 */ 249 bool RecordingStream::IsFeatureEnabled(RecordingFeature_T enmFeature) const 250 { 251 return m_fEnabled && m_ScreenSettings.isFeatureEnabled(enmFeature); 246 252 } 247 253 … … 392 398 * 393 399 * @returns VBox status code. 400 * @retval VINF_RECORDING_LIMIT_REACHED if the stream's recording limit has been reached. 394 401 * @param rcWait Result of the encoding thread's wait operation. 395 402 * Can be used for figuring out if the encoder has to perform some … … 401 408 int RecordingStream::ThreadMain(int rcWait, RecordingBlockMap &commonBlocks) 402 409 { 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(); 404 413 405 414 /* No new data arrived within time? Feed the encoder with the last frame we built. … … 410 419 && m_ScreenSettings.isFeatureEnabled(RecordingFeature_Video)) 411 420 { 412 return recordingCodecEncodeCurrent(&m_CodecVideo, m _pCtx->GetCurrentPTS());421 return recordingCodecEncodeCurrent(&m_CodecVideo, msTimestamp); 413 422 } 414 423 … … 528 537 AssertPtrReturn(pPos, VERR_INVALID_POINTER); 529 538 530 lock();531 532 539 int vrc = iterateInternal(msTimestamp); 533 540 if (vrc != VINF_SUCCESS) /* Can return VINF_RECORDING_LIMIT_REACHED. */ 534 {535 unlock();536 541 return vrc; 537 }538 542 539 543 PRECORDINGFRAME pFrame = (PRECORDINGFRAME)RTMemAlloc(sizeof(RECORDINGFRAME)); … … 544 548 pFrame->u.Cursor.Pos = *pPos; 545 549 550 lock(); 551 546 552 vrc = addFrame(pFrame, msTimestamp); 547 553 … … 568 574 AssertPtrReturn(m_pCtx, VERR_WRONG_ORDER); 569 575 570 lock();571 572 576 int vrc = iterateInternal(msTimestamp); 573 577 if (vrc != VINF_SUCCESS) /* Can return VINF_RECORDING_LIMIT_REACHED. */ 574 {575 unlock();576 578 return vrc; 577 }578 579 579 580 PRECORDINGFRAME pFrame = (PRECORDINGFRAME)RTMemAlloc(sizeof(RECORDINGFRAME)); … … 589 590 pFrame->msTimestamp = msTimestamp; 590 591 592 lock(); 593 591 594 vrc = addFrame(pFrame, msTimestamp); 595 596 unlock(); 592 597 593 598 if (RT_FAILURE(vrc)) … … 596 601 RecordingFrameFree(pFrame); 597 602 } 598 599 unlock();600 603 601 604 LogFlowFuncLeaveRC(vrc); … … 620 623 AssertPtrReturn(m_pCtx, VERR_WRONG_ORDER); 621 624 622 lock();623 624 625 int vrc = iterateInternal(msTimestamp); 625 626 if (vrc != VINF_SUCCESS) /* Can return VINF_RECORDING_LIMIT_REACHED. */ 626 {627 unlock();628 627 return vrc; 629 }630 628 631 629 PRECORDINGFRAME pFrame = (PRECORDINGFRAME)RTMemAlloc(sizeof(RECORDINGFRAME)); … … 633 631 634 632 pFrame->u.Video = *pVideoFrame; 633 635 634 /* Make a deep copy of the pixel data. */ 636 pFrame->u.Video.pau8Buf = (uint8_t *)RTMem Dup(pVideoFrame->pau8Buf,pVideoFrame->cbBuf);635 pFrame->u.Video.pau8Buf = (uint8_t *)RTMemAlloc(pVideoFrame->cbBuf); 637 636 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; 639 647 640 648 pFrame->enmType = RECORDINGFRAME_TYPE_VIDEO; 641 649 pFrame->msTimestamp = msTimestamp; 642 650 651 lock(); 652 643 653 vrc = addFrame(pFrame, msTimestamp); 654 655 unlock(); 644 656 645 657 if (RT_FAILURE(vrc)) … … 648 660 RecordingFrameFree(pFrame); 649 661 } 650 651 unlock();652 662 653 663 LogFlowFuncLeaveRC(vrc); -
trunk/src/VBox/Main/src-client/RecordingUtils.cpp
r105010 r105095 42 42 #endif 43 43 44 #define LOG_GROUP LOG_GROUP_RECORDING 44 45 #include <VBox/log.h> 45 46 … … 370 371 * @returns VBox status code. 371 372 * @param pu8RGBBuf Pointer to actual RGB image data. 373 * Must point right to the beginning of the pixel data (offset, if any). 372 374 * @param cbRGBBuf Size (in bytes) of \a pu8RGBBuf. 373 375 * @param pszPath Absolute path to dump file to. Must exist. … … 383 385 uint32_t uWidth, uint32_t uHeight, uint32_t uBytesPerLine, uint8_t uBPP) 384 386 { 385 RT_NOREF(cbRGBBuf);386 387 387 const uint8_t uBytesPerPixel = uBPP / 8 /* Bits */; 388 388 const size_t cbData = uWidth * uHeight * uBytesPerPixel; … … 390 390 if (!cbData) /* No data to write? Bail out early. */ 391 391 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)); 392 397 393 398 BMPFILEHDR fileHdr; … … 409 414 coreHdr.uYPelsPerMeter = 5000; 410 415 411 static uint64_t s_ iCount= 0;416 static uint64_t s_cRecordingUtilsBmpsDumped = 0; 412 417 413 418 /* Hardcoded path for now. */ … … 421 426 422 427 char szFileName[RTPATH_MAX]; 423 if (RTStrPrintf2(szFileName, sizeof(szFileName), "%s/RecDump-%04RU64-%s-w%RU 16h%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) 425 430 return VERR_BUFFER_OVERFLOW; 426 431 427 s_ iCount++;432 s_cRecordingUtilsBmpsDumped++; 428 433 429 434 RTFILE fh; … … 436 441 437 442 /* 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); 439 445 440 446 /* 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); 444 453 offSrc -= uBytesPerLine; 445 } 446 447 RTFileClose(fh); 454 455 } 456 457 int vrc2 = RTFileClose(fh); 458 if (RT_SUCCESS(vrc)) 459 vrc = vrc2; 448 460 } 449 461
Note:
See TracChangeset
for help on using the changeset viewer.