VirtualBox

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

Last change on this file since 34575 was 31700, checked in by vboxsync, 14 years ago

missed

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