1 | /* $Id: VideoRecUtils.cpp 74999 2018-10-23 13:50:28Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * Video recording utility code.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2012-2018 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 | #include "VideoRec.h"
|
---|
19 | #include "VideoRecUtils.h"
|
---|
20 |
|
---|
21 | #include <iprt/asm.h>
|
---|
22 | #include <iprt/assert.h>
|
---|
23 | #include <iprt/critsect.h>
|
---|
24 | #include <iprt/path.h>
|
---|
25 | #include <iprt/semaphore.h>
|
---|
26 | #include <iprt/thread.h>
|
---|
27 | #include <iprt/time.h>
|
---|
28 |
|
---|
29 |
|
---|
30 | /**
|
---|
31 | * Convert an image to YUV420p format.
|
---|
32 | *
|
---|
33 | * @return true on success, false on failure.
|
---|
34 | * @param aDstBuf The destination image buffer.
|
---|
35 | * @param aDstWidth Width (in pixel) of destination buffer.
|
---|
36 | * @param aDstHeight Height (in pixel) of destination buffer.
|
---|
37 | * @param aSrcBuf The source image buffer.
|
---|
38 | * @param aSrcWidth Width (in pixel) of source buffer.
|
---|
39 | * @param aSrcHeight Height (in pixel) of source buffer.
|
---|
40 | */
|
---|
41 | template <class T>
|
---|
42 | inline bool videoRecColorConvWriteYUV420p(uint8_t *aDstBuf, unsigned aDstWidth, unsigned aDstHeight,
|
---|
43 | uint8_t *aSrcBuf, unsigned aSrcWidth, unsigned aSrcHeight)
|
---|
44 | {
|
---|
45 | RT_NOREF(aDstWidth, aDstHeight);
|
---|
46 |
|
---|
47 | AssertReturn(!(aSrcWidth & 1), false);
|
---|
48 | AssertReturn(!(aSrcHeight & 1), false);
|
---|
49 |
|
---|
50 | bool fRc = true;
|
---|
51 | T iter1(aSrcWidth, aSrcHeight, aSrcBuf);
|
---|
52 | T iter2 = iter1;
|
---|
53 | iter2.skip(aSrcWidth);
|
---|
54 | unsigned cPixels = aSrcWidth * aSrcHeight;
|
---|
55 | unsigned offY = 0;
|
---|
56 | unsigned offU = cPixels;
|
---|
57 | unsigned offV = cPixels + cPixels / 4;
|
---|
58 | unsigned const cyHalf = aSrcHeight / 2;
|
---|
59 | unsigned const cxHalf = aSrcWidth / 2;
|
---|
60 | for (unsigned i = 0; i < cyHalf && fRc; ++i)
|
---|
61 | {
|
---|
62 | for (unsigned j = 0; j < cxHalf; ++j)
|
---|
63 | {
|
---|
64 | unsigned red, green, blue;
|
---|
65 | fRc = iter1.getRGB(&red, &green, &blue);
|
---|
66 | AssertReturn(fRc, false);
|
---|
67 | aDstBuf[offY] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
|
---|
68 | unsigned u = (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
|
---|
69 | unsigned v = (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
|
---|
70 |
|
---|
71 | fRc = iter1.getRGB(&red, &green, &blue);
|
---|
72 | AssertReturn(fRc, false);
|
---|
73 | aDstBuf[offY + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
|
---|
74 | u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
|
---|
75 | v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
|
---|
76 |
|
---|
77 | fRc = iter2.getRGB(&red, &green, &blue);
|
---|
78 | AssertReturn(fRc, false);
|
---|
79 | aDstBuf[offY + aSrcWidth] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
|
---|
80 | u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
|
---|
81 | v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
|
---|
82 |
|
---|
83 | fRc = iter2.getRGB(&red, &green, &blue);
|
---|
84 | AssertReturn(fRc, false);
|
---|
85 | aDstBuf[offY + aSrcWidth + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
|
---|
86 | u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
|
---|
87 | v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
|
---|
88 |
|
---|
89 | aDstBuf[offU] = u;
|
---|
90 | aDstBuf[offV] = v;
|
---|
91 | offY += 2;
|
---|
92 | ++offU;
|
---|
93 | ++offV;
|
---|
94 | }
|
---|
95 |
|
---|
96 | iter1.skip(aSrcWidth);
|
---|
97 | iter2.skip(aSrcWidth);
|
---|
98 | offY += aSrcWidth;
|
---|
99 | }
|
---|
100 |
|
---|
101 | return true;
|
---|
102 | }
|
---|
103 |
|
---|
104 | /**
|
---|
105 | * Convert an image to RGB24 format
|
---|
106 | * @returns true on success, false on failure
|
---|
107 | * @param aWidth width of image
|
---|
108 | * @param aHeight height of image
|
---|
109 | * @param aDestBuf an allocated memory buffer large enough to hold the
|
---|
110 | * destination image (i.e. width * height * 12bits)
|
---|
111 | * @param aSrcBuf the source image as an array of bytes
|
---|
112 | */
|
---|
113 | template <class T>
|
---|
114 | inline bool videoRecColorConvWriteRGB24(unsigned aWidth, unsigned aHeight,
|
---|
115 | uint8_t *aDestBuf, uint8_t *aSrcBuf)
|
---|
116 | {
|
---|
117 | enum { PIX_SIZE = 3 };
|
---|
118 | bool rc = true;
|
---|
119 | AssertReturn(0 == (aWidth & 1), false);
|
---|
120 | AssertReturn(0 == (aHeight & 1), false);
|
---|
121 | T iter(aWidth, aHeight, aSrcBuf);
|
---|
122 | unsigned cPixels = aWidth * aHeight;
|
---|
123 | for (unsigned i = 0; i < cPixels && rc; ++i)
|
---|
124 | {
|
---|
125 | unsigned red, green, blue;
|
---|
126 | rc = iter.getRGB(&red, &green, &blue);
|
---|
127 | if (rc)
|
---|
128 | {
|
---|
129 | aDestBuf[i * PIX_SIZE ] = red;
|
---|
130 | aDestBuf[i * PIX_SIZE + 1] = green;
|
---|
131 | aDestBuf[i * PIX_SIZE + 2] = blue;
|
---|
132 | }
|
---|
133 | }
|
---|
134 | return rc;
|
---|
135 | }
|
---|
136 |
|
---|
137 | /**
|
---|
138 | * Converts a RGB to YUV buffer.
|
---|
139 | *
|
---|
140 | * @returns IPRT status code.
|
---|
141 | * @param uPixelFormat Pixel format to use for conversion.
|
---|
142 | * @param paDst Pointer to destination buffer.
|
---|
143 | * @param uDstWidth Width (X, in pixels) of destination buffer.
|
---|
144 | * @param uDstHeight Height (Y, in pixels) of destination buffer.
|
---|
145 | * @param paSrc Pointer to source buffer.
|
---|
146 | * @param uSrcWidth Width (X, in pixels) of source buffer.
|
---|
147 | * @param uSrcHeight Height (Y, in pixels) of source buffer.
|
---|
148 | */
|
---|
149 | int videoRecRGBToYUV(uint32_t uPixelFormat,
|
---|
150 | uint8_t *paDst, uint32_t uDstWidth, uint32_t uDstHeight,
|
---|
151 | uint8_t *paSrc, uint32_t uSrcWidth, uint32_t uSrcHeight)
|
---|
152 | {
|
---|
153 | switch (uPixelFormat)
|
---|
154 | {
|
---|
155 | case VIDEORECPIXELFMT_RGB32:
|
---|
156 | if (!videoRecColorConvWriteYUV420p<ColorConvBGRA32Iter>(paDst, uDstWidth, uDstHeight,
|
---|
157 | paSrc, uSrcWidth, uSrcHeight))
|
---|
158 | return VERR_INVALID_PARAMETER;
|
---|
159 | break;
|
---|
160 | case VIDEORECPIXELFMT_RGB24:
|
---|
161 | if (!videoRecColorConvWriteYUV420p<ColorConvBGR24Iter>(paDst, uDstWidth, uDstHeight,
|
---|
162 | paSrc, uSrcWidth, uSrcHeight))
|
---|
163 | return VERR_INVALID_PARAMETER;
|
---|
164 | break;
|
---|
165 | case VIDEORECPIXELFMT_RGB565:
|
---|
166 | if (!videoRecColorConvWriteYUV420p<ColorConvBGR565Iter>(paDst, uDstWidth, uDstHeight,
|
---|
167 | paSrc, uSrcWidth, uSrcHeight))
|
---|
168 | return VERR_INVALID_PARAMETER;
|
---|
169 | break;
|
---|
170 | default:
|
---|
171 | AssertFailed();
|
---|
172 | return VERR_NOT_SUPPORTED;
|
---|
173 | }
|
---|
174 | return VINF_SUCCESS;
|
---|
175 | }
|
---|
176 |
|
---|