VirtualBox

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

最後變更 在這個檔案從7509是 7509,由 vboxsync 提交於 17 年 前

Frontends/VBoxHeadless: removed references to deprecated ffmpeg function img_convert() and replaced it with functions of our own to avoid new dependencies

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

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