VirtualBox

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

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

HGSMI: post host VBVA commands to display; Video HW Accel: mechanism for passing/processing commands to framebuffer

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.8 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, ULONG w, ULONG h);
103 STDMETHOD(RequestResize)(ULONG aScreenId, ULONG pixelFormat, BYTE *vram,
104 ULONG bitsPerPixel, ULONG bytesPerLine,
105 ULONG w, ULONG h, BOOL *finished);
106 STDMETHOD(VideoModeSupported)(ULONG width, ULONG height, ULONG bpp, BOOL *supported);
107 STDMETHOD(GetVisibleRegion)(BYTE *rectangles, ULONG count, ULONG *countCopied);
108 STDMETHOD(SetVisibleRegion)(BYTE *rectangles, ULONG count);
109
110 STDMETHOD(ProcessVHWACommand)(BYTE *pCommand);
111
112private:
113 /** true if url_fopen actually succeeded */
114 bool mfUrlOpen;
115 /** Guest framebuffer width */
116 ULONG mGuestWidth;
117 /** Guest framebuffer height */
118 ULONG mGuestHeight;
119 /** Bit rate used for encoding */
120 ULONG mBitRate;
121 /** Guest framebuffer pixel format */
122 ULONG mPixelFormat;
123 /** Guest framebuffer color depth */
124 ULONG mBitsPerPixel;
125 /** Name of the file we will write to */
126 com::Bstr mFileName;
127 /** Guest framebuffer line length */
128 ULONG mBytesPerLine;
129 /** MPEG frame framebuffer width */
130 ULONG mFrameWidth;
131 /** MPEG frame framebuffer height */
132 ULONG mFrameHeight;
133 /** The size of one YUV frame */
134 ULONG mYUVFrameSize;
135 /** If we can't use the video RAM directly, we allocate our own
136 * buffer */
137 uint8_t *mRGBBuffer;
138 /** The address of the buffer - can be either mRGBBuffer or the
139 * guests VRAM (HC address) if we can handle that directly */
140 uint8_t *mBufferAddress;
141 /** An intermediary RGB buffer with the same dimensions */
142 uint8_t *mTempRGBBuffer;
143 /** Frame buffer translated into YUV420 for the mpeg codec */
144 uint8_t *mYUVBuffer;
145 /** Temporary buffer into which the codec writes frames to be
146 * written into the file */
147 uint8_t *mOutBuf;
148 RTCRITSECT mCritSect;
149 /** File where we store the mpeg stream */
150 RTFILE mFile;
151 /** time at which the last "real" frame was created */
152 int64_t mLastTime;
153 /** Pointer to ffmpeg's format information context */
154 AVFormatContext *mpFormatContext;
155 /** ffmpeg context containing information about the stream */
156 AVStream *mpStream;
157 /** Information for ffmpeg describing the current frame */
158 AVFrame *mFrame;
159 /** ffmpeg pixel format of guest framebuffer */
160 int mFFMPEGPixelFormat;
161 /** Since we are building without exception support, we use this
162 to signal allocation failure in the constructor */
163 bool mOutOfMemory;
164 /** A hack: ffmpeg mpeg2 only writes a frame if something has
165 changed. So we flip the low luminance bit of the first
166 pixel every frame. */
167 bool mToggle;
168
169 HRESULT setup_library();
170 HRESULT setup_output_format();
171 HRESULT list_formats();
172 HRESULT open_codec();
173 HRESULT open_output_file();
174 void copy_to_intermediate_buffer(ULONG x, ULONG y, ULONG w, ULONG h);
175 HRESULT do_rgb_to_yuv_conversion();
176 HRESULT do_encoding_and_write();
177 HRESULT write_png();
178#ifndef VBOX_WITH_XPCOM
179 long refcnt;
180#endif
181};
182
183/**
184 * Iterator class for running through an BGRA32 image buffer and converting
185 * it to RGB.
186 */
187class FFmpegBGRA32Iter
188{
189private:
190 enum { PIX_SIZE = 4 };
191public:
192 FFmpegBGRA32Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuffer)
193 {
194 mPos = 0;
195 mSize = aWidth * aHeight * PIX_SIZE;
196 mBuffer = aBuffer;
197 }
198 /**
199 * Convert the next pixel to RGB.
200 * @returns true on success, false if we have reached the end of the buffer
201 * @param aRed where to store the red value
202 * @param aGreen where to store the green value
203 * @param aBlue where to store the blue value
204 */
205 bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue)
206 {
207 bool rc = false;
208 if (mPos + PIX_SIZE <= mSize)
209 {
210 *aRed = mBuffer[mPos + 2];
211 *aGreen = mBuffer[mPos + 1];
212 *aBlue = mBuffer[mPos];
213 mPos += PIX_SIZE;
214 rc = true;
215 }
216 return rc;
217 }
218
219 /**
220 * Skip forward by a certain number of pixels
221 * @param aPixels how many pixels to skip
222 */
223 void skip(unsigned aPixels)
224 {
225 mPos += PIX_SIZE * aPixels;
226 }
227private:
228 /** Size of the picture buffer */
229 unsigned mSize;
230 /** Current position in the picture buffer */
231 unsigned mPos;
232 /** Address of the picture buffer */
233 uint8_t *mBuffer;
234};
235
236/**
237 * Iterator class for running through an BGR24 image buffer and converting
238 * it to RGB.
239 */
240class FFmpegBGR24Iter
241{
242private:
243 enum { PIX_SIZE = 3 };
244public:
245 FFmpegBGR24Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuffer)
246 {
247 mPos = 0;
248 mSize = aWidth * aHeight * PIX_SIZE;
249 mBuffer = aBuffer;
250 }
251 /**
252 * Convert the next pixel to RGB.
253 * @returns true on success, false if we have reached the end of the buffer
254 * @param aRed where to store the red value
255 * @param aGreen where to store the green value
256 * @param aBlue where to store the blue value
257 */
258 bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue)
259 {
260 bool rc = false;
261 if (mPos + PIX_SIZE <= mSize)
262 {
263 *aRed = mBuffer[mPos + 2];
264 *aGreen = mBuffer[mPos + 1];
265 *aBlue = mBuffer[mPos];
266 mPos += PIX_SIZE;
267 rc = true;
268 }
269 return rc;
270 }
271
272 /**
273 * Skip forward by a certain number of pixels
274 * @param aPixels how many pixels to skip
275 */
276 void skip(unsigned aPixels)
277 {
278 mPos += PIX_SIZE * aPixels;
279 }
280private:
281 /** Size of the picture buffer */
282 unsigned mSize;
283 /** Current position in the picture buffer */
284 unsigned mPos;
285 /** Address of the picture buffer */
286 uint8_t *mBuffer;
287};
288
289/**
290 * Iterator class for running through an BGR565 image buffer and converting
291 * it to RGB.
292 */
293class FFmpegBGR565Iter
294{
295private:
296 enum { PIX_SIZE = 2 };
297public:
298 FFmpegBGR565Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuffer)
299 {
300 mPos = 0;
301 mSize = aWidth * aHeight * PIX_SIZE;
302 mBuffer = aBuffer;
303 }
304 /**
305 * Convert the next pixel to RGB.
306 * @returns true on success, false if we have reached the end of the buffer
307 * @param aRed where to store the red value
308 * @param aGreen where to store the green value
309 * @param aBlue where to store the blue value
310 */
311 bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue)
312 {
313 bool rc = false;
314 if (mPos + PIX_SIZE <= mSize)
315 {
316 unsigned uFull = (((unsigned) mBuffer[mPos + 1]) << 8)
317 | ((unsigned) mBuffer[mPos]);
318 *aRed = (uFull >> 8) & ~7;
319 *aGreen = (uFull >> 3) & ~3 & 0xff;
320 *aBlue = (uFull << 3) & ~7 & 0xff;
321 mPos += PIX_SIZE;
322 rc = true;
323 }
324 return rc;
325 }
326
327 /**
328 * Skip forward by a certain number of pixels
329 * @param aPixels how many pixels to skip
330 */
331 void skip(unsigned aPixels)
332 {
333 mPos += PIX_SIZE * aPixels;
334 }
335private:
336 /** Size of the picture buffer */
337 unsigned mSize;
338 /** Current position in the picture buffer */
339 unsigned mPos;
340 /** Address of the picture buffer */
341 uint8_t *mBuffer;
342};
343
344
345/**
346 * Convert an image to YUV420p format
347 * @returns true on success, false on failure
348 * @param aWidth width of image
349 * @param aHeight height of image
350 * @param aDestBuf an allocated memory buffer large enough to hold the
351 * destination image (i.e. width * height * 12bits)
352 * @param aSrcBuf the source image as an array of bytes
353 */
354template <class T>
355inline bool FFmpegWriteYUV420p(unsigned aWidth, unsigned aHeight, uint8_t *aDestBuf,
356 uint8_t *aSrcBuf)
357{
358 AssertReturn(0 == (aWidth & 1), false);
359 AssertReturn(0 == (aHeight & 1), false);
360 bool rc = true;
361 T iter1(aWidth, aHeight, aSrcBuf);
362 T iter2 = iter1;
363 iter2.skip(aWidth);
364 unsigned cPixels = aWidth * aHeight;
365 unsigned offY = 0;
366 unsigned offU = cPixels;
367 unsigned offV = cPixels + cPixels / 4;
368 for (unsigned i = 0; (i < aHeight / 2) && rc; ++i)
369 {
370 for (unsigned j = 0; (j < aWidth / 2) && rc; ++j)
371 {
372 unsigned red, green, blue, u, v;
373 rc = iter1.getRGB(&red, &green, &blue);
374 if (rc)
375 {
376 aDestBuf[offY] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
377 u = (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
378 v = (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
379 rc = iter1.getRGB(&red, &green, &blue);
380 }
381 if (rc)
382 {
383 aDestBuf[offY + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
384 u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
385 v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
386 rc = iter2.getRGB(&red, &green, &blue);
387 }
388 if (rc)
389 {
390 aDestBuf[offY + aWidth] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
391 u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
392 v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
393 rc = iter2.getRGB(&red, &green, &blue);
394 }
395 if (rc)
396 {
397 aDestBuf[offY + aWidth + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
398 u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
399 v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
400 aDestBuf[offU] = u;
401 aDestBuf[offV] = v;
402 offY += 2;
403 ++offU;
404 ++offV;
405 }
406 }
407 if (rc)
408 {
409 iter1.skip(aWidth);
410 iter2.skip(aWidth);
411 offY += aWidth;
412 }
413 }
414 return rc;
415}
416
417
418/**
419 * Convert an image to RGB24 format
420 * @returns true on success, false on failure
421 * @param aWidth width of image
422 * @param aHeight height of image
423 * @param aDestBuf an allocated memory buffer large enough to hold the
424 * destination image (i.e. width * height * 12bits)
425 * @param aSrcBuf the source image as an array of bytes
426 */
427template <class T>
428inline bool FFmpegWriteRGB24(unsigned aWidth, unsigned aHeight, uint8_t *aDestBuf,
429 uint8_t *aSrcBuf)
430{
431 enum { PIX_SIZE = 3 };
432 bool rc = true;
433 AssertReturn(0 == (aWidth & 1), false);
434 AssertReturn(0 == (aHeight & 1), false);
435 T iter(aWidth, aHeight, aSrcBuf);
436 unsigned cPixels = aWidth * aHeight;
437 for (unsigned i = 0; (i < cPixels) && rc; ++i)
438 {
439 unsigned red, green, blue;
440 rc = iter.getRGB(&red, &green, &blue);
441 if (rc)
442 {
443 aDestBuf[i * PIX_SIZE] = red;
444 aDestBuf[i * PIX_SIZE + 1] = green;
445 aDestBuf[i * PIX_SIZE + 2] = blue;
446 }
447 }
448 return rc;
449}
450
451#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