VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/RecordingInternals.cpp@ 105011

Last change on this file since 105011 was 105011, checked in by vboxsync, 3 months ago

Video Recording: SCM fix. bugref:10650

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.1 KB
Line 
1/* $Id: RecordingInternals.cpp 105011 2024-06-24 18:56:05Z vboxsync $ */
2/** @file
3 * Recording internals code.
4 */
5
6/*
7 * Copyright (C) 2012-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include "RecordingInternals.h"
29#include "RecordingUtils.h"
30
31#include <iprt/assert.h>
32#include <iprt/mem.h>
33
34#ifdef DEBUG
35# include <math.h>
36# include <iprt/file.h>
37# include <iprt/formats/bmp.h>
38#endif
39
40
41/*********************************************************************************************************************************
42* Prototypes *
43*********************************************************************************************************************************/
44DECLINLINE(int) recordingVideoFrameInit(PRECORDINGVIDEOFRAME pFrame, uint32_t fFlags, uint32_t uWidth, uint32_t uHeight, uint32_t uPosX, uint32_t uPosY,
45 uint8_t uBPP, RECORDINGPIXELFMT enmFmt);
46
47
48/**
49 * Allocates an empty video frame, inline version.
50 *
51 * @returns Allocated video frame on success, or NULL on failure.
52 */
53DECLINLINE(PRECORDINGVIDEOFRAME) recordingVideoFrameAlloc(void)
54{
55 return (PRECORDINGVIDEOFRAME)RTMemAlloc(sizeof(RECORDINGVIDEOFRAME));
56}
57
58/**
59 * Allocates an empty video frame.
60 *
61 * @returns Allocated video frame on success, or NULL on failure.
62 */
63PRECORDINGVIDEOFRAME RecordingVideoFrameAlloc(void)
64{
65 PRECORDINGVIDEOFRAME pFrame = recordingVideoFrameAlloc();
66 AssertPtrReturn(pFrame, NULL);
67 RT_BZERO(pFrame, sizeof(RECORDINGVIDEOFRAME));
68 return pFrame;
69}
70
71/**
72 * Returns an allocated video frame from given image data.
73 *
74 * @returns Allocated video frame on success, or NULL on failure.
75 * @param pvData Pointer to image data to use.
76 * @param x X location hint (in pixel) to use for allocated frame.
77 * This is *not* the offset within \a pvData!
78 * @param y X location hint (in pixel) to use for allocated frame.
79 * This is *not* the offset within \a pvData!
80 * @param w Width (in pixel) of \a pvData image data.
81 * @param h Height (in pixel) of \a pvData image data.
82 * @param uBPP Bits per pixel) of \a pvData image data.
83 * @param enmFmt Pixel format of \a pvData image data.
84 */
85PRECORDINGVIDEOFRAME RecordingVideoFrameAllocEx(const void *pvData, uint32_t x, uint32_t y, uint32_t w, uint32_t h,
86 uint8_t uBPP, RECORDINGPIXELFMT enmFmt)
87{
88 PRECORDINGVIDEOFRAME pFrame = recordingVideoFrameAlloc();
89 AssertPtrReturn(pFrame, NULL);
90 int vrc = recordingVideoFrameInit(pFrame, RECORDINGVIDEOFRAME_F_VISIBLE, w, h, x, y, uBPP, enmFmt);
91 AssertRCReturn(vrc, NULL);
92 memcpy(pFrame->pau8Buf, pvData, pFrame->cbBuf);
93
94 return VINF_SUCCESS;
95}
96
97/**
98 * Frees a recording video frame.
99 *
100 * @param pFrame Pointer to video frame to free. The pointer will be invalid after return.
101 */
102void RecordingVideoFrameFree(PRECORDINGVIDEOFRAME pFrame)
103{
104 if (!pFrame)
105 return;
106
107 RecordingVideoFrameDestroy(pFrame);
108
109 RTMemFree(pFrame);
110}
111
112/**
113 * Initializes a recording frame, inline version.
114 *
115 * @returns VBox status code.
116 * @param pFrame Pointer to video frame to initialize.
117 * @param fFlags Flags of type RECORDINGVIDEOFRAME_F_XXX.
118 * @param uWidth Width (in pixel) of video frame.
119 * @param uHeight Height (in pixel) of video frame.
120 * @param uPosX X positioning hint.
121 * @param uPosY Y positioning hint.
122 * @param uBPP Bits per pixel (BPP).
123 * @param enmFmt Pixel format to use.
124 */
125DECLINLINE(int) recordingVideoFrameInit(PRECORDINGVIDEOFRAME pFrame, uint32_t fFlags, uint32_t uWidth, uint32_t uHeight,
126 uint32_t uPosX, uint32_t uPosY, uint8_t uBPP, RECORDINGPIXELFMT enmFmt)
127{
128 AssertPtrReturn(pFrame, VERR_INVALID_POINTER);
129 AssertReturn(uWidth, VERR_INVALID_PARAMETER);
130 AssertReturn(uHeight, VERR_INVALID_PARAMETER);
131 AssertReturn(uBPP && uBPP % 8 == 0, VERR_INVALID_PARAMETER);
132
133 /* Calculate bytes per pixel and set pixel format. */
134 const unsigned uBytesPerPixel = uBPP / 8;
135
136 /* Calculate bytes per pixel and set pixel format. */
137 const size_t cbRGBBuf = uWidth * uHeight * uBytesPerPixel;
138 AssertReturn(cbRGBBuf, VERR_INVALID_PARAMETER);
139
140 pFrame->pau8Buf = (uint8_t *)RTMemAlloc(cbRGBBuf);
141 AssertPtrReturn(pFrame->pau8Buf, VERR_NO_MEMORY);
142 pFrame->cbBuf = cbRGBBuf;
143
144 pFrame->fFlags = fFlags;
145 pFrame->Info.uWidth = uWidth;
146 pFrame->Info.uHeight = uHeight;
147 pFrame->Info.uBPP = uBPP;
148 pFrame->Info.enmPixelFmt = enmFmt;
149 pFrame->Info.uBytesPerLine = uWidth * uBytesPerPixel;
150 pFrame->Pos.x = uPosX;
151 pFrame->Pos.y = uPosY;
152
153 return VINF_SUCCESS;
154}
155
156/**
157 * Initializes a recording frame.
158 *
159 * @param pFrame Pointer to video frame to initialize.
160 * @param fFlags Flags of type RECORDINGVIDEOFRAME_F_XXX.
161 * @param uWidth Width (in pixel) of video frame.
162 * @param uHeight Height (in pixel) of video frame.
163 * @param uPosX X positioning hint.
164 * @param uPosY Y positioning hint.
165 * @param uBPP Bits per pixel (BPP).
166 * @param enmFmt Pixel format to use.
167 */
168int RecordingVideoFrameInit(PRECORDINGVIDEOFRAME pFrame, uint32_t fFlags, uint32_t uWidth, uint32_t uHeight, uint32_t uPosX, uint32_t uPosY,
169 uint8_t uBPP, RECORDINGPIXELFMT enmFmt)
170{
171 return recordingVideoFrameInit(pFrame, fFlags, uWidth, uHeight, uPosX, uPosY, uBPP, enmFmt);
172}
173
174/**
175 * Destroys a recording video frame.
176 *
177 * @param pFrame Pointer to video frame to destroy.
178 */
179void RecordingVideoFrameDestroy(PRECORDINGVIDEOFRAME pFrame)
180{
181 if (!pFrame)
182 return;
183
184 if (pFrame->pau8Buf)
185 {
186 Assert(pFrame->cbBuf);
187 RTMemFree(pFrame->pau8Buf);
188 pFrame->pau8Buf = NULL;
189 pFrame->cbBuf = 0;
190 }
191}
192
193/**
194 * Duplicates a video frame.
195 *
196 * @returns Pointer to duplicated frame on success, or NULL on failure.
197 * @param pFrame Video frame to duplicate.
198 */
199PRECORDINGVIDEOFRAME RecordingVideoFrameDup(PRECORDINGVIDEOFRAME pFrame)
200{
201 PRECORDINGVIDEOFRAME pFrameDup = (PRECORDINGVIDEOFRAME)RTMemDup(pFrame, sizeof(RECORDINGVIDEOFRAME));
202 AssertPtrReturn(pFrameDup, NULL);
203 pFrameDup->pau8Buf = (uint8_t *)RTMemDup(pFrame->pau8Buf, pFrame->cbBuf);
204 AssertPtrReturnStmt(pFrameDup, RTMemFree(pFrameDup), NULL);
205
206 return pFrameDup;
207}
208
209/**
210 * Clears the content of a video recording frame, inlined version.
211 *
212 * @param pFrame Video recording frame to clear content for.
213 */
214DECLINLINE(void) recordingVideoFrameClear(PRECORDINGVIDEOFRAME pFrame)
215{
216 RT_BZERO(pFrame->pau8Buf, pFrame->cbBuf);
217}
218
219/**
220 * Clears the content of a video recording frame.
221 *
222 * @param pFrame Video recording frame to clear content for.
223 */
224void RecordingVideoFrameClear(PRECORDINGVIDEOFRAME pFrame)
225{
226 recordingVideoFrameClear(pFrame);
227}
228
229/**
230 * Simple blitting function for raw image data, inlined version.
231 *
232 * @returns VBox status code.
233 * @param pu8Dst Destination buffer.
234 * @param cbDst Size (in bytes) of \a pu8Dst.
235 * @param uDstX X destination (in pixel) within destination frame.
236 * @param uDstY Y destination (in pixel) within destination frame.
237 * @param uDstBytesPerLine Bytes per line in destination buffer.
238 * @param uDstBPP BPP of destination buffer.
239 * @param enmDstFmt Pixel format of source data. Must match \a pFrame.
240 * @param pu8Src Source data to blit. Must be in the same pixel format as \a pFrame.
241 * @param cbSrc Size (in bytes) of \a pu8Src.
242 * @param uSrcX X start (in pixel) within source data.
243 * @param uSrcY Y start (in pixel) within source data.
244 * @param uSrcWidth Width (in pixel) to blit from source data.
245 * @param uSrcHeight Height (in pixel) to blit from data.
246 * @param uSrcBytesPerLine Bytes per line in source data.
247 * @param uSrcBPP BPP of source data. Must match \a pFrame.
248 * @param enmSrcFmt Pixel format of source data. Must match \a pFrame.
249 */
250DECLINLINE(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)
254{
255 RT_NOREF(enmDstFmt, enmSrcFmt);
256
257 uint8_t const uDstBytesPerPixel = uDstBPP / 8;
258 uint8_t const uSrcBytesPerPixel = uSrcBPP / 8;
259
260 size_t offSrc = RT_MIN(uSrcY * uSrcBytesPerLine + uSrcX * uSrcBytesPerPixel, cbSrc);
261 size_t offDst = RT_MIN(uDstY * uDstBytesPerLine + uDstX * uDstBytesPerPixel, cbDst);
262
263 for (uint32_t y = 0; y < uSrcHeight; y++)
264 {
265 size_t const cbToCopy = RT_MIN(cbDst - offDst,
266 RT_MIN(uSrcWidth * uSrcBytesPerPixel, cbSrc - offSrc));
267 if (!cbToCopy)
268 break;
269 memcpy(pu8Dst + offDst, (const uint8_t *)pu8Src + offSrc, cbToCopy);
270 offDst = RT_MIN(offDst + uDstBytesPerLine, cbDst);
271 Assert(offDst <= cbDst);
272 offSrc = RT_MIN(offSrc + uSrcBytesPerLine, cbSrc);
273 Assert(offSrc <= cbSrc);
274 }
275
276 return VINF_SUCCESS;
277}
278
279/**
280 * Simple blitting function for raw image data with alpha channel, inlined version.
281 *
282 * @returns VBox status code.
283 * @param pFrame Destination frame.
284 * @param uDstX X destination (in pixel) within destination frame.
285 * @param uDstY Y destination (in pixel) within destination frame.
286 * @param pu8Src Source data to blit. Must be in the same pixel format as \a pFrame.
287 * @param cbSrc Size (in bytes) of \a pu8Src.
288 * @param uSrcX X start (in pixel) within source data.
289 * @param uSrcY Y start (in pixel) within source data.
290 * @param uSrcWidth Width (in pixel) to blit from source data.
291 * @param uSrcHeight Height (in pixel) to blit from data.
292 * @param uSrcBytesPerLine Bytes per line in source data.
293 * @param uSrcBPP BPP of source data. Must match \a pFrame.
294 * @param enmFmt Pixel format of source data. Must match \a pFrame.
295 */
296DECLINLINE(int) recordingVideoFrameBlitRawAlpha(PRECORDINGVIDEOFRAME pFrame, uint32_t uDstX, uint32_t uDstY,
297 const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight,
298 uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmFmt)
299{
300 AssertReturn(pFrame->Info.enmPixelFmt == enmFmt, VERR_NOT_SUPPORTED);
301 AssertReturn(pFrame->Info.uBPP == uSrcBPP, VERR_NOT_SUPPORTED);
302
303 RT_NOREF(uDstX, uDstY, cbSrc, uSrcX, uSrcY, uSrcBytesPerLine);
304 uint8_t const uDstBytesPerPixel = pFrame->Info.uBPP / 8;
305 uint8_t const uSrcBytesPerPixel = uSrcBPP / 8;
306
307 for (uint32_t y = 0; y < uSrcHeight; y++)
308 {
309 size_t offSrc = RT_MIN((uSrcY + y) * uSrcBytesPerLine + uSrcX * uSrcBytesPerPixel, cbSrc);
310 size_t offDst = RT_MIN((uDstY + y) * pFrame->Info.uBytesPerLine + uDstX * uDstBytesPerPixel, pFrame->cbBuf);
311
312 for (uint32_t x = 0; x < uSrcWidth; x++)
313 {
314 /* BGRA */
315 int const idx_b = 0;
316 int const idx_g = 1;
317 int const idx_r = 2;
318 int const idx_a = 3;
319
320 unsigned int const alpha = pu8Src[offSrc + idx_a] + 1;
321 unsigned int const inv_alpha = 256 - pu8Src[offSrc + idx_a];
322 if (pu8Src[offSrc + idx_a])
323 {
324 pFrame->pau8Buf[offDst + idx_r] = (unsigned char)((alpha * pu8Src[offSrc + idx_r] + inv_alpha * pFrame->pau8Buf[offDst + idx_r]) >> 8);
325 pFrame->pau8Buf[offDst + idx_g] = (unsigned char)((alpha * pu8Src[offSrc + idx_g] + inv_alpha * pFrame->pau8Buf[offDst + idx_g]) >> 8);
326 pFrame->pau8Buf[offDst + idx_b] = (unsigned char)((alpha * pu8Src[offSrc + idx_b] + inv_alpha * pFrame->pau8Buf[offDst + idx_b]) >> 8);
327 pFrame->pau8Buf[offDst + idx_a] = 0xff;
328 }
329
330 offSrc = RT_MIN(offSrc + uSrcBytesPerPixel, cbSrc);
331 if (offSrc >= cbSrc)
332 break;
333 offDst = RT_MIN(offDst + uDstBytesPerPixel, pFrame->cbBuf);
334 if (offDst >= pFrame->cbBuf)
335 break;
336 }
337 }
338
339#if 0
340 RecordingUtilsDbgDumpImageData(pu8Src, cbSrc, "/tmp", "cursor-src", uSrcWidth, uSrcHeight, uSrcBytesPerLine, 32);
341 RecordingUtilsDbgDumpVideoFrameEx(pFrame, "/tmp", "cursor-dst");
342#endif
343
344 return VINF_SUCCESS;
345}
346
347/**
348 * Simple blitting function for raw image data.
349 *
350 * @returns VBox status code.
351 * @param pDstFrame Destination frame.
352 * @param uDstX X destination (in pixel) within destination frame.
353 * @param uDstY Y destination (in pixel) within destination frame.
354 * @param pu8Src Source data to blit. Must be in the same pixel format as \a pFrame.
355 * @param cbSrc Size (in bytes) of \a pu8Src.
356 * @param uSrcX X start (in pixel) within source data.
357 * @param uSrcY Y start (in pixel) within source data.
358 * @param uSrcWidth Width (in pixel) to blit from source data.
359 * @param uSrcHeight Height (in pixel) to blit from data.
360 * @param uSrcBytesPerLine Bytes per line in source data.
361 * @param uSrcBPP BPP of source data. Must match \a pFrame.
362 * @param enmFmt Pixel format of source data. Must match \a pFrame.
363 */
364int RecordingVideoFrameBlitRaw(PRECORDINGVIDEOFRAME pDstFrame, uint32_t uDstX, uint32_t uDstY,
365 const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight,
366 uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmFmt)
367{
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);
373}
374
375/**
376 * Simple blitting function for raw image data with alpha channel.
377 *
378 * @returns VBox status code.
379 * @param pFrame Destination frame.
380 * @param uDstX X destination (in pixel) within destination frame.
381 * @param uDstY Y destination (in pixel) within destination frame.
382 * @param pu8Src Source data to blit. Must be in the same pixel format as \a pFrame.
383 * @param cbSrc Size (in bytes) of \a pu8Src.
384 * @param uSrcX X start (in pixel) within source data.
385 * @param uSrcY Y start (in pixel) within source data.
386 * @param uSrcWidth Width (in pixel) to blit from source data.
387 * @param uSrcHeight Height (in pixel) to blit from data.
388 * @param uSrcBytesPerLine Bytes per line in source data.
389 * @param uSrcBPP BPP of source data. Must match \a pFrame.
390 * @param enmFmt Pixel format of source data. Must match \a pFrame.
391 */
392int RecordingVideoFrameBlitRawAlpha(PRECORDINGVIDEOFRAME pFrame, uint32_t uDstX, uint32_t uDstY,
393 const uint8_t *pu8Src, size_t cbSrc, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight,
394 uint32_t uSrcBytesPerLine, uint8_t uSrcBPP, RECORDINGPIXELFMT enmFmt)
395{
396 return recordingVideoFrameBlitRawAlpha(pFrame, uDstX, uDstY,
397 pu8Src, cbSrc, uSrcX, uSrcY, uSrcWidth, uSrcHeight, uSrcBytesPerLine, uSrcBPP, enmFmt);
398}
399
400/**
401 * Simple blitting function for video frames.
402 *
403 * @returns VBox status code.
404 * @param pDstFrame Destination frame.
405 * @param uDstX X destination (in pixel) within destination frame.
406 * @param uDstY Y destination (in pixel) within destination frame.
407 * @param pSrcFrame Source frame.
408 * @param uSrcX X start (in pixel) within source frame.
409 * @param uSrcY Y start (in pixel) within source frame.
410 * @param uSrcWidth Width (in pixel) to blit from source frame.
411 * @param uSrcHeight Height (in pixel) to blit from frame.
412 *
413 * @note Does NOT check for limits, so use with care!
414 */
415int RecordingVideoFrameBlitFrame(PRECORDINGVIDEOFRAME pDstFrame, uint32_t uDstX, uint32_t uDstY,
416 PRECORDINGVIDEOFRAME pSrcFrame, uint32_t uSrcX, uint32_t uSrcY, uint32_t uSrcWidth, uint32_t uSrcHeight)
417{
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);
424}
425
426#ifdef VBOX_WITH_AUDIO_RECORDING
427/**
428 * Destroys a recording audio frame.
429 *
430 * @param pFrame Pointer to audio frame to destroy.
431 */
432DECLINLINE(void) recordingAudioFrameDestroy(PRECORDINGAUDIOFRAME pFrame)
433{
434 if (!pFrame)
435 return;
436
437 if (pFrame->pvBuf)
438 {
439 Assert(pFrame->cbBuf);
440 RTMemFree(pFrame->pvBuf);
441 pFrame->pvBuf = NULL;
442 pFrame->cbBuf = 0;
443 }
444}
445
446/**
447 * Frees a previously allocated recording audio frame.
448 *
449 * @param pFrame Audio frame to free. The pointer will be invalid after return.
450 */
451void RecordingAudioFrameFree(PRECORDINGAUDIOFRAME pFrame)
452{
453 if (!pFrame)
454 return;
455
456 recordingAudioFrameDestroy(pFrame);
457
458 RTMemFree(pFrame);
459 pFrame = NULL;
460}
461#endif /* VBOX_WITH_AUDIO_RECORDING */
462
463/**
464 * Frees a recording frame.
465 *
466 * @param pFrame Pointer to recording frame to free.
467 * The pointer will be invalid after return.
468 */
469void RecordingFrameFree(PRECORDINGFRAME pFrame)
470{
471 if (!pFrame)
472 return;
473
474 switch (pFrame->enmType)
475 {
476#ifdef VBOX_WITH_AUDIO_RECORDING
477 case RECORDINGFRAME_TYPE_AUDIO:
478 recordingAudioFrameDestroy(&pFrame->u.Audio);
479 break;
480#endif
481 case RECORDINGFRAME_TYPE_VIDEO:
482 RecordingVideoFrameDestroy(&pFrame->u.Video);
483 break;
484
485 case RECORDINGFRAME_TYPE_CURSOR_SHAPE:
486 RecordingVideoFrameDestroy(&pFrame->u.CursorShape);
487 break;
488
489 default:
490 /* Nothing to do here. */
491 break;
492 }
493
494 RTMemFree(pFrame);
495 pFrame = NULL;
496}
497
Note: See TracBrowser for help on using the repository browser.

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