VirtualBox

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

Last change on this file since 9723 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

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