VirtualBox

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

Last change on this file since 19340 was 19340, checked in by vboxsync, 16 years ago

FE/Headless/FFmpegFB: this seems to be needed now to build on Windows

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