VirtualBox

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

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

Main/VPX: 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.5 KB
Line 
1/* $Id: VideoRec.cpp 45922 2013-05-06 19:11:54Z 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 rc = videoRecEncodeAndWrite(pVideoRecCtx);
408 if (RT_FAILURE(rc))
409 LogRel(("Error %Rrc encoding video frame\n", rc));
410 }
411 }
412
413 ASMAtomicWriteU32(&pVideoRecCtx->u32State, VIDREC_TERMINATED);
414 RTThreadUserSignal(ThreadSelf);
415 return VINF_SUCCESS;
416}
417
418/**
419 * VideoRec utility function to initialize video recording context.
420 *
421 * @returns IPRT status code.
422 * @param pVideoRecCtx Pointer to video recording context to initialize Framebuffer width.
423 * @param strFile File to save the recorded data
424 * @param uTargetWidth Width of the target image in the video recoriding file (movie)
425 * @param uTargetHeight Height of the target image in video recording file.
426 */
427int VideoRecContextInit(PVIDEORECCONTEXT pVideoRecCtx, com::Bstr strFile,
428 uint32_t uWidth, uint32_t uHeight, uint32_t uRate)
429{
430 pVideoRecCtx->uTargetWidth = uWidth;
431 pVideoRecCtx->uTargetHeight = uHeight;
432 pVideoRecCtx->pu8RgbBuf = (uint8_t *)RTMemAllocZ(uWidth * uHeight * 4);
433 AssertReturn(pVideoRecCtx->pu8RgbBuf, VERR_NO_MEMORY);
434
435 int rc = RTFileOpen(&pVideoRecCtx->ebml.file,
436 com::Utf8Str(strFile).c_str(),
437 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
438 if (RT_FAILURE(rc))
439 {
440 LogFlow(("Failed to open the output File \n"));
441 return VERR_GENERAL_FAILURE;
442 }
443
444 vpx_codec_err_t rcv = vpx_codec_enc_config_default(DEFAULTCODEC, &pVideoRecCtx->VpxConfig, 0);
445 if (rcv != VPX_CODEC_OK)
446 {
447 LogFlow(("Failed to configure codec \n", vpx_codec_err_to_string(rcv)));
448 return VERR_GENERAL_FAILURE;
449 }
450
451 /* target bitrate in kilobits per second */
452 pVideoRecCtx->VpxConfig.rc_target_bitrate = uRate;
453 /* frame width */
454 pVideoRecCtx->VpxConfig.g_w = uWidth;
455 /* frame height */
456 pVideoRecCtx->VpxConfig.g_h = uHeight;
457 /* 1ms per frame */
458 pVideoRecCtx->VpxConfig.g_timebase.num = 1;
459 pVideoRecCtx->VpxConfig.g_timebase.den = 1000;
460 /* disable multithreading */
461 pVideoRecCtx->VpxConfig.g_threads = 0;
462
463 struct vpx_rational arg_framerate = {30, 1};
464 rc = Ebml_WriteWebMFileHeader(&pVideoRecCtx->ebml, &pVideoRecCtx->VpxConfig, &arg_framerate);
465 AssertRCReturn(rc, rc);
466
467 /* Initialize codec */
468 rcv = vpx_codec_enc_init(&pVideoRecCtx->VpxCodec, DEFAULTCODEC,
469 &pVideoRecCtx->VpxConfig, 0);
470 if (rcv != VPX_CODEC_OK)
471 {
472 LogFlow(("Failed to initialize encoder %s", vpx_codec_err_to_string(rcv)));
473 return VERR_GENERAL_FAILURE;
474 }
475
476 ASMAtomicWriteU32(&pVideoRecCtx->u32State, VIDREC_INITIALIZED);
477
478 if (!vpx_img_alloc(&pVideoRecCtx->VpxRawImage, VPX_IMG_FMT_I420, uWidth, uHeight, 1))
479 {
480 LogFlow(("Failed to allocate image %dx%d", uWidth, uHeight));
481 return VERR_NO_MEMORY;
482 }
483 pVideoRecCtx->pu8YuvBuf = pVideoRecCtx->VpxRawImage.planes[0];
484
485 int vrc = RTSemEventCreate(&pVideoRecCtx->WaitEvent);
486 AssertRCReturn(vrc, vrc);
487
488 vrc = RTThreadCreate(&pVideoRecCtx->Thread, VideoRecThread,
489 (void*)pVideoRecCtx, 0,
490 RTTHREADTYPE_MAIN_WORKER, 0, "VideoRec");
491 AssertRCReturn(vrc, vrc);
492
493 pVideoRecCtx->fEnabled = true;
494 return VINF_SUCCESS;
495}
496
497/**
498 * VideoRec utility function to close the video recording context.
499 *
500 * @param pVideoRecCtx Pointer to video recording context.
501 */
502void VideoRecContextClose(PVIDEORECCONTEXT pVideoRecCtx)
503{
504 if (ASMAtomicReadU32(&pVideoRecCtx->u32State) == VIDREC_UNINITIALIZED)
505 return;
506
507 if (pVideoRecCtx->ebml.file != NIL_RTFILE)
508 {
509 int rc = Ebml_WriteWebMFileFooter(&pVideoRecCtx->ebml, 0);
510 AssertRC(rc);
511 RTFileClose(pVideoRecCtx->ebml.file);
512 pVideoRecCtx->ebml.file = NIL_RTFILE;
513 }
514 if (pVideoRecCtx->ebml.cue_list)
515 {
516 RTMemFree(pVideoRecCtx->ebml.cue_list);
517 pVideoRecCtx->ebml.cue_list = NULL;
518 }
519 if (pVideoRecCtx->fEnabled)
520 {
521 ASMAtomicWriteU32(&pVideoRecCtx->u32State, VIDREC_TERMINATING);
522 RTSemEventSignal(pVideoRecCtx->WaitEvent);
523 RTThreadUserWait(pVideoRecCtx->Thread, 10000);
524 RTSemEventDestroy(pVideoRecCtx->WaitEvent);
525 vpx_img_free(&pVideoRecCtx->VpxRawImage);
526 vpx_codec_destroy(&pVideoRecCtx->VpxCodec);
527 RTMemFree(pVideoRecCtx->pu8RgbBuf);
528 pVideoRecCtx->pu8RgbBuf = NULL;
529 }
530}
531
532/**
533 * VideoRec utility function to check if recording is enabled.
534 *
535 * @returns true if recording is enabled
536 * @param pVideoRecCtx Pointer to video recording context.
537 */
538bool VideoRecIsEnabled(PVIDEORECCONTEXT pVideoRecCtx)
539{
540 AssertPtr(pVideoRecCtx);
541 return pVideoRecCtx->fEnabled;
542}
543
544/**
545 * VideoRec utility function to encode the source image and write the encoded
546 * image to target file.
547 *
548 * @returns IPRT status code.
549 * @param pVideoRecCtx Pointer to video recording context.
550 * @param uSourceWidth Width of the source image.
551 * @param uSourceHeight Height of the source image.
552 */
553static int videoRecEncodeAndWrite(PVIDEORECCONTEXT pVideoRecCtx)
554{
555 /* presentation time stamp */
556 vpx_codec_pts_t pts = pVideoRecCtx->u64TimeStamp;
557 vpx_codec_err_t rcv = vpx_codec_encode(&pVideoRecCtx->VpxCodec,
558 &pVideoRecCtx->VpxRawImage,
559 pts /* time stamp */,
560 10 /* how long to show this frame */,
561 0 /* flags */,
562 VPX_DL_REALTIME /* deadline */);
563 if (rcv != VPX_CODEC_OK)
564 {
565 LogFlow(("Failed to encode:%s\n", vpx_codec_err_to_string(rcv)));
566 return VERR_GENERAL_FAILURE;
567 }
568
569 vpx_codec_iter_t iter = NULL;
570 int rc = VERR_NO_DATA;
571 for (;;)
572 {
573 const vpx_codec_cx_pkt_t *pkt = vpx_codec_get_cx_data(&pVideoRecCtx->VpxCodec, &iter);
574 if (!pkt)
575 break;
576 switch (pkt->kind)
577 {
578 case VPX_CODEC_CX_FRAME_PKT:
579 rc = Ebml_WriteWebMBlock(&pVideoRecCtx->ebml, &pVideoRecCtx->VpxConfig, pkt);
580 break;
581 default:
582 LogFlow(("Unexpected CODEC Packet.\n"));
583 break;
584 }
585 }
586
587 pVideoRecCtx->cFrame++;
588 return rc;
589}
590
591/**
592 * VideoRec utility function to convert RGB to YUV.
593 *
594 * @returns IPRT status code.
595 * @param pVideoRecCtx Pointer to video recording context.
596 */
597static int videoRecRGBToYUV(PVIDEORECCONTEXT pVideoRecCtx)
598{
599 switch (pVideoRecCtx->u32PixelFormat)
600 {
601 case VPX_IMG_FMT_RGB32:
602 LogFlow(("32 bit\n"));
603 if (!colorConvWriteYUV420p<ColorConvBGRA32Iter>(pVideoRecCtx->uTargetWidth,
604 pVideoRecCtx->uTargetHeight,
605 pVideoRecCtx->pu8YuvBuf,
606 pVideoRecCtx->pu8RgbBuf))
607 return VERR_GENERAL_FAILURE;
608 break;
609 case VPX_IMG_FMT_RGB24:
610 LogFlow(("24 bit\n"));
611 if (!colorConvWriteYUV420p<ColorConvBGR24Iter>(pVideoRecCtx->uTargetWidth,
612 pVideoRecCtx->uTargetHeight,
613 pVideoRecCtx->pu8YuvBuf,
614 pVideoRecCtx->pu8RgbBuf))
615 return VERR_GENERAL_FAILURE;
616 break;
617 case VPX_IMG_FMT_RGB565:
618 LogFlow(("565 bit\n"));
619 if (!colorConvWriteYUV420p<ColorConvBGR565Iter>(pVideoRecCtx->uTargetWidth,
620 pVideoRecCtx->uTargetHeight,
621 pVideoRecCtx->pu8YuvBuf,
622 pVideoRecCtx->pu8RgbBuf))
623 return VERR_GENERAL_FAILURE;
624 break;
625 default:
626 return VERR_GENERAL_FAILURE;
627 }
628 return VINF_SUCCESS;
629}
630
631/**
632 * VideoRec utility function to copy source image (FrameBuf) to
633 * intermediate RGB buffer.
634 *
635 * @returns IPRT status code.
636 * @param pVideoRecCtx Pointer to video recording context.
637 * @param x Starting x coordinate of the source buffer (Framebuffer).
638 * @param y Starting y coordinate of the source buffer (Framebuffer).
639 * @param uPixelFormat Pixel Format.
640 * @param uBitsPerPixel Bits Per Pixel
641 * @param uBytesPerLine Bytes per source scanlineName.
642 * @param uSourceWidth Width of the source image (framebuffer).
643 * @param uSourceHeight Height of the source image (framebuffer).
644 * @param pu8BufAddr Pointer to source image(framebuffer).
645 * @param u64TimeStamp Time stamp.
646 */
647int VideoRecCopyToIntBuf(PVIDEORECCONTEXT pVideoRecCtx, uint32_t x, uint32_t y,
648 uint32_t uPixelFormat, uint32_t uBitsPerPixel, uint32_t uBytesPerLine,
649 uint32_t uSourceWidth, uint32_t uSourceHeight, uint8_t *pu8BufAddr,
650 uint64_t u64TimeStamp)
651{
652 AssertPtrReturn(pu8BufAddr, VERR_INVALID_PARAMETER);
653 AssertReturn(uSourceWidth, VERR_INVALID_PARAMETER);
654 AssertReturn(uSourceHeight, VERR_INVALID_PARAMETER);
655
656 if (ASMAtomicReadBool(&pVideoRecCtx->fRgbFilled))
657 return VERR_TRY_AGAIN;
658
659 int xDiff = ((int)pVideoRecCtx->uTargetWidth - (int)uSourceWidth) / 2;
660 uint32_t w = uSourceWidth;
661 if ((int)w + xDiff + (int)x <= 0) /* nothing visible */
662 return VERR_INVALID_PARAMETER;
663
664 uint32_t destX;
665 if ((int)x < -xDiff)
666 {
667 w += xDiff + x;
668 x = -xDiff;
669 destX = 0;
670 }
671 else
672 destX = x + xDiff;
673
674 uint32_t h = uSourceHeight;
675 int yDiff = ((int)pVideoRecCtx->uTargetHeight - (int)uSourceHeight) / 2;
676 if ((int)h + yDiff + (int)y <= 0) /* nothing visible */
677 return VERR_INVALID_PARAMETER;
678
679 uint32_t destY;
680 if ((int)y < -yDiff)
681 {
682 h += yDiff + (int)y;
683 y = -yDiff;
684 destY = 0;
685 }
686 else
687 destY = y + yDiff;
688
689 if ( destX > pVideoRecCtx->uTargetWidth
690 || destY > pVideoRecCtx->uTargetHeight)
691 return VERR_INVALID_PARAMETER; /* nothing visible */
692
693 if (destX + w > pVideoRecCtx->uTargetWidth)
694 w = pVideoRecCtx->uTargetWidth - destX;
695
696 if (destY + h > pVideoRecCtx->uTargetHeight)
697 h = pVideoRecCtx->uTargetHeight - destY;
698
699 /* Calculate bytes per pixel */
700 uint32_t bpp = 1;
701 if (uPixelFormat == FramebufferPixelFormat_FOURCC_RGB)
702 {
703 switch (uBitsPerPixel)
704 {
705 case 32:
706 pVideoRecCtx->u32PixelFormat = VPX_IMG_FMT_RGB32;
707 bpp = 4;
708 break;
709 case 24:
710 pVideoRecCtx->u32PixelFormat = VPX_IMG_FMT_RGB24;
711 bpp = 3;
712 break;
713 case 16:
714 pVideoRecCtx->u32PixelFormat = VPX_IMG_FMT_RGB565;
715 bpp = 2;
716 break;
717 default:
718 AssertMsgFailed(("Unknown color depth! mBitsPerPixel=%d\n", uBitsPerPixel));
719 break;
720 }
721 }
722 else
723 AssertMsgFailed(("Unknown pixel format! mPixelFormat=%d\n", uPixelFormat));
724
725 /* One of the dimensions of the current frame is smaller than before so
726 * clear the entire buffer to prevent artifacts from the previous frame */
727 if ( uSourceWidth < pVideoRecCtx->uLastSourceWidth
728 || uSourceHeight < pVideoRecCtx->uLastSourceHeight)
729 {
730 memset(pVideoRecCtx->pu8RgbBuf, 0,
731 pVideoRecCtx->uTargetWidth * pVideoRecCtx->uTargetHeight * 4);
732 }
733 pVideoRecCtx->uLastSourceWidth = uSourceWidth;
734 pVideoRecCtx->uLastSourceHeight = uSourceHeight;
735
736 /* Calculate start offset in source and destination buffers */
737 uint32_t offSrc = y * uBytesPerLine + x * bpp;
738 uint32_t offDst = (destY * pVideoRecCtx->uTargetWidth + destX) * bpp;
739 /* do the copy */
740 for (unsigned int i = 0; i < h; i++)
741 {
742 /* Overflow check */
743 Assert(offSrc + w * bpp <= uSourceHeight * uBytesPerLine);
744 Assert(offDst + w * bpp <= pVideoRecCtx->uTargetHeight * pVideoRecCtx->uTargetWidth * bpp);
745 memcpy(pVideoRecCtx->pu8RgbBuf + offDst, pu8BufAddr + offSrc, w * bpp);
746 offSrc += uBytesPerLine;
747 offDst += pVideoRecCtx->uTargetWidth * bpp;
748 }
749
750 pVideoRecCtx->u64TimeStamp = u64TimeStamp;
751
752 ASMAtomicWriteBool(&pVideoRecCtx->fRgbFilled, true);
753 RTSemEventSignal(pVideoRecCtx->WaitEvent);
754
755 return VINF_SUCCESS;
756}
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