VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxHeadless/VideoCapture/FFmpegFB.h@ 41203

Last change on this file since 41203 was 41203, checked in by vboxsync, 13 years ago

Frontends: forgotten change for FFmpegFB

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.3 KB
Line 
1/** @file
2 *
3 * VBox Remote Desktop Protocol.
4 * FFmpeg framebuffer interface.
5 */
6
7/*
8 * Copyright (C) 2006-2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#ifndef _H_FFMPEGFB
20#define _H_FFMPEGFB
21
22#include <VBox/com/VirtualBox.h>
23
24#include <iprt/uuid.h>
25
26#include <VBox/com/com.h>
27#include <VBox/com/string.h>
28
29#include <iprt/initterm.h>
30#include <iprt/critsect.h>
31
32#ifdef DEBUG
33# define VBOX_DEBUG_FF DEBUG
34# include <avcodec.h>
35# include <avformat.h>
36# undef DEBUG
37# define DEBUG VBOX_DEBUG_FF
38#else /* DEBUG not defined */
39# include <avcodec.h>
40# include <avformat.h>
41#endif /* DEBUG not defined */
42
43class FFmpegFB : VBOX_SCRIPTABLE_IMPL(IFramebuffer)
44{
45public:
46 FFmpegFB(ULONG width, ULONG height, ULONG bitrate, com::Bstr filename);
47 virtual ~FFmpegFB();
48
49#ifndef VBOX_WITH_XPCOM
50 STDMETHOD_(ULONG, AddRef)()
51 {
52 return ::InterlockedIncrement (&refcnt);
53 }
54 STDMETHOD_(ULONG, Release)()
55 {
56 long cnt = ::InterlockedDecrement (&refcnt);
57 if (cnt == 0)
58 delete this;
59 return cnt;
60 }
61#endif
62
63 BEGIN_COM_MAP(FFmpegFB)
64 VBOX_DEFAULT_INTERFACE_ENTRIES(IFramebuffer)
65 END_COM_MAP()
66
67 // public methods only for internal purposes
68 HRESULT init ();
69
70 STDMETHOD(COMGETTER(Width))(ULONG *width);
71 STDMETHOD(COMGETTER(Height))(ULONG *height);
72 STDMETHOD(Lock)();
73 STDMETHOD(Unlock)();
74 STDMETHOD(COMGETTER(Address))(BYTE **address);
75 STDMETHOD(COMGETTER(BitsPerPixel))(ULONG *bitsPerPixel);
76 STDMETHOD(COMGETTER(BytesPerLine))(ULONG *bytesPerLine);
77 STDMETHOD(COMGETTER(PixelFormat)) (ULONG *pixelFormat);
78 STDMETHOD(COMGETTER(UsesGuestVRAM)) (BOOL *usesGuestVRAM);
79 STDMETHOD(COMGETTER(HeightReduction)) (ULONG *heightReduction);
80 STDMETHOD(COMGETTER(Overlay)) (IFramebufferOverlay **aOverlay);
81 STDMETHOD(COMGETTER(WinId)) (LONG64 *winId);
82
83 STDMETHOD(NotifyUpdate)(ULONG x, ULONG y, ULONG w, ULONG h);
84 STDMETHOD(RequestResize)(ULONG aScreenId, ULONG pixelFormat, BYTE *vram,
85 ULONG bitsPerPixel, ULONG bytesPerLine,
86 ULONG w, ULONG h, BOOL *finished);
87 STDMETHOD(VideoModeSupported)(ULONG width, ULONG height, ULONG bpp, BOOL *supported);
88 STDMETHOD(GetVisibleRegion)(BYTE *rectangles, ULONG count, ULONG *countCopied);
89 STDMETHOD(SetVisibleRegion)(BYTE *rectangles, ULONG count);
90
91 STDMETHOD(ProcessVHWACommand)(BYTE *pCommand);
92
93private:
94 /** true if url_fopen actually succeeded */
95 bool mfUrlOpen;
96 /** Guest framebuffer width */
97 ULONG mGuestWidth;
98 /** Guest framebuffer height */
99 ULONG mGuestHeight;
100 /** Bit rate used for encoding */
101 ULONG mBitRate;
102 /** Guest framebuffer pixel format */
103 ULONG mPixelFormat;
104 /** Guest framebuffer color depth */
105 ULONG mBitsPerPixel;
106 /** Name of the file we will write to */
107 com::Bstr mFileName;
108 /** Guest framebuffer line length */
109 ULONG mBytesPerLine;
110 /** MPEG frame framebuffer width */
111 ULONG mFrameWidth;
112 /** MPEG frame framebuffer height */
113 ULONG mFrameHeight;
114 /** The size of one YUV frame */
115 ULONG mYUVFrameSize;
116 /** If we can't use the video RAM directly, we allocate our own
117 * buffer */
118 uint8_t *mRGBBuffer;
119 /** The address of the buffer - can be either mRGBBuffer or the
120 * guests VRAM (HC address) if we can handle that directly */
121 uint8_t *mBufferAddress;
122 /** An intermediary RGB buffer with the same dimensions */
123 uint8_t *mTempRGBBuffer;
124 /** Frame buffer translated into YUV420 for the mpeg codec */
125 uint8_t *mYUVBuffer;
126 /** Temporary buffer into which the codec writes frames to be
127 * written into the file */
128 uint8_t *mOutBuf;
129 RTCRITSECT mCritSect;
130 /** File where we store the mpeg stream */
131 RTFILE mFile;
132 /** time at which the last "real" frame was created */
133 int64_t mLastTime;
134 /** Pointer to ffmpeg's format information context */
135 AVFormatContext *mpFormatContext;
136 /** ffmpeg context containing information about the stream */
137 AVStream *mpStream;
138 /** Information for ffmpeg describing the current frame */
139 AVFrame *mFrame;
140 /** ffmpeg pixel format of guest framebuffer */
141 int mFFMPEGPixelFormat;
142 /** Since we are building without exception support, we use this
143 to signal allocation failure in the constructor */
144 bool mOutOfMemory;
145 /** A hack: ffmpeg mpeg2 only writes a frame if something has
146 changed. So we flip the low luminance bit of the first
147 pixel every frame. */
148 bool mToggle;
149
150 HRESULT setup_library();
151 HRESULT setup_output_format();
152 HRESULT list_formats();
153 HRESULT open_codec();
154 HRESULT open_output_file();
155 void copy_to_intermediate_buffer(ULONG x, ULONG y, ULONG w, ULONG h);
156 HRESULT do_rgb_to_yuv_conversion();
157 HRESULT do_encoding_and_write();
158 HRESULT write_png();
159#ifndef VBOX_WITH_XPCOM
160 long refcnt;
161#endif
162};
163
164/**
165 * Iterator class for running through an BGRA32 image buffer and converting
166 * it to RGB.
167 */
168class FFmpegBGRA32Iter
169{
170private:
171 enum { PIX_SIZE = 4 };
172public:
173 FFmpegBGRA32Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuffer)
174 {
175 mPos = 0;
176 mSize = aWidth * aHeight * PIX_SIZE;
177 mBuffer = aBuffer;
178 }
179 /**
180 * Convert the next pixel to RGB.
181 * @returns true on success, false if we have reached the end of the buffer
182 * @param aRed where to store the red value
183 * @param aGreen where to store the green value
184 * @param aBlue where to store the blue value
185 */
186 bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue)
187 {
188 bool rc = false;
189 if (mPos + PIX_SIZE <= mSize)
190 {
191 *aRed = mBuffer[mPos + 2];
192 *aGreen = mBuffer[mPos + 1];
193 *aBlue = mBuffer[mPos];
194 mPos += PIX_SIZE;
195 rc = true;
196 }
197 return rc;
198 }
199
200 /**
201 * Skip forward by a certain number of pixels
202 * @param aPixels how many pixels to skip
203 */
204 void skip(unsigned aPixels)
205 {
206 mPos += PIX_SIZE * aPixels;
207 }
208private:
209 /** Size of the picture buffer */
210 unsigned mSize;
211 /** Current position in the picture buffer */
212 unsigned mPos;
213 /** Address of the picture buffer */
214 uint8_t *mBuffer;
215};
216
217/**
218 * Iterator class for running through an BGR24 image buffer and converting
219 * it to RGB.
220 */
221class FFmpegBGR24Iter
222{
223private:
224 enum { PIX_SIZE = 3 };
225public:
226 FFmpegBGR24Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuffer)
227 {
228 mPos = 0;
229 mSize = aWidth * aHeight * PIX_SIZE;
230 mBuffer = aBuffer;
231 }
232 /**
233 * Convert the next pixel to RGB.
234 * @returns true on success, false if we have reached the end of the buffer
235 * @param aRed where to store the red value
236 * @param aGreen where to store the green value
237 * @param aBlue where to store the blue value
238 */
239 bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue)
240 {
241 bool rc = false;
242 if (mPos + PIX_SIZE <= mSize)
243 {
244 *aRed = mBuffer[mPos + 2];
245 *aGreen = mBuffer[mPos + 1];
246 *aBlue = mBuffer[mPos];
247 mPos += PIX_SIZE;
248 rc = true;
249 }
250 return rc;
251 }
252
253 /**
254 * Skip forward by a certain number of pixels
255 * @param aPixels how many pixels to skip
256 */
257 void skip(unsigned aPixels)
258 {
259 mPos += PIX_SIZE * aPixels;
260 }
261private:
262 /** Size of the picture buffer */
263 unsigned mSize;
264 /** Current position in the picture buffer */
265 unsigned mPos;
266 /** Address of the picture buffer */
267 uint8_t *mBuffer;
268};
269
270/**
271 * Iterator class for running through an BGR565 image buffer and converting
272 * it to RGB.
273 */
274class FFmpegBGR565Iter
275{
276private:
277 enum { PIX_SIZE = 2 };
278public:
279 FFmpegBGR565Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuffer)
280 {
281 mPos = 0;
282 mSize = aWidth * aHeight * PIX_SIZE;
283 mBuffer = aBuffer;
284 }
285 /**
286 * Convert the next pixel to RGB.
287 * @returns true on success, false if we have reached the end of the buffer
288 * @param aRed where to store the red value
289 * @param aGreen where to store the green value
290 * @param aBlue where to store the blue value
291 */
292 bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue)
293 {
294 bool rc = false;
295 if (mPos + PIX_SIZE <= mSize)
296 {
297 unsigned uFull = (((unsigned) mBuffer[mPos + 1]) << 8)
298 | ((unsigned) mBuffer[mPos]);
299 *aRed = (uFull >> 8) & ~7;
300 *aGreen = (uFull >> 3) & ~3 & 0xff;
301 *aBlue = (uFull << 3) & ~7 & 0xff;
302 mPos += PIX_SIZE;
303 rc = true;
304 }
305 return rc;
306 }
307
308 /**
309 * Skip forward by a certain number of pixels
310 * @param aPixels how many pixels to skip
311 */
312 void skip(unsigned aPixels)
313 {
314 mPos += PIX_SIZE * aPixels;
315 }
316private:
317 /** Size of the picture buffer */
318 unsigned mSize;
319 /** Current position in the picture buffer */
320 unsigned mPos;
321 /** Address of the picture buffer */
322 uint8_t *mBuffer;
323};
324
325
326/**
327 * Convert an image to YUV420p format
328 * @returns true on success, false on failure
329 * @param aWidth width of image
330 * @param aHeight height of image
331 * @param aDestBuf an allocated memory buffer large enough to hold the
332 * destination image (i.e. width * height * 12bits)
333 * @param aSrcBuf the source image as an array of bytes
334 */
335template <class T>
336inline bool FFmpegWriteYUV420p(unsigned aWidth, unsigned aHeight, uint8_t *aDestBuf,
337 uint8_t *aSrcBuf)
338{
339 AssertReturn(0 == (aWidth & 1), false);
340 AssertReturn(0 == (aHeight & 1), false);
341 bool rc = true;
342 T iter1(aWidth, aHeight, aSrcBuf);
343 T iter2 = iter1;
344 iter2.skip(aWidth);
345 unsigned cPixels = aWidth * aHeight;
346 unsigned offY = 0;
347 unsigned offU = cPixels;
348 unsigned offV = cPixels + cPixels / 4;
349 for (unsigned i = 0; (i < aHeight / 2) && rc; ++i)
350 {
351 for (unsigned j = 0; (j < aWidth / 2) && rc; ++j)
352 {
353 unsigned red, green, blue, u, v;
354 rc = iter1.getRGB(&red, &green, &blue);
355 if (rc)
356 {
357 aDestBuf[offY] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
358 u = (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
359 v = (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
360 rc = iter1.getRGB(&red, &green, &blue);
361 }
362 if (rc)
363 {
364 aDestBuf[offY + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
365 u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
366 v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
367 rc = iter2.getRGB(&red, &green, &blue);
368 }
369 if (rc)
370 {
371 aDestBuf[offY + aWidth] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
372 u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
373 v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
374 rc = iter2.getRGB(&red, &green, &blue);
375 }
376 if (rc)
377 {
378 aDestBuf[offY + aWidth + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
379 u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
380 v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
381 aDestBuf[offU] = u;
382 aDestBuf[offV] = v;
383 offY += 2;
384 ++offU;
385 ++offV;
386 }
387 }
388 if (rc)
389 {
390 iter1.skip(aWidth);
391 iter2.skip(aWidth);
392 offY += aWidth;
393 }
394 }
395 return rc;
396}
397
398
399/**
400 * Convert an image to RGB24 format
401 * @returns true on success, false on failure
402 * @param aWidth width of image
403 * @param aHeight height of image
404 * @param aDestBuf an allocated memory buffer large enough to hold the
405 * destination image (i.e. width * height * 12bits)
406 * @param aSrcBuf the source image as an array of bytes
407 */
408template <class T>
409inline bool FFmpegWriteRGB24(unsigned aWidth, unsigned aHeight, uint8_t *aDestBuf,
410 uint8_t *aSrcBuf)
411{
412 enum { PIX_SIZE = 3 };
413 bool rc = true;
414 AssertReturn(0 == (aWidth & 1), false);
415 AssertReturn(0 == (aHeight & 1), false);
416 T iter(aWidth, aHeight, aSrcBuf);
417 unsigned cPixels = aWidth * aHeight;
418 for (unsigned i = 0; (i < cPixels) && rc; ++i)
419 {
420 unsigned red, green, blue;
421 rc = iter.getRGB(&red, &green, &blue);
422 if (rc)
423 {
424 aDestBuf[i * PIX_SIZE] = red;
425 aDestBuf[i * PIX_SIZE + 1] = green;
426 aDestBuf[i * PIX_SIZE + 2] = blue;
427 }
428 }
429 return rc;
430}
431
432#endif /* !_H_FFMPEGFB */
Note: See TracBrowser for help on using the repository browser.

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