VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/VideoRec.cpp@ 45878

Last change on this file since 45878 was 45878, checked in by vboxsync, 12 years ago

VPX: separate encoding thread; more cleanup

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
  • Property svn:mergeinfo set to (toggle deleted branches)
    /branches/VBox-3.0/src/VBox/Frontends/VBoxHeadless/VideoCapture/EncodeAndWrite.cpp58652,​70973
    /branches/VBox-3.2/src/VBox/Frontends/VBoxHeadless/VideoCapture/EncodeAndWrite.cpp66309,​66318
    /branches/VBox-4.0/src/VBox/Frontends/VBoxHeadless/VideoCapture/EncodeAndWrite.cpp70873
    /branches/VBox-4.1/src/VBox/Frontends/VBoxHeadless/VideoCapture/EncodeAndWrite.cpp74233
    /branches/dsen/gui/src/VBox/Frontends/VBoxHeadless/VideoCapture/EncodeAndWrite.cpp79076-79078,​79089,​79109-79110,​79112-79113,​79127-79130,​79134,​79141,​79151,​79155,​79157-79159,​79193,​79197
    /branches/dsen/gui2/src/VBox/Frontends/VBoxHeadless/VideoCapture/EncodeAndWrite.cpp79224,​79228,​79233,​79235,​79258,​79262-79263,​79273,​79341,​79345,​79354,​79357,​79387-79388,​79559-79569,​79572-79573,​79578,​79581-79582,​79590-79591,​79598-79599,​79602-79603,​79605-79606,​79632,​79635,​79637,​79644
    /branches/dsen/gui3/src/VBox/Frontends/VBoxHeadless/VideoCapture/EncodeAndWrite.cpp79645-79692
File size: 24.1 KB
Line 
1/* $Id: VideoRec.cpp 45878 2013-05-02 14:04:57Z vboxsync $ */
2/** @file
3 * Encodes the screen content in VPX format.
4 */
5
6/*
7 * Copyright (C) 2012-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_MAIN
19#include <VBox/log.h>
20#include <iprt/asm.h>
21#include <iprt/assert.h>
22#include <iprt/semaphore.h>
23#include <iprt/thread.h>
24
25#include <VBox/com/VirtualBox.h>
26#include <VBox/com/com.h>
27#include <VBox/com/string.h>
28
29#include "EbmlWriter.h"
30#include "VideoRec.h"
31
32#define VPX_CODEC_DISABLE_COMPAT 1
33#include <vpx/vp8cx.h>
34#include <vpx/vpx_image.h>
35
36/** Default VPX codec to use */
37#define DEFAULTCODEC (vpx_codec_vp8_cx())
38
39static int videoRecEncodeAndWrite(PVIDEORECCONTEXT pVideoRecCtx);
40static int videoRecRGBToYUV(PVIDEORECCONTEXT pVideoRecCtx);
41
42/* RGB buffer */
43enum
44{
45 /* RGB buffer empty */
46 VIDREC_RGB_EMPTY = 0,
47 /* RGB buffer filled */
48 VIDREC_RGB_FILLED
49};
50
51/* encoding */
52enum
53{
54 VIDREC_UNINITIALIZED = 0,
55 /* initialized */
56 VIDREC_INITIALIZED = 1,
57 /* signal that we are terminating */
58 VIDREC_TERMINATING = 2,
59 /* confirmation that the worker thread terminated */
60 VIDREC_TERMINATED = 3
61};
62
63typedef struct VIDEORECCONTEXT
64{
65 /* container context */
66 EbmlGlobal ebml;
67 /* VPX codec context */
68 vpx_codec_ctx_t VpxCodec;
69 /* VPX configuration */
70 vpx_codec_enc_cfg_t VpxConfig;
71 /* X resolution */
72 uint32_t uTargetWidth;
73 /* Y resolution */
74 uint32_t uTargetHeight;
75 /* X resolution of the last encoded picture */
76 uint32_t uLastSourceWidth;
77 /* Y resolution of the last encoded picture */
78 uint32_t uLastSourceHeight;
79 /* current frame number */
80 uint32_t cFrame;
81 /* RGB buffer containing the most recent frame of the framebuffer */
82 uint8_t *pu8RgbBuf;
83 /* YUV buffer the encode function fetches the frame from */
84 uint8_t *pu8YuvBuf;
85 /* VPX image context */
86 vpx_image_t VpxRawImage;
87 /* semaphore */
88 RTSEMEVENT WaitEvent;
89 /* true if video recording is enabled */
90 bool fEnabled;
91 /* worker thread */
92 RTTHREAD Thread;
93 /* see VIDREC_xxx */
94 uint32_t u32State;
95 /* true if the RGB buffer is filled */
96 bool fRgbFilled;
97 /* pixel format of the current frame */
98 uint32_t u32PixelFormat;
99 /* time stamp of the current frame */
100 uint64_t u64TimeStamp;
101} VIDEORECCONTEXT;
102
103
104/**
105 * Iterator class for running through a BGRA32 image buffer and converting
106 * it to RGB.
107 */
108class ColorConvBGRA32Iter
109{
110private:
111 enum { PIX_SIZE = 4 };
112public:
113 ColorConvBGRA32Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuf)
114 {
115 LogFlow(("width = %d height=%d aBuf=%lx\n", aWidth, aHeight, aBuf));
116 mPos = 0;
117 mSize = aWidth * aHeight * PIX_SIZE;
118 mBuf = aBuf;
119 }
120 /**
121 * Convert the next pixel to RGB.
122 * @returns true on success, false if we have reached the end of the buffer
123 * @param aRed where to store the red value
124 * @param aGreen where to store the green value
125 * @param aBlue where to store the blue value
126 */
127 bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue)
128 {
129 bool rc = false;
130 if (mPos + PIX_SIZE <= mSize)
131 {
132 *aRed = mBuf[mPos + 2];
133 *aGreen = mBuf[mPos + 1];
134 *aBlue = mBuf[mPos ];
135 mPos += PIX_SIZE;
136 rc = true;
137 }
138 return rc;
139 }
140
141 /**
142 * Skip forward by a certain number of pixels
143 * @param aPixels how many pixels to skip
144 */
145 void skip(unsigned aPixels)
146 {
147 mPos += PIX_SIZE * aPixels;
148 }
149private:
150 /** Size of the picture buffer */
151 unsigned mSize;
152 /** Current position in the picture buffer */
153 unsigned mPos;
154 /** Address of the picture buffer */
155 uint8_t *mBuf;
156};
157
158/**
159 * Iterator class for running through an BGR24 image buffer and converting
160 * it to RGB.
161 */
162class ColorConvBGR24Iter
163{
164private:
165 enum { PIX_SIZE = 3 };
166public:
167 ColorConvBGR24Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuf)
168 {
169 mPos = 0;
170 mSize = aWidth * aHeight * PIX_SIZE;
171 mBuf = aBuf;
172 }
173 /**
174 * Convert the next pixel to RGB.
175 * @returns true on success, false if we have reached the end of the buffer
176 * @param aRed where to store the red value
177 * @param aGreen where to store the green value
178 * @param aBlue where to store the blue value
179 */
180 bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue)
181 {
182 bool rc = false;
183 if (mPos + PIX_SIZE <= mSize)
184 {
185 *aRed = mBuf[mPos + 2];
186 *aGreen = mBuf[mPos + 1];
187 *aBlue = mBuf[mPos ];
188 mPos += PIX_SIZE;
189 rc = true;
190 }
191 return rc;
192 }
193
194 /**
195 * Skip forward by a certain number of pixels
196 * @param aPixels how many pixels to skip
197 */
198 void skip(unsigned aPixels)
199 {
200 mPos += PIX_SIZE * aPixels;
201 }
202private:
203 /** Size of the picture buffer */
204 unsigned mSize;
205 /** Current position in the picture buffer */
206 unsigned mPos;
207 /** Address of the picture buffer */
208 uint8_t *mBuf;
209};
210
211/**
212 * Iterator class for running through an BGR565 image buffer and converting
213 * it to RGB.
214 */
215class ColorConvBGR565Iter
216{
217private:
218 enum { PIX_SIZE = 2 };
219public:
220 ColorConvBGR565Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuf)
221 {
222 mPos = 0;
223 mSize = aWidth * aHeight * PIX_SIZE;
224 mBuf = aBuf;
225 }
226 /**
227 * Convert the next pixel to RGB.
228 * @returns true on success, false if we have reached the end of the buffer
229 * @param aRed where to store the red value
230 * @param aGreen where to store the green value
231 * @param aBlue where to store the blue value
232 */
233 bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue)
234 {
235 bool rc = false;
236 if (mPos + PIX_SIZE <= mSize)
237 {
238 unsigned uFull = (((unsigned) mBuf[mPos + 1]) << 8)
239 | ((unsigned) mBuf[mPos]);
240 *aRed = (uFull >> 8) & ~7;
241 *aGreen = (uFull >> 3) & ~3 & 0xff;
242 *aBlue = (uFull << 3) & ~7 & 0xff;
243 mPos += PIX_SIZE;
244 rc = true;
245 }
246 return rc;
247 }
248
249 /**
250 * Skip forward by a certain number of pixels
251 * @param aPixels how many pixels to skip
252 */
253 void skip(unsigned aPixels)
254 {
255 mPos += PIX_SIZE * aPixels;
256 }
257private:
258 /** Size of the picture buffer */
259 unsigned mSize;
260 /** Current position in the picture buffer */
261 unsigned mPos;
262 /** Address of the picture buffer */
263 uint8_t *mBuf;
264};
265
266/**
267 * Convert an image to YUV420p format
268 * @returns true on success, false on failure
269 * @param aWidth width of image
270 * @param aHeight height of image
271 * @param aDestBuf an allocated memory buffer large enough to hold the
272 * destination image (i.e. width * height * 12bits)
273 * @param aSrcBuf the source image as an array of bytes
274 */
275template <class T>
276inline bool colorConvWriteYUV420p(unsigned aWidth, unsigned aHeight,
277 uint8_t *aDestBuf, uint8_t *aSrcBuf)
278{
279 AssertReturn(0 == (aWidth & 1), false);
280 AssertReturn(0 == (aHeight & 1), false);
281 bool rc = true;
282 T iter1(aWidth, aHeight, aSrcBuf);
283 T iter2 = iter1;
284 iter2.skip(aWidth);
285 unsigned cPixels = aWidth * aHeight;
286 unsigned offY = 0;
287 unsigned offU = cPixels;
288 unsigned offV = cPixels + cPixels / 4;
289 for (unsigned i = 0; (i < aHeight / 2) && rc; ++i)
290 {
291 for (unsigned j = 0; (j < aWidth / 2) && rc; ++j)
292 {
293 unsigned red, green, blue, u, v;
294 rc = iter1.getRGB(&red, &green, &blue);
295 if (rc)
296 {
297 aDestBuf[offY] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
298 u = (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
299 v = (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
300 rc = iter1.getRGB(&red, &green, &blue);
301 }
302 if (rc)
303 {
304 aDestBuf[offY + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
305 u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
306 v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
307 rc = iter2.getRGB(&red, &green, &blue);
308 }
309 if (rc)
310 {
311 aDestBuf[offY + aWidth] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
312 u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
313 v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
314 rc = iter2.getRGB(&red, &green, &blue);
315 }
316 if (rc)
317 {
318 aDestBuf[offY + aWidth + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
319 u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
320 v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
321 aDestBuf[offU] = u;
322 aDestBuf[offV] = v;
323 offY += 2;
324 ++offU;
325 ++offV;
326 }
327 }
328 if (rc)
329 {
330 iter1.skip(aWidth);
331 iter2.skip(aWidth);
332 offY += aWidth;
333 }
334 }
335 return rc;
336}
337
338/**
339 * Convert an image to RGB24 format
340 * @returns true on success, false on failure
341 * @param aWidth width of image
342 * @param aHeight height of image
343 * @param aDestBuf an allocated memory buffer large enough to hold the
344 * destination image (i.e. width * height * 12bits)
345 * @param aSrcBuf the source image as an array of bytes
346 */
347template <class T>
348inline bool colorConvWriteRGB24(unsigned aWidth, unsigned aHeight,
349 uint8_t *aDestBuf, uint8_t *aSrcBuf)
350{
351 enum { PIX_SIZE = 3 };
352 bool rc = true;
353 AssertReturn(0 == (aWidth & 1), false);
354 AssertReturn(0 == (aHeight & 1), false);
355 T iter(aWidth, aHeight, aSrcBuf);
356 unsigned cPixels = aWidth * aHeight;
357 for (unsigned i = 0; i < cPixels && rc; ++i)
358 {
359 unsigned red, green, blue;
360 rc = iter.getRGB(&red, &green, &blue);
361 if (rc)
362 {
363 aDestBuf[i * PIX_SIZE ] = red;
364 aDestBuf[i * PIX_SIZE + 1] = green;
365 aDestBuf[i * PIX_SIZE + 2] = blue;
366 }
367 }
368 return rc;
369}
370
371/**
372 * VideoRec utility function to create video recording context.
373 *
374 * @returns IPRT status code.
375 * @param ppVideoRecCtx video recording context
376 */
377int VideoRecContextCreate(PVIDEORECCONTEXT *ppVideoRecCtx)
378{
379 PVIDEORECCONTEXT pVideoRecCtx = (PVIDEORECCONTEXT)RTMemAllocZ(sizeof(VIDEORECCONTEXT));
380 *ppVideoRecCtx = pVideoRecCtx;
381 AssertReturn(pVideoRecCtx, VERR_NO_MEMORY);
382
383 pVideoRecCtx->ebml.last_pts_ms = -1;
384 return VINF_SUCCESS;
385}
386
387/**
388 * Worker thread.
389 *
390 * RGB/YUV conversion and encoding.
391 */
392DECLCALLBACK(int) VideoRecThread(RTTHREAD ThreadSelf, void *pvUser)
393{
394 PVIDEORECCONTEXT pVideoRecCtx = (PVIDEORECCONTEXT)pvUser;
395 for (;;)
396 {
397 int rc = RTSemEventWait(pVideoRecCtx->WaitEvent, RT_INDEFINITE_WAIT);
398 AssertRCBreak(rc);
399
400 if (ASMAtomicReadU32(&pVideoRecCtx->u32State) == VIDREC_TERMINATING)
401 break;
402 else if (ASMAtomicReadBool(&pVideoRecCtx->fRgbFilled))
403 {
404 rc = videoRecRGBToYUV(pVideoRecCtx);
405 ASMAtomicWriteBool(&pVideoRecCtx->fRgbFilled, false);
406 if (RT_SUCCESS(rc))
407 videoRecEncodeAndWrite(pVideoRecCtx);
408 }
409 }
410
411 ASMAtomicWriteU32(&pVideoRecCtx->u32State, VIDREC_TERMINATED);
412 RTThreadUserSignal(ThreadSelf);
413 return VINF_SUCCESS;
414}
415
416/**
417 * VideoRec utility function to initialize video recording context.
418 *
419 * @returns IPRT status code.
420 * @param pVideoRecCtx Pointer to video recording context to initialize Framebuffer width.
421 * @param strFile File to save the recorded data
422 * @param uTargetWidth Width of the target image in the video recoriding file (movie)
423 * @param uTargetHeight Height of the target image in video recording file.
424 */
425int VideoRecContextInit(PVIDEORECCONTEXT pVideoRecCtx, com::Bstr strFile,
426 uint32_t uWidth, uint32_t uHeight, uint32_t uRate)
427{
428 pVideoRecCtx->uTargetWidth = uWidth;
429 pVideoRecCtx->uTargetHeight = uHeight;
430 pVideoRecCtx->pu8RgbBuf = (uint8_t *)RTMemAlloc(uWidth * uHeight * 4);
431 AssertReturn(pVideoRecCtx->pu8RgbBuf, VERR_NO_MEMORY);
432
433 pVideoRecCtx->ebml.stream = fopen(com::Utf8Str(strFile).c_str(), "wb");
434 if (!pVideoRecCtx->ebml.stream)
435 {
436 LogFlow(("Failed to open the output File \n"));
437 return VERR_GENERAL_FAILURE;
438 }
439
440 vpx_codec_err_t rcVpx = vpx_codec_enc_config_default(DEFAULTCODEC, &pVideoRecCtx->VpxConfig, 0);
441 if (rcVpx != VPX_CODEC_OK)
442 {
443 LogFlow(("Failed to configure codec \n", vpx_codec_err_to_string(rcVpx)));
444 return VERR_GENERAL_FAILURE;
445 }
446
447 /* target bitrate in kilobits per second */
448 pVideoRecCtx->VpxConfig.rc_target_bitrate = uRate;
449 /* frame width */
450 pVideoRecCtx->VpxConfig.g_w = uWidth;
451 /* frame height */
452 pVideoRecCtx->VpxConfig.g_h = uHeight;
453 /* 1ms per frame */
454 pVideoRecCtx->VpxConfig.g_timebase.num = 1;
455 pVideoRecCtx->VpxConfig.g_timebase.den = 1000;
456 /* disable multithreading */
457 pVideoRecCtx->VpxConfig.g_threads = 0;
458
459 struct vpx_rational arg_framerate = {30, 1};
460 Ebml_WriteWebMFileHeader(&pVideoRecCtx->ebml, &pVideoRecCtx->VpxConfig, &arg_framerate);
461
462 /* Initialize codec */
463 rcVpx = vpx_codec_enc_init(&pVideoRecCtx->VpxCodec,
464 DEFAULTCODEC,
465 &pVideoRecCtx->VpxConfig,
466 0);
467 if (rcVpx != VPX_CODEC_OK)
468 {
469 LogFlow(("Failed to initialize encoder %s", vpx_codec_err_to_string(rcVpx)));
470 return VERR_GENERAL_FAILURE;
471 }
472
473 ASMAtomicWriteU32(&pVideoRecCtx->u32State, VIDREC_INITIALIZED);
474
475 if (!vpx_img_alloc(&pVideoRecCtx->VpxRawImage, VPX_IMG_FMT_I420, uWidth, uHeight, 1))
476 {
477 LogFlow(("Failed to allocate image %dx%d", uWidth, uHeight));
478 return VERR_NO_MEMORY;
479 }
480 pVideoRecCtx->pu8YuvBuf = pVideoRecCtx->VpxRawImage.planes[0];
481
482 int vrc = RTSemEventCreate(&pVideoRecCtx->WaitEvent);
483 AssertRCReturn(vrc, vrc);
484
485 vrc = RTThreadCreate(&pVideoRecCtx->Thread, VideoRecThread,
486 (void*)pVideoRecCtx, 0,
487 RTTHREADTYPE_MAIN_WORKER, 0, "VideoRec");
488 AssertRCReturn(vrc, vrc);
489
490 pVideoRecCtx->fEnabled = true;
491 return VINF_SUCCESS;
492}
493
494/**
495 * VideoRec utility function to close the video recording context.
496 *
497 * @param pVideoRecCtx Pointer to video recording context.
498 */
499void VideoRecContextClose(PVIDEORECCONTEXT pVideoRecCtx)
500{
501 if (ASMAtomicReadU32(&pVideoRecCtx->u32State) == VIDREC_UNINITIALIZED)
502 return;
503
504 if (pVideoRecCtx->ebml.stream)
505 {
506 Ebml_WriteWebMFileFooter(&pVideoRecCtx->ebml, 0);
507 fclose(pVideoRecCtx->ebml.stream);
508 }
509
510 if (pVideoRecCtx->fEnabled)
511 {
512 ASMAtomicWriteU32(&pVideoRecCtx->u32State, VIDREC_TERMINATING);
513 RTSemEventSignal(pVideoRecCtx->WaitEvent);
514 RTThreadUserWait(pVideoRecCtx->Thread, 10000);
515 RTSemEventDestroy(pVideoRecCtx->WaitEvent);
516 vpx_img_free(&pVideoRecCtx->VpxRawImage);
517 vpx_codec_destroy(&pVideoRecCtx->VpxCodec);
518 RTMemFree(pVideoRecCtx->pu8RgbBuf);
519 pVideoRecCtx->pu8RgbBuf = NULL;
520 }
521}
522
523/**
524 * VideoRec utility function to check if recording is enabled.
525 *
526 * @returns true if recording is enabled
527 * @param pVideoRecCtx Pointer to video recording context.
528 */
529bool VideoRecIsEnabled(PVIDEORECCONTEXT pVideoRecCtx)
530{
531 AssertPtr(pVideoRecCtx);
532 return pVideoRecCtx->fEnabled;
533}
534
535/**
536 * VideoRec utility function to encode the source image and write the encoded
537 * image to target file.
538 *
539 * @returns IPRT status code.
540 * @param pVideoRecCtx Pointer to video recording context.
541 * @param uSourceWidth Width of the source image.
542 * @param uSourceHeight Height of the source image.
543 */
544static int videoRecEncodeAndWrite(PVIDEORECCONTEXT pVideoRecCtx)
545{
546 /* presentation time stamp */
547 vpx_codec_pts_t pts = pVideoRecCtx->u64TimeStamp;
548 vpx_codec_err_t rcVpx = vpx_codec_encode(&pVideoRecCtx->VpxCodec,
549 &pVideoRecCtx->VpxRawImage,
550 pts /* time stamp */,
551 10 /* how long to show this frame */,
552 0 /* flags */,
553 VPX_DL_REALTIME /* deadline */);
554 if (rcVpx != VPX_CODEC_OK)
555 {
556 LogFlow(("Failed to encode:%s\n", vpx_codec_err_to_string(rcVpx)));
557 return VERR_GENERAL_FAILURE;
558 }
559
560 vpx_codec_iter_t iter = NULL;
561 for (;;)
562 {
563 const vpx_codec_cx_pkt_t *pkt = vpx_codec_get_cx_data(&pVideoRecCtx->VpxCodec, &iter);
564 if (!pkt)
565 return VERR_NO_DATA;
566 switch (pkt->kind)
567 {
568 case VPX_CODEC_CX_FRAME_PKT:
569 Ebml_WriteWebMBlock(&pVideoRecCtx->ebml, &pVideoRecCtx->VpxConfig, pkt);
570 break;
571 default:
572 LogFlow(("Unexpected CODEC Packet.\n"));
573 break;
574 }
575 }
576
577 pVideoRecCtx->cFrame++;
578 return VINF_SUCCESS;
579}
580
581/**
582 * VideoRec utility function to convert RGB to YUV.
583 *
584 * @returns IPRT status code.
585 * @param pVideoRecCtx Pointer to video recording context.
586 */
587static int videoRecRGBToYUV(PVIDEORECCONTEXT pVideoRecCtx)
588{
589 switch (pVideoRecCtx->u32PixelFormat)
590 {
591 case VPX_IMG_FMT_RGB32:
592 LogFlow(("32 bit\n"));
593 if (!colorConvWriteYUV420p<ColorConvBGRA32Iter>(pVideoRecCtx->uTargetWidth,
594 pVideoRecCtx->uTargetHeight,
595 pVideoRecCtx->pu8YuvBuf,
596 pVideoRecCtx->pu8RgbBuf))
597 return VERR_GENERAL_FAILURE;
598 break;
599 case VPX_IMG_FMT_RGB24:
600 LogFlow(("24 bit\n"));
601 if (!colorConvWriteYUV420p<ColorConvBGR24Iter>(pVideoRecCtx->uTargetWidth,
602 pVideoRecCtx->uTargetHeight,
603 pVideoRecCtx->pu8YuvBuf,
604 pVideoRecCtx->pu8RgbBuf))
605 return VERR_GENERAL_FAILURE;
606 break;
607 case VPX_IMG_FMT_RGB565:
608 LogFlow(("565 bit\n"));
609 if (!colorConvWriteYUV420p<ColorConvBGR565Iter>(pVideoRecCtx->uTargetWidth,
610 pVideoRecCtx->uTargetHeight,
611 pVideoRecCtx->pu8YuvBuf,
612 pVideoRecCtx->pu8RgbBuf))
613 return VERR_GENERAL_FAILURE;
614 break;
615 default:
616 return VERR_GENERAL_FAILURE;
617 }
618 return VINF_SUCCESS;
619}
620
621/**
622 * VideoRec utility function to copy source image (FrameBuf) to
623 * intermediate RGB buffer.
624 *
625 * @returns IPRT status code.
626 * @param pVideoRecCtx Pointer to video recording context.
627 * @param x Starting x coordinate of the source buffer (Framebuffer).
628 * @param y Starting y coordinate of the source buffer (Framebuffer).
629 * @param uPixelFormat Pixel Format.
630 * @param uBitsPerPixel Bits Per Pixel
631 * @param uBytesPerLine Bytes per source scanlineName.
632 * @param uSourceWidth Width of the source image (framebuffer).
633 * @param uSourceHeight Height of the source image (framebuffer).
634 * @param pu8BufAddr Pointer to source image(framebuffer).
635 * @param u64TimeStamp Time stamp.
636 */
637int VideoRecCopyToIntBuf(PVIDEORECCONTEXT pVideoRecCtx, uint32_t x, uint32_t y,
638 uint32_t uPixelFormat, uint32_t uBitsPerPixel, uint32_t uBytesPerLine,
639 uint32_t uSourceWidth, uint32_t uSourceHeight, uint8_t *pu8BufAddr,
640 uint64_t u64TimeStamp)
641{
642 AssertPtrReturn(pu8BufAddr, VERR_INVALID_PARAMETER);
643 AssertReturn(uSourceWidth, VERR_INVALID_PARAMETER);
644 AssertReturn(uSourceHeight, VERR_INVALID_PARAMETER);
645
646 if (ASMAtomicReadBool(&pVideoRecCtx->fRgbFilled))
647 return VERR_TRY_AGAIN;
648
649 int xDiff = ((int)pVideoRecCtx->uTargetWidth - (int)uSourceWidth) / 2;
650 uint32_t w = uSourceWidth;
651 if ((int)w + xDiff + (int)x <= 0) /* nothing visible */
652 return VERR_INVALID_PARAMETER;
653
654 uint32_t destX;
655 if ((int)x < -xDiff)
656 {
657 w += xDiff + x;
658 x = -xDiff;
659 destX = 0;
660 }
661 else
662 destX = x + xDiff;
663
664 uint32_t h = uSourceHeight;
665 int yDiff = ((int)pVideoRecCtx->uTargetHeight - (int)uSourceHeight) / 2;
666 if ((int)h + yDiff + (int)y <= 0) /* nothing visible */
667 return VERR_INVALID_PARAMETER;
668
669 uint32_t destY;
670 if ((int)y < -yDiff)
671 {
672 h += yDiff + (int)y;
673 y = -yDiff;
674 destY = 0;
675 }
676 else
677 destY = y + yDiff;
678
679 if ( destX > pVideoRecCtx->uTargetWidth
680 || destY > pVideoRecCtx->uTargetHeight)
681 return VERR_INVALID_PARAMETER; /* nothing visible */
682
683 if (destX + w > pVideoRecCtx->uTargetWidth)
684 w = pVideoRecCtx->uTargetWidth - destX;
685
686 if (destY + h > pVideoRecCtx->uTargetHeight)
687 h = pVideoRecCtx->uTargetHeight - destY;
688
689 /* Calculate bytes per pixel */
690 uint32_t bpp = 1;
691 if (uPixelFormat == FramebufferPixelFormat_FOURCC_RGB)
692 {
693 switch (uBitsPerPixel)
694 {
695 case 32:
696 pVideoRecCtx->u32PixelFormat = VPX_IMG_FMT_RGB32;
697 bpp = 4;
698 break;
699 case 24:
700 pVideoRecCtx->u32PixelFormat = VPX_IMG_FMT_RGB24;
701 bpp = 3;
702 break;
703 case 16:
704 pVideoRecCtx->u32PixelFormat = VPX_IMG_FMT_RGB565;
705 bpp = 2;
706 break;
707 default:
708 AssertMsgFailed(("Unknown color depth! mBitsPerPixel=%d\n", uBitsPerPixel));
709 break;
710 }
711 }
712 else
713 AssertMsgFailed(("Unknown pixel format! mPixelFormat=%d\n", uPixelFormat));
714
715 /* One of the dimensions of the current frame is smaller than before so
716 * clear the entire buffer to prevent artifacts from the previous frame */
717 if ( pVideoRecCtx->uLastSourceWidth < uSourceWidth
718 || pVideoRecCtx->uLastSourceHeight < uSourceHeight)
719 {
720 memset(pVideoRecCtx->pu8RgbBuf, 0,
721 pVideoRecCtx->uTargetWidth * pVideoRecCtx->uTargetHeight * 4);
722 }
723 pVideoRecCtx->uLastSourceWidth = uSourceWidth;
724 pVideoRecCtx->uLastSourceHeight = uSourceHeight;
725
726 /* Calculate start offset in source and destination buffers */
727 uint32_t offSrc = y * uBytesPerLine + x * bpp;
728 uint32_t offDst = (destY * pVideoRecCtx->uTargetWidth + destX) * bpp;
729 /* do the copy */
730 for (unsigned int i = 0; i < h; i++)
731 {
732 /* Overflow check */
733 Assert(offSrc + w * bpp <= uSourceHeight * uBytesPerLine);
734 Assert(offDst + w * bpp <= pVideoRecCtx->uTargetHeight * pVideoRecCtx->uTargetWidth * bpp);
735 memcpy(pVideoRecCtx->pu8RgbBuf + offDst, pu8BufAddr + offSrc, w * bpp);
736 offSrc += uBytesPerLine;
737 offDst += pVideoRecCtx->uTargetWidth * bpp;
738 }
739
740 pVideoRecCtx->u64TimeStamp = u64TimeStamp;
741
742 ASMAtomicWriteBool(&pVideoRecCtx->fRgbFilled, true);
743 RTSemEventSignal(pVideoRecCtx->WaitEvent);
744
745 return VINF_SUCCESS;
746}
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