summaryrefslogtreecommitdiff
path: root/src/VBox/Frontends/VBoxHeadless/VideoCapture
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-03-26 19:21:20 +0000
committer <>2014-05-08 15:03:54 +0000
commitfb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch)
treec2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Frontends/VBoxHeadless/VideoCapture
parent58ed4748338f9466599adfc8a9171280ed99e23f (diff)
downloadVirtualBox-master.tar.gz
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Frontends/VBoxHeadless/VideoCapture')
-rw-r--r--src/VBox/Frontends/VBoxHeadless/VideoCapture/FFmpegFB.cpp1223
-rw-r--r--src/VBox/Frontends/VBoxHeadless/VideoCapture/FFmpegFB.h458
-rw-r--r--src/VBox/Frontends/VBoxHeadless/VideoCapture/Makefile.kmk32
3 files changed, 0 insertions, 1713 deletions
diff --git a/src/VBox/Frontends/VBoxHeadless/VideoCapture/FFmpegFB.cpp b/src/VBox/Frontends/VBoxHeadless/VideoCapture/FFmpegFB.cpp
deleted file mode 100644
index 7b35b3b2..00000000
--- a/src/VBox/Frontends/VBoxHeadless/VideoCapture/FFmpegFB.cpp
+++ /dev/null
@@ -1,1223 +0,0 @@
-/** @file
- *
- * Framebuffer implementation that interfaces with FFmpeg
- * to create a video of the guest.
- */
-
-/*
- * Copyright (C) 2006-2012 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#define LOG_GROUP LOG_GROUP_GUI
-
-#include "FFmpegFB.h"
-
-#include <iprt/file.h>
-#include <iprt/param.h>
-#include <iprt/assert.h>
-#include <VBox/log.h>
-#include <png.h>
-#include <iprt/stream.h>
-
-#define VBOX_SHOW_AVAILABLE_FORMATS
-
-// external constructor for dynamic loading
-/////////////////////////////////////////////////////////////////////////////
-
-/**
- * Callback function to register an ffmpeg framebuffer.
- *
- * @returns COM status code.
- * @param width Framebuffer width.
- * @param height Framebuffer height.
- * @param bitrate Bitrate of mpeg file to be created.
- * @param filename Name of mpeg file to be created
- * @retval retVal The new framebuffer
- */
-extern "C" DECLEXPORT(HRESULT) VBoxRegisterFFmpegFB(ULONG width,
- ULONG height, ULONG bitrate,
- com::Bstr filename,
- IFramebuffer **retVal)
-{
- Log2(("VBoxRegisterFFmpegFB: called\n"));
- FFmpegFB *pFramebuffer = new FFmpegFB(width, height, bitrate, filename);
- int rc = pFramebuffer->init();
- AssertMsg(rc == S_OK,
- ("failed to initialise the FFmpeg framebuffer, rc = %d\n",
- rc));
- if (rc == S_OK)
- {
- *retVal = pFramebuffer;
- return S_OK;
- }
- delete pFramebuffer;
- return rc;
-}
-
-
-
-
-
-// constructor / destructor
-/////////////////////////////////////////////////////////////////////////////
-
-/**
- * Perform parts of initialisation which are guaranteed not to fail
- * unless we run out of memory. In this case, we just set the guest
- * buffer to 0 so that RequestResize() does not free it the first time
- * it is called.
- */
-#ifdef VBOX_WITH_VPX
-FFmpegFB::FFmpegFB(ULONG width, ULONG height, ULONG bitrate,
- com::Bstr filename) :
- mfUrlOpen(false),
- mBitRate(bitrate),
- mPixelFormat(FramebufferPixelFormat_Opaque),
- mBitsPerPixel(0),
- mFileName(filename),
- mBytesPerLine(0),
- mFrameWidth(width), mFrameHeight(height),
- mYUVFrameSize(width * height * 3 / 2),
- mRGBBuffer(0),
- mOutOfMemory(false), mToggle(false)
-#else
-FFmpegFB::FFmpegFB(ULONG width, ULONG height, ULONG bitrate,
- com::Bstr filename) :
- mpFormatContext(0), mpStream(0),
- mfUrlOpen(false),
- mBitRate(bitrate),
- mPixelFormat(FramebufferPixelFormat_Opaque),
- mBitsPerPixel(0),
- mFileName(filename),
- mBytesPerLine(0),
- mFrameWidth(width), mFrameHeight(height),
- mYUVFrameSize(width * height * 3 / 2),mRGBBuffer(0),
- mOutOfMemory(false), mToggle(false)
-#endif
-{
- ULONG cPixels = width * height;
-
-#ifdef VBOX_WITH_VPX
- Assert(width % 2 == 0 && height % 2 == 0);
- /* For temporary RGB frame we allocate enough memory to deal with
- RGB16 to RGB32 */
- mTempRGBBuffer = reinterpret_cast<uint8_t *>(RTMemAlloc(cPixels * 4));
- if (!mTempRGBBuffer)
- goto nomem_temp_rgb_buffer;
- mYUVBuffer = reinterpret_cast<uint8_t *>(RTMemAlloc(mYUVFrameSize));
- if (!mYUVBuffer)
- goto nomem_yuv_buffer;
- return;
-
- /* C-based memory allocation and how to deal with it in C++ :) */
-nomem_yuv_buffer:
- Log(("Failed to allocate memory for mYUVBuffer\n"));
- RTMemFree(mYUVBuffer);
-nomem_temp_rgb_buffer:
- Log(("Failed to allocate memory for mTempRGBBuffer\n"));
- RTMemFree(mTempRGBBuffer);
- mOutOfMemory = true;
-#else
- LogFlow(("Creating FFmpegFB object %p, width=%lu, height=%lu\n",
- this, (unsigned long) width, (unsigned long) height));
- Assert(width % 2 == 0 && height % 2 == 0);
- /* For temporary RGB frame we allocate enough memory to deal with
- RGB16 to RGB32 */
- mTempRGBBuffer = reinterpret_cast<uint8_t *>(av_malloc(cPixels * 4));
- if (!mTempRGBBuffer)
- goto nomem_temp_rgb_buffer;
- mYUVBuffer = reinterpret_cast<uint8_t *>(av_malloc(mYUVFrameSize));
- if (!mYUVBuffer)
- goto nomem_yuv_buffer;
- mFrame = avcodec_alloc_frame();
- if (!mFrame)
- goto nomem_mframe;
- mOutBuf = reinterpret_cast<uint8_t *>(av_malloc(mYUVFrameSize * 2));
- if (!mOutBuf)
- goto nomem_moutbuf;
-
- return;
-
- /* C-based memory allocation and how to deal with it in C++ :) */
-nomem_moutbuf:
- Log(("Failed to allocate memory for mOutBuf\n"));
- av_free(mFrame);
-nomem_mframe:
- Log(("Failed to allocate memory for mFrame\n"));
- av_free(mYUVBuffer);
-nomem_yuv_buffer:
- Log(("Failed to allocate memory for mYUVBuffer\n"));
- av_free(mTempRGBBuffer);
-nomem_temp_rgb_buffer:
- Log(("Failed to allocate memory for mTempRGBBuffer\n"));
- mOutOfMemory = true;
-#endif
-}
-
-
-/**
- * Write the last frame to disk and free allocated memory
- */
-FFmpegFB::~FFmpegFB()
-{
- LogFlow(("Destroying FFmpegFB object %p\n", this));
-#ifdef VBOX_WITH_VPX
- /* Dummy update to make sure we get all the frame (timing). */
- NotifyUpdate(0, 0, 0, 0);
- /* Write the last pending frame before exiting */
- int rc = do_rgb_to_yuv_conversion();
- if (rc == S_OK)
- VideoRecEncodeAndWrite(pVideoRecContext, mFrameWidth, mFrameHeight, mYUVBuffer);
-# if 1
- /* Add another 10 seconds. */
- for (int i = 10*25; i > 0; i--)
- VideoRecEncodeAndWrite(pVideoRecContext, mFrameWidth, mFrameHeight, mYUVBuffer);
-# endif
- VideoRecContextClose(pVideoRecContext);
- RTCritSectDelete(&mCritSect);
-
- /* We have already freed the stream above */
- if (mTempRGBBuffer)
- RTMemFree(mTempRGBBuffer);
- if (mYUVBuffer)
- RTMemFree(mYUVBuffer);
- if (mRGBBuffer)
- RTMemFree(mRGBBuffer);
-#else
- if (mpFormatContext != 0)
- {
- if (mfUrlOpen)
- {
- /* Dummy update to make sure we get all the frame (timing). */
- NotifyUpdate(0, 0, 0, 0);
- /* Write the last pending frame before exiting */
- int rc = do_rgb_to_yuv_conversion();
- if (rc == S_OK)
- do_encoding_and_write();
-# if 1
- /* Add another 10 seconds. */
- for (int i = 10*25; i > 0; i--)
- do_encoding_and_write();
-# endif
- /* write a png file of the last frame */
- write_png();
- avcodec_close(mpStream->codec);
- av_write_trailer(mpFormatContext);
- /* free the streams */
- for(unsigned i = 0; i < (unsigned)mpFormatContext->nb_streams; i++) {
- av_freep(&mpFormatContext->streams[i]->codec);
- av_freep(&mpFormatContext->streams[i]);
- }
-/* Changed sometime between 50.5.0 and 52.7.0 */
-# if LIBAVFORMAT_VERSION_INT >= (52 << 16)
- url_fclose(mpFormatContext->pb);
-# else /* older version */
- url_fclose(&mpFormatContext->pb);
-# endif /* older version */
- }
- av_free(mpFormatContext);
- }
- RTCritSectDelete(&mCritSect);
- /* We have already freed the stream above */
- mpStream = 0;
- if (mTempRGBBuffer)
- av_free(mTempRGBBuffer);
- if (mYUVBuffer)
- av_free(mYUVBuffer);
- if (mFrame)
- av_free(mFrame);
- if (mOutBuf)
- av_free(mOutBuf);
- if (mRGBBuffer)
- RTMemFree(mRGBBuffer);
-#endif
-}
-
-// public methods only for internal purposes
-/////////////////////////////////////////////////////////////////////////////
-
-/**
- * Perform any parts of the initialisation which could potentially fail
- * for reasons other than "out of memory".
- *
- * @returns COM status code
- * @param width width to be used for MPEG frame framebuffer and initially
- * for the guest frame buffer - must be a multiple of two
- * @param height height to be used for MPEG frame framebuffer and
- * initially for the guest framebuffer - must be a multiple
- * of two
- * @param depth depth to be used initially for the guest framebuffer
- */
-HRESULT FFmpegFB::init()
-{
- LogFlow(("Initialising FFmpegFB object %p\n", this));
- if (mOutOfMemory == true)
- return E_OUTOFMEMORY;
- int rc;
- int rcOpenFile;
- int rcOpenCodec;
-
-#ifdef VBOX_WITH_VPX
-
- rc = VideoRecContextCreate(&pVideoRecContext);
- rc = RTCritSectInit(&mCritSect);
- AssertReturn(rc == VINF_SUCCESS, E_UNEXPECTED);
-
- if(rc == VINF_SUCCESS)
- rc = VideoRecContextInit(pVideoRecContext, mFileName, mFrameWidth, mFrameHeight);
-#else
- rc = RTCritSectInit(&mCritSect);
- AssertReturn(rc == VINF_SUCCESS, E_UNEXPECTED);
- int rcSetupLibrary = setup_library();
- AssertReturn(rcSetupLibrary == S_OK, rcSetupLibrary);
- int rcSetupFormat = setup_output_format();
- AssertReturn(rcSetupFormat == S_OK, rcSetupFormat);
- rcOpenCodec = open_codec();
- AssertReturn(rcOpenCodec == S_OK, rcOpenCodec);
- rcOpenFile = open_output_file();
- AssertReturn(rcOpenFile == S_OK, rcOpenFile);
-
- /* Fill in the picture data for the AVFrame - not particularly
- elegant, but that is the API. */
- avpicture_fill((AVPicture *) mFrame, mYUVBuffer, PIX_FMT_YUV420P,
- mFrameWidth, mFrameHeight);
-#endif
-
- /* Set the initial framebuffer size to the mpeg frame dimensions */
- BOOL finished;
- RequestResize(0, FramebufferPixelFormat_Opaque, NULL, 0, 0,
- mFrameWidth, mFrameHeight, &finished);
- /* Start counting time */
- mLastTime = RTTimeMilliTS();
- mLastTime = mLastTime - mLastTime % 40;
- return rc;
-}
-
-// IFramebuffer properties
-/////////////////////////////////////////////////////////////////////////////
-
-/**
- * Return the address of the frame buffer for the virtual VGA device to
- * write to. If COMGETTER(UsesGuestVRAM) returns FLASE (or if this address
- * is not the same as the guests VRAM buffer), the device will perform
- * translation.
- *
- * @returns COM status code
- * @retval address The address of the buffer
- */
-STDMETHODIMP FFmpegFB::COMGETTER(Address) (BYTE **address)
-{
- if (!address)
- return E_POINTER;
- LogFlow(("FFmpeg::COMGETTER(Address): returning address %p\n", mBufferAddress));
- *address = mBufferAddress;
- return S_OK;
-}
-
-/**
- * Return the width of our frame buffer.
- *
- * @returns COM status code
- * @retval width The width of the frame buffer
- */
-STDMETHODIMP FFmpegFB::COMGETTER(Width) (ULONG *width)
-{
- if (!width)
- return E_POINTER;
- LogFlow(("FFmpeg::COMGETTER(Width): returning width %lu\n",
- (unsigned long) mGuestWidth));
- *width = mGuestWidth;
- return S_OK;
-}
-
-/**
- * Return the height of our frame buffer.
- *
- * @returns COM status code
- * @retval height The height of the frame buffer
- */
-STDMETHODIMP FFmpegFB::COMGETTER(Height) (ULONG *height)
-{
- if (!height)
- return E_POINTER;
- LogFlow(("FFmpeg::COMGETTER(Height): returning height %lu\n",
- (unsigned long) mGuestHeight));
- *height = mGuestHeight;
- return S_OK;
-}
-
-/**
- * Return the colour depth of our frame buffer. Note that we actually
- * store the pixel format, not the colour depth internally, since
- * when display sets FramebufferPixelFormat_Opaque, it
- * wants to retrieve FramebufferPixelFormat_Opaque and
- * nothing else.
- *
- * @returns COM status code
- * @retval bitsPerPixel The colour depth of the frame buffer
- */
-STDMETHODIMP FFmpegFB::COMGETTER(BitsPerPixel) (ULONG *bitsPerPixel)
-{
- if (!bitsPerPixel)
- return E_POINTER;
- *bitsPerPixel = mBitsPerPixel;
- LogFlow(("FFmpeg::COMGETTER(BitsPerPixel): returning depth %lu\n",
- (unsigned long) *bitsPerPixel));
- return S_OK;
-}
-
-/**
- * Return the number of bytes per line in our frame buffer.
- *
- * @returns COM status code
- * @retval bytesPerLine The number of bytes per line
- */
-STDMETHODIMP FFmpegFB::COMGETTER(BytesPerLine) (ULONG *bytesPerLine)
-{
- if (!bytesPerLine)
- return E_POINTER;
- LogFlow(("FFmpeg::COMGETTER(BytesPerLine): returning line size %lu\n",
- (unsigned long) mBytesPerLine));
- *bytesPerLine = mBytesPerLine;
- return S_OK;
-}
-
-/**
- * Return the pixel layout of our frame buffer.
- *
- * @returns COM status code
- * @retval pixelFormat The pixel layout
- */
-STDMETHODIMP FFmpegFB::COMGETTER(PixelFormat) (ULONG *pixelFormat)
-{
- if (!pixelFormat)
- return E_POINTER;
- LogFlow(("FFmpeg::COMGETTER(PixelFormat): returning pixel format: %lu\n",
- (unsigned long) mPixelFormat));
- *pixelFormat = mPixelFormat;
- return S_OK;
-}
-
-/**
- * Return whether we use the guest VRAM directly.
- *
- * @returns COM status code
- * @retval pixelFormat The pixel layout
- */
-STDMETHODIMP FFmpegFB::COMGETTER(UsesGuestVRAM) (BOOL *usesGuestVRAM)
-{
- if (!usesGuestVRAM)
- return E_POINTER;
- LogFlow(("FFmpeg::COMGETTER(UsesGuestVRAM): uses guest VRAM? %d\n",
- mRGBBuffer == NULL));
- *usesGuestVRAM = (mRGBBuffer == NULL);
- return S_OK;
-}
-
-/**
- * Return the number of lines of our frame buffer which can not be used
- * (e.g. for status lines etc?).
- *
- * @returns COM status code
- * @retval heightReduction The number of unused lines
- */
-STDMETHODIMP FFmpegFB::COMGETTER(HeightReduction) (ULONG *heightReduction)
-{
- if (!heightReduction)
- return E_POINTER;
- /* no reduction */
- *heightReduction = 0;
- LogFlow(("FFmpeg::COMGETTER(HeightReduction): returning 0\n"));
- return S_OK;
-}
-
-/**
- * Return a pointer to the alpha-blended overlay used to render status icons
- * etc above the framebuffer.
- *
- * @returns COM status code
- * @retval aOverlay The overlay framebuffer
- */
-STDMETHODIMP FFmpegFB::COMGETTER(Overlay) (IFramebufferOverlay **aOverlay)
-{
- if (!aOverlay)
- return E_POINTER;
- /* not yet implemented */
- *aOverlay = 0;
- LogFlow(("FFmpeg::COMGETTER(Overlay): returning 0\n"));
- return S_OK;
-}
-
-/**
- * Return id of associated window
- *
- * @returns COM status code
- * @retval winId Associated window id
- */
-STDMETHODIMP FFmpegFB::COMGETTER(WinId) (LONG64 *winId)
-{
- if (!winId)
- return E_POINTER;
- *winId = 0;
- return S_OK;
-}
-
-// IFramebuffer methods
-/////////////////////////////////////////////////////////////////////////////
-
-STDMETHODIMP FFmpegFB::Lock()
-{
- LogFlow(("FFmpeg::Lock: called\n"));
- int rc = RTCritSectEnter(&mCritSect);
- AssertRC(rc);
- if (rc == VINF_SUCCESS)
- return S_OK;
- return E_UNEXPECTED;
-}
-
-STDMETHODIMP FFmpegFB::Unlock()
-{
- LogFlow(("FFmpeg::Unlock: called\n"));
- RTCritSectLeave(&mCritSect);
- return S_OK;
-}
-
-
-/**
- * This method is used to notify us that an area of the guest framebuffer
- * has been updated.
- *
- * @returns COM status code
- * @param x X co-ordinate of the upper left-hand corner of the
- * area which has been updated
- * @param y Y co-ordinate of the upper left-hand corner of the
- * area which has been updated
- * @param w width of the area which has been updated
- * @param h height of the area which has been updated
- */
-STDMETHODIMP FFmpegFB::NotifyUpdate(ULONG x, ULONG y, ULONG w, ULONG h)
-{
- int rc;
- int64_t iCurrentTime = RTTimeMilliTS();
-
- LogFlow(("FFmpeg::NotifyUpdate called: x=%lu, y=%lu, w=%lu, h=%lu\n",
- (unsigned long) x, (unsigned long) y, (unsigned long) w,
- (unsigned long) h));
-
- /* We always leave at least one frame update pending, which we
- process when the time until the next frame has elapsed. */
- if (iCurrentTime - mLastTime >= 40)
- {
- rc = do_rgb_to_yuv_conversion();
- if (rc != S_OK)
- {
-#ifdef VBOX_WITH_VPX
- VideoRecCopyToIntBuffer(pVideoRecContext, x, y, w, h, mPixelFormat,
- mBitsPerPixel, mBytesPerLine, mFrameWidth,
- mFrameHeight, mGuestHeight, mGuestWidth,
- mBufferAddress, mTempRGBBuffer);
-#else
- copy_to_intermediate_buffer(x, y, w, h);
-#endif
- return rc;
- }
- rc = do_encoding_and_write();
- if (rc != S_OK)
- {
-#ifdef VBOX_WITH_VPX
- VideoRecCopyToIntBuffer(pVideoRecContext, x, y, w, h, mPixelFormat,
- mBitsPerPixel, mBytesPerLine, mFrameWidth,
- mFrameHeight, mGuestHeight, mGuestWidth,
- mBufferAddress, mTempRGBBuffer);
-#else
- copy_to_intermediate_buffer(x, y, w, h);
-#endif
-
- return rc;
- }
- mLastTime = mLastTime + 40;
- /* Write frames for the time in-between. Not a good way
- to handle this. */
- while (iCurrentTime - mLastTime >= 40)
- {
-/* rc = do_rgb_to_yuv_conversion();
- if (rc != S_OK)
- {
- copy_to_intermediate_buffer(x, y, w, h);
- return rc;
- }
-*/ rc = do_encoding_and_write();
- if (rc != S_OK)
- {
-#ifdef VBOX_WITH_VPX
- VideoRecCopyToIntBuffer(pVideoRecContext, x, y, w, h, mPixelFormat,
- mBitsPerPixel, mBytesPerLine, mFrameWidth,
- mFrameHeight, mGuestHeight, mGuestWidth,
- mBufferAddress, mTempRGBBuffer);
-#else
- copy_to_intermediate_buffer(x, y, w, h);
-#endif
- return rc;
- }
- mLastTime = mLastTime + 40;
- }
- }
- /* Finally we copy the updated data to the intermediate buffer,
- ready for the next update. */
-#ifdef VBOX_WITH_VPX
- VideoRecCopyToIntBuffer(pVideoRecContext, x, y, w, h, mPixelFormat,
- mBitsPerPixel, mBytesPerLine, mFrameWidth,
- mFrameHeight, mGuestHeight, mGuestWidth,
- mBufferAddress, mTempRGBBuffer);
-
-#else
- copy_to_intermediate_buffer(x, y, w, h);
-#endif
- return S_OK;
-}
-
-
-/**
- * Requests a resize of our "screen".
- *
- * @returns COM status code
- * @param pixelFormat Layout of the guest video RAM (i.e. 16, 24,
- * 32 bpp)
- * @param vram host context pointer to the guest video RAM,
- * in case we can cope with the format
- * @param bitsPerPixel color depth of the guest video RAM
- * @param bytesPerLine length of a screen line in the guest video RAM
- * @param w video mode width in pixels
- * @param h video mode height in pixels
- * @retval finished set to true if the method is synchronous and
- * to false otherwise
- *
- * This method is called when the guest attempts to resize the virtual
- * screen. The pointer to the guest's video RAM is supplied in case
- * the framebuffer can handle the pixel format. If it can't, it should
- * allocate a memory buffer itself, and the virtual VGA device will copy
- * the guest VRAM to that in a format we can handle. The
- * COMGETTER(UsesGuestVRAM) method is used to tell the VGA device which method
- * we have chosen, and the other COMGETTER methods tell the device about
- * the layout of our buffer. We currently handle all VRAM layouts except
- * FramebufferPixelFormat_Opaque (which cannot be handled by
- * definition).
- */
-STDMETHODIMP FFmpegFB::RequestResize(ULONG aScreenId, ULONG pixelFormat,
- BYTE *vram, ULONG bitsPerPixel,
- ULONG bytesPerLine,
- ULONG w, ULONG h, BOOL *finished)
-{
- NOREF(aScreenId);
- if (!finished)
- return E_POINTER;
- LogFlow(("FFmpeg::RequestResize called: pixelFormat=%lu, vram=%lu, "
- "bpp=%lu bpl=%lu, w=%lu, h=%lu\n",
- (unsigned long) pixelFormat, (unsigned long) vram,
- (unsigned long) bitsPerPixel, (unsigned long) bytesPerLine,
- (unsigned long) w, (unsigned long) h));
- /* For now, we are doing things synchronously */
- *finished = true;
-
- /* We always reallocate our buffer */
- if (mRGBBuffer)
- RTMemFree(mRGBBuffer);
- mGuestWidth = w;
- mGuestHeight = h;
-
- bool fallback = false;
-
- /* See if there are conditions under which we can use the guest's VRAM,
- * fallback to our own memory buffer otherwise */
-
- if (pixelFormat == FramebufferPixelFormat_FOURCC_RGB)
- {
- switch (bitsPerPixel)
- {
-#ifdef VBOX_WITH_VPX
- case 32:
- mFFMPEGPixelFormat = VPX_IMG_FMT_RGB32;
- Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB32\n"));
- break;
- case 24:
- mFFMPEGPixelFormat = VPX_IMG_FMT_RGB24;
- Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB24\n"));
- break;
- case 16:
- mFFMPEGPixelFormat = VPX_IMG_FMT_RGB565;
- Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB565\n"));
- break;
-#else
- case 32:
- mFFMPEGPixelFormat = PIX_FMT_RGBA32;
- Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to PIX_FMT_RGBA32\n"));
- break;
- case 24:
- mFFMPEGPixelFormat = PIX_FMT_RGB24;
- Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to PIX_FMT_RGB24\n"));
- break;
- case 16:
- mFFMPEGPixelFormat = PIX_FMT_RGB565;
- Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to PIX_FMT_RGB565\n"));
- break;
-#endif
- default:
- fallback = true;
- break;
- }
- }
- else
- {
- fallback = true;
- }
-
- if (!fallback)
- {
- mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
- mBufferAddress = reinterpret_cast<uint8_t *>(vram);
- mBytesPerLine = bytesPerLine;
- mBitsPerPixel = bitsPerPixel;
- mRGBBuffer = 0;
- Log2(("FFmpeg::RequestResize: setting mBufferAddress to vram and mLineSize to %lu\n",
- (unsigned long) mBytesPerLine));
- }
- else
- {
- /* we always fallback to 32bpp RGB */
- mPixelFormat = FramebufferPixelFormat_FOURCC_RGB;
-#ifdef VBOX_WITH_VPX
- mFFMPEGPixelFormat = VPX_IMG_FMT_RGB32;
- Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB32\n"));
-#else
- mFFMPEGPixelFormat = PIX_FMT_RGBA32;
- Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to PIX_FMT_RGBA32\n"));
-#endif
-
- mBytesPerLine = w * 4;
- mBitsPerPixel = 32;
- mRGBBuffer = reinterpret_cast<uint8_t *>(RTMemAlloc(mBytesPerLine * h));
- AssertReturn(mRGBBuffer != 0, E_OUTOFMEMORY);
- Log2(("FFmpeg::RequestResize: alloc'ing mBufferAddress and mRGBBuffer to %p and mBytesPerLine to %lu\n",
- mBufferAddress, (unsigned long) mBytesPerLine));
- mBufferAddress = mRGBBuffer;
- }
-
- /* Blank out the intermediate frame framebuffer */
- memset(mTempRGBBuffer, 0, mFrameWidth * mFrameHeight * 4);
- return S_OK;
-}
-
-/**
- * Returns whether we like the given video mode.
- *
- * @returns COM status code
- * @param width video mode width in pixels
- * @param height video mode height in pixels
- * @param bpp video mode bit depth in bits per pixel
- * @param supported pointer to result variable
- *
- * As far as I know, the only restriction we have on video modes is that
- * we have to have an even number of horizontal and vertical pixels.
- * I sincerely doubt that anything else will be requested, and if it
- * is anyway, we will just silently amputate one line when we write to
- * the mpeg file.
- */
-STDMETHODIMP FFmpegFB::VideoModeSupported(ULONG width, ULONG height,
- ULONG bpp, BOOL *supported)
-{
- if (!supported)
- return E_POINTER;
- *supported = true;
- return S_OK;
-}
-
-/** Stubbed */
-STDMETHODIMP FFmpegFB::GetVisibleRegion(BYTE *rectangles, ULONG /* count */, ULONG * /* countCopied */)
-{
- if (!rectangles)
- return E_POINTER;
- *rectangles = 0;
- return S_OK;
-}
-
-/** Stubbed */
-STDMETHODIMP FFmpegFB::SetVisibleRegion(BYTE *rectangles, ULONG /* count */)
-{
- if (!rectangles)
- return E_POINTER;
- return S_OK;
-}
-
-STDMETHODIMP FFmpegFB::ProcessVHWACommand(BYTE *pCommand)
-{
- return E_NOTIMPL;
-}
-// Private Methods
-//////////////////////////////////////////////////////////////////////////
-//
-#ifndef VBOX_WITH_VPX
-HRESULT FFmpegFB::setup_library()
-{
- /* Set up the avcodec library */
- avcodec_init();
- /* Register all codecs in the library. */
- avcodec_register_all();
- /* Register all formats in the format library */
- av_register_all();
- mpFormatContext = av_alloc_format_context();
- AssertReturn(mpFormatContext != 0, E_OUTOFMEMORY);
- mpStream = av_new_stream(mpFormatContext, 0);
- AssertReturn(mpStream != 0, E_UNEXPECTED);
- strncpy(mpFormatContext->filename, com::Utf8Str(mFileName).c_str(),
- sizeof(mpFormatContext->filename));
- return S_OK;
-}
-
-
-/**
- * Determine the correct output format and codec for our MPEG file.
- *
- * @returns COM status code
- *
- * @pre The format context (mpFormatContext) should have already been
- * allocated.
- */
-HRESULT FFmpegFB::setup_output_format()
-{
- Assert(mpFormatContext != 0);
- AVOutputFormat *pOutFormat = guess_format(0, com::Utf8Str(mFileName).c_str(),
- 0);
-# ifdef VBOX_SHOW_AVAILABLE_FORMATS
- if (!pOutFormat)
- {
- RTPrintf("Could not guess an output format for that extension.\n"
- "Available formats:\n");
- list_formats();
- }
-# endif
- AssertMsgReturn(pOutFormat != 0,
- ("Could not deduce output format from file name\n"),
- E_INVALIDARG);
- AssertMsgReturn((pOutFormat->flags & AVFMT_RAWPICTURE) == 0,
- ("Can't handle output format for file\n"),
- E_INVALIDARG);
- AssertMsgReturn((pOutFormat->flags & AVFMT_NOFILE) == 0,
- ("pOutFormat->flags=%x, pOutFormat->name=%s\n",
- pOutFormat->flags, pOutFormat->name), E_UNEXPECTED);
- AssertMsgReturn(pOutFormat->video_codec != CODEC_ID_NONE,
- ("No video codec available - you have probably selected a non-video file format\n"), E_UNEXPECTED);
- mpFormatContext->oformat = pOutFormat;
- /* Set format specific parameters - requires the format to be set. */
- int rcSetParam = av_set_parameters(mpFormatContext, 0);
- AssertReturn(rcSetParam >= 0, E_UNEXPECTED);
-# if 1 /* bird: This works for me on the mac, please review & test elsewhere. */
- /* Fill in any uninitialized parameters like opt_output_file in ffpmeg.c does.
- This fixes most of the buffer underflow warnings:
- http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/2005-June/001699.html */
- if (!mpFormatContext->preload)
- mpFormatContext->preload = (int)(0.5 * AV_TIME_BASE);
- if (!mpFormatContext->max_delay)
- mpFormatContext->max_delay = (int)(0.7 * AV_TIME_BASE);
-# endif
- return S_OK;
-}
-
-
-HRESULT FFmpegFB::list_formats()
-{
- AVCodec *codec;
- for (codec = first_avcodec; codec != NULL; codec = codec->next)
- {
- if (codec->type == CODEC_TYPE_VIDEO && codec->encode)
- {
- AVOutputFormat *ofmt;
- for (ofmt = first_oformat; ofmt != NULL; ofmt = ofmt->next)
- {
- if (ofmt->video_codec == codec->id)
- RTPrintf(" %20s: %20s => '%s'\n", codec->name, ofmt->extensions, ofmt->long_name);
- }
- }
- }
- return S_OK;
-}
-#endif
-
-#ifndef VBOX_WITH_VPX
-/**
- * Open the FFmpeg codec and set it up (width, etc) for our MPEG file.
- *
- * @returns COM status code
- *
- * @pre The format context (mpFormatContext) and the stream (mpStream)
- * should have already been allocated.
- */
-HRESULT FFmpegFB::open_codec()
-{
- Assert(mpFormatContext != 0);
- Assert(mpStream != 0);
- AVOutputFormat *pOutFormat = mpFormatContext->oformat;
- AVCodecContext *pCodecContext = mpStream->codec;
- AssertReturn(pCodecContext != 0, E_UNEXPECTED);
- AVCodec *pCodec = avcodec_find_encoder(pOutFormat->video_codec);
-# ifdef VBOX_SHOW_AVAILABLE_FORMATS
- if (!pCodec)
- {
- RTPrintf("Could not find a suitable codec for the output format on your system\n"
- "Available formats:\n");
- list_formats();
- }
-# endif
- AssertReturn(pCodec != 0, E_UNEXPECTED);
- pCodecContext->codec_id = pOutFormat->video_codec;
- pCodecContext->codec_type = CODEC_TYPE_VIDEO;
- pCodecContext->bit_rate = mBitRate;
- pCodecContext->width = mFrameWidth;
- pCodecContext->height = mFrameHeight;
- pCodecContext->time_base.den = 25;
- pCodecContext->time_base.num = 1;
- pCodecContext->gop_size = 12; /* at most one intra frame in 12 */
- pCodecContext->max_b_frames = 1;
- pCodecContext->pix_fmt = PIX_FMT_YUV420P;
- /* taken from the ffmpeg output example */
- // some formats want stream headers to be separate
- if (!strcmp(pOutFormat->name, "mp4")
- || !strcmp(pOutFormat->name, "mov")
- || !strcmp(pOutFormat->name, "3gp"))
- pCodecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;
- /* end output example section */
- int rcOpenCodec = avcodec_open(pCodecContext, pCodec);
- AssertReturn(rcOpenCodec >= 0, E_UNEXPECTED);
- return S_OK;
-}
-
-
-/**
- * Open our MPEG file and write the header.
- *
- * @returns COM status code
- *
- * @pre The format context (mpFormatContext) and the stream (mpStream)
- * should have already been allocated and set up.
- */
-HRESULT FFmpegFB::open_output_file()
-{
- char szFileName[RTPATH_MAX];
- Assert(mpFormatContext);
- Assert(mpFormatContext->oformat);
- strcpy(szFileName, com::Utf8Str(mFileName).c_str());
- int rcUrlFopen = url_fopen(&mpFormatContext->pb,
- szFileName, URL_WRONLY);
- AssertReturn(rcUrlFopen >= 0, E_UNEXPECTED);
- mfUrlOpen = true;
- av_write_header(mpFormatContext);
- return S_OK;
-}
-#endif
-
-/**
- * Copy an area from the output buffer used by the virtual VGA (may
- * just be the guest's VRAM) to our fixed size intermediate buffer.
- * The picture in the intermediate buffer is centred if the guest
- * screen dimensions are smaller and amputated if they are larger than
- * our frame dimensions.
- *
- * @param x X co-ordinate of the upper left-hand corner of the
- * area which has been updated
- * @param y Y co-ordinate of the upper left-hand corner of the
- * area which has been updated
- * @param w width of the area which has been updated
- * @param h height of the area which has been updated
- */
-void FFmpegFB::copy_to_intermediate_buffer(ULONG x, ULONG y, ULONG w, ULONG h)
-{
- Log2(("FFmpegFB::copy_to_intermediate_buffer: x=%lu, y=%lu, w=%lu, h=%lu\n",
- (unsigned long) x, (unsigned long) y, (unsigned long) w, (unsigned long) h));
- /* Perform clipping and calculate the destination co-ordinates */
- ULONG destX, destY, bpp;
- LONG xDiff = (LONG(mFrameWidth) - LONG(mGuestWidth)) / 2;
- LONG yDiff = (LONG(mFrameHeight) - LONG(mGuestHeight)) / 2;
- if (LONG(w) + xDiff + LONG(x) <= 0) /* nothing visible */
- return;
- if (LONG(x) < -xDiff)
- {
- w = LONG(w) + xDiff + x;
- x = -xDiff;
- destX = 0;
- }
- else
- destX = x + xDiff;
-
- if (LONG(h) + yDiff + LONG(y) <= 0) /* nothing visible */
- return;
- if (LONG(y) < -yDiff)
- {
- h = LONG(h) + yDiff + LONG(y);
- y = -yDiff;
- destY = 0;
- }
- else
- destY = y + yDiff;
- if (destX > mFrameWidth || destY > mFrameHeight)
- return; /* nothing visible */
- if (destX + w > mFrameWidth)
- w = mFrameWidth - destX;
- if (destY + h > mFrameHeight)
- h = mFrameHeight - destY;
- /* Calculate bytes per pixel */
- if (mPixelFormat == FramebufferPixelFormat_FOURCC_RGB)
- {
- switch (mBitsPerPixel)
- {
- case 32:
- case 24:
- case 16:
- bpp = mBitsPerPixel / 8;
- break;
- default:
- AssertMsgFailed(("Unknown color depth! mBitsPerPixel=%d\n", mBitsPerPixel));
- bpp = 1;
- break;
- }
- }
- else
- {
- AssertMsgFailed(("Unknown pixel format! mPixelFormat=%d\n", mPixelFormat));
- bpp = 1;
- }
- /* Calculate start offset in source and destination buffers */
- ULONG srcOffs = y * mBytesPerLine + x * bpp;
- ULONG destOffs = (destY * mFrameWidth + destX) * bpp;
- /* do the copy */
- for (unsigned int i = 0; i < h; i++)
- {
- /* Overflow check */
- Assert(srcOffs + w * bpp <= mGuestHeight * mBytesPerLine);
- Assert(destOffs + w * bpp <= mFrameHeight * mFrameWidth * bpp);
- memcpy(mTempRGBBuffer + destOffs, mBufferAddress + srcOffs,
- w * bpp);
- srcOffs = srcOffs + mBytesPerLine;
- destOffs = destOffs + mFrameWidth * bpp;
- }
-}
-
-
-/**
- * Copy the RGB data in the intermediate framebuffer to YUV data in
- * the YUV framebuffer.
- *
- * @returns COM status code
- */
-HRESULT FFmpegFB::do_rgb_to_yuv_conversion()
-{
- switch (mFFMPEGPixelFormat)
- {
-#ifdef VBOX_WITH_VPX
- case VPX_IMG_FMT_RGB32:
- if (!FFmpegWriteYUV420p<FFmpegBGRA32Iter>(mFrameWidth, mFrameHeight,
- mYUVBuffer, mTempRGBBuffer))
- return E_UNEXPECTED;
- break;
- case VPX_IMG_FMT_RGB24:
- if (!FFmpegWriteYUV420p<FFmpegBGR24Iter>(mFrameWidth, mFrameHeight,
- mYUVBuffer, mTempRGBBuffer))
- return E_UNEXPECTED;
- break;
- case VPX_IMG_FMT_RGB565:
- if (!FFmpegWriteYUV420p<FFmpegBGR565Iter>(mFrameWidth, mFrameHeight,
- mYUVBuffer, mTempRGBBuffer))
- return E_UNEXPECTED;
- break;
-#else
- case PIX_FMT_RGBA32:
- if (!FFmpegWriteYUV420p<FFmpegBGRA32Iter>(mFrameWidth, mFrameHeight,
- mYUVBuffer, mTempRGBBuffer))
- return E_UNEXPECTED;
- break;
- case PIX_FMT_RGB24:
- if (!FFmpegWriteYUV420p<FFmpegBGR24Iter>(mFrameWidth, mFrameHeight,
- mYUVBuffer, mTempRGBBuffer))
- return E_UNEXPECTED;
- break;
- case PIX_FMT_RGB565:
- if (!FFmpegWriteYUV420p<FFmpegBGR565Iter>(mFrameWidth, mFrameHeight,
- mYUVBuffer, mTempRGBBuffer))
- return E_UNEXPECTED;
- break;
-
-#endif
- default:
- return E_UNEXPECTED;
- }
- return S_OK;
-}
-
-/**
- * Encode the YUV framebuffer as an MPEG frame and write it to the file.
- *
- * @returns COM status code
- */
-HRESULT FFmpegFB::do_encoding_and_write()
-{
-
-
- /* A hack: ffmpeg mpeg2 only writes a frame if something has
- changed. So we flip the low luminance bit of the first
- pixel every frame. */
- if (mToggle)
- mYUVBuffer[0] |= 1;
- else
- mYUVBuffer[0] &= 0xfe;
- mToggle = !mToggle;
-
-#ifdef VBOX_WITH_VPX
- VideoRecEncodeAndWrite(pVideoRecContext, mFrameWidth, mFrameHeight, mYUVBuffer);
-#else
- AVCodecContext *pContext = mpStream->codec;
- int cSize = avcodec_encode_video(pContext, mOutBuf, mYUVFrameSize * 2,
- mFrame);
- AssertMsgReturn(cSize >= 0,
- ("avcodec_encode_video() failed with rc=%d.\n"
- "mFrameWidth=%u, mFrameHeight=%u\n", cSize,
- mFrameWidth, mFrameHeight), E_UNEXPECTED);
- if (cSize > 0)
- {
- AVPacket Packet;
- av_init_packet(&Packet);
- Packet.pts = av_rescale_q(pContext->coded_frame->pts,
- pContext->time_base,
- mpStream->time_base);
- if(pContext->coded_frame->key_frame)
- Packet.flags |= PKT_FLAG_KEY;
- Packet.stream_index = mpStream->index;
- Packet.data = mOutBuf;
- Packet.size = cSize;
-
- /* write the compressed frame in the media file */
- int rcWriteFrame = av_write_frame(mpFormatContext, &Packet);
- AssertReturn(rcWriteFrame == 0, E_UNEXPECTED);
- }
-#endif
- return S_OK;
-}
-
-#ifndef VBOX_WITH_VPX
-/**
- * Capture the current (i.e. the last) frame as a PNG file with the
- * same basename as the captured video file.
- */
-HRESULT FFmpegFB::write_png()
-{
- HRESULT errorCode = E_OUTOFMEMORY;
- png_bytep *row_pointers;
- char PNGFileName[RTPATH_MAX], oldName[RTPATH_MAX];
- png_structp png_ptr;
- png_infop info_ptr;
- uint8_t *PNGBuffer;
- /* Work out the new file name - for some reason, we can't use
- the com::Utf8Str() directly, but have to copy it */
- strcpy(oldName, com::Utf8Str(mFileName).c_str());
- int baseLen = strrchr(oldName, '.') - oldName;
- if (baseLen == 0)
- baseLen = strlen(oldName);
- if (baseLen >= RTPATH_MAX - 5) /* for whatever reason */
- baseLen = RTPATH_MAX - 5;
- memcpy(&PNGFileName[0], oldName, baseLen);
- PNGFileName[baseLen] = '.';
- PNGFileName[baseLen + 1] = 'p';
- PNGFileName[baseLen + 2] = 'n';
- PNGFileName[baseLen + 3] = 'g';
- PNGFileName[baseLen + 4] = 0;
- /* Open output file */
- FILE *fp = fopen(PNGFileName, "wb");
- if (fp == 0)
- {
- errorCode = E_UNEXPECTED;
- goto fopen_failed;
- }
- /* Create libpng basic structures */
- png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
- 0 /* error function */, 0 /* warning function */);
- if (png_ptr == 0)
- goto png_create_write_struct_failed;
- info_ptr = png_create_info_struct(png_ptr);
- if (info_ptr == 0)
- {
- png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
- goto png_create_info_struct_failed;
- }
- /* Convert image to standard RGB24 to simplify life */
- PNGBuffer = reinterpret_cast<uint8_t *>(av_malloc(mFrameWidth
- * mFrameHeight * 4));
- if (PNGBuffer == 0)
- goto av_malloc_buffer_failed;
- row_pointers =
- reinterpret_cast<png_bytep *>(av_malloc(mFrameHeight
- * sizeof(png_bytep)));
- if (row_pointers == 0)
- goto av_malloc_pointers_failed;
- switch (mFFMPEGPixelFormat)
- {
- case PIX_FMT_RGBA32:
- if (!FFmpegWriteRGB24<FFmpegBGRA32Iter>(mFrameWidth, mFrameHeight,
- PNGBuffer, mTempRGBBuffer))
- goto setjmp_exception;
- break;
- case PIX_FMT_RGB24:
- if (!FFmpegWriteRGB24<FFmpegBGR24Iter>(mFrameWidth, mFrameHeight,
- PNGBuffer, mTempRGBBuffer))
- goto setjmp_exception;
- break;
- case PIX_FMT_RGB565:
- if (!FFmpegWriteRGB24<FFmpegBGR565Iter>(mFrameWidth, mFrameHeight,
- PNGBuffer, mTempRGBBuffer))
- goto setjmp_exception;
- break;
- default:
- goto setjmp_exception;
- }
- /* libpng exception handling */
- if (setjmp(png_jmpbuf(png_ptr)))
- goto setjmp_exception;
- /* pass libpng the file pointer */
- png_init_io(png_ptr, fp);
- /* set the image properties */
- png_set_IHDR(png_ptr, info_ptr, mFrameWidth, mFrameHeight,
- 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
- /* set up the information about the bitmap for libpng */
- row_pointers[0] = png_bytep(PNGBuffer);
- for (unsigned i = 1; i < mFrameHeight; i++)
- row_pointers[i] = row_pointers[i - 1] + mFrameWidth * 3;
- png_set_rows(png_ptr, info_ptr, &row_pointers[0]);
- /* and write the thing! */
- png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0);
- /* drop through to cleanup */
- errorCode = S_OK;
-setjmp_exception:
- av_free(row_pointers);
-av_malloc_pointers_failed:
- av_free(PNGBuffer);
-av_malloc_buffer_failed:
- png_destroy_write_struct(&png_ptr, &info_ptr);
-png_create_info_struct_failed:
-png_create_write_struct_failed:
- fclose(fp);
-fopen_failed:
- if (errorCode != S_OK)
- Log(("FFmpegFB::write_png: Failed to write .png image of final frame\n"));
- return errorCode;
-}
-#endif
-
-#ifdef VBOX_WITH_XPCOM
-NS_DECL_CLASSINFO(FFmpegFB)
-NS_IMPL_THREADSAFE_ISUPPORTS1_CI(FFmpegFB, IFramebuffer)
-#endif
diff --git a/src/VBox/Frontends/VBoxHeadless/VideoCapture/FFmpegFB.h b/src/VBox/Frontends/VBoxHeadless/VideoCapture/FFmpegFB.h
deleted file mode 100644
index a3f9bdc0..00000000
--- a/src/VBox/Frontends/VBoxHeadless/VideoCapture/FFmpegFB.h
+++ /dev/null
@@ -1,458 +0,0 @@
-/** @file
- *
- * VBox Remote Desktop Protocol.
- * FFmpeg framebuffer interface.
- */
-
-/*
- * Copyright (C) 2006-2012 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef _H_FFMPEGFB
-#define _H_FFMPEGFB
-
-#include <VBox/com/VirtualBox.h>
-#include <iprt/uuid.h>
-
-#include <VBox/com/com.h>
-#include <VBox/com/string.h>
-
-#include <iprt/initterm.h>
-#include <iprt/critsect.h>
-
-#ifdef VBOX_WITH_VPX
-#include "EbmlWriter.h"
-#include "EncodeAndWrite.h"
-#include <stdarg.h>
-#include <string.h>
-#define VPX_CODEC_DISABLE_COMPAT 1
-#include <vp8cx.h>
-#include <vpx_image.h>
-#include <vpx_mem.h>
-#define interface (vpx_codec_vp8_cx())
-#else
-# ifdef DEBUG
-# define VBOX_DEBUG_FF DEBUG
-# include <avcodec.h>
-# include <avformat.h>
-# undef DEBUG
-# define DEBUG VBOX_DEBUG_FF
-# else /* DEBUG not defined */
-# include <avcodec.h>
-# include <avformat.h>
-# endif /* DEBUG not defined */
-#endif
-
-#ifdef VBOX_WITH_VPX
-PVIDEORECCONTEXT pVideoRecContext;
-#endif
-
-class FFmpegFB : VBOX_SCRIPTABLE_IMPL(IFramebuffer)
-{
-public:
- FFmpegFB(ULONG width, ULONG height, ULONG bitrate, com::Bstr filename);
- virtual ~FFmpegFB();
-
-#ifndef VBOX_WITH_XPCOM
- STDMETHOD_(ULONG, AddRef)()
- {
- return ::InterlockedIncrement (&refcnt);
- }
- STDMETHOD_(ULONG, Release)()
- {
- long cnt = ::InterlockedDecrement (&refcnt);
- if (cnt == 0)
- delete this;
- return cnt;
- }
-#endif
- VBOX_SCRIPTABLE_DISPATCH_IMPL(IFramebuffer)
-
- NS_DECL_ISUPPORTS
-
- // public methods only for internal purposes
- HRESULT init ();
-
- STDMETHOD(COMGETTER(Width))(ULONG *width);
- STDMETHOD(COMGETTER(Height))(ULONG *height);
- STDMETHOD(Lock)();
- STDMETHOD(Unlock)();
- STDMETHOD(COMGETTER(Address))(BYTE **address);
- STDMETHOD(COMGETTER(BitsPerPixel))(ULONG *bitsPerPixel);
- STDMETHOD(COMGETTER(BytesPerLine))(ULONG *bytesPerLine);
- STDMETHOD(COMGETTER(PixelFormat)) (ULONG *pixelFormat);
- STDMETHOD(COMGETTER(UsesGuestVRAM)) (BOOL *usesGuestVRAM);
- STDMETHOD(COMGETTER(HeightReduction)) (ULONG *heightReduction);
- STDMETHOD(COMGETTER(Overlay)) (IFramebufferOverlay **aOverlay);
- STDMETHOD(COMGETTER(WinId)) (LONG64 *winId);
-
- STDMETHOD(NotifyUpdate)(ULONG x, ULONG y, ULONG w, ULONG h);
- STDMETHOD(RequestResize)(ULONG aScreenId, ULONG pixelFormat, BYTE *vram,
- ULONG bitsPerPixel, ULONG bytesPerLine,
- ULONG w, ULONG h, BOOL *finished);
- STDMETHOD(VideoModeSupported)(ULONG width, ULONG height, ULONG bpp, BOOL *supported);
- STDMETHOD(GetVisibleRegion)(BYTE *rectangles, ULONG count, ULONG *countCopied);
- STDMETHOD(SetVisibleRegion)(BYTE *rectangles, ULONG count);
-
- STDMETHOD(ProcessVHWACommand)(BYTE *pCommand);
-public:
-private:
-#ifdef VBOX_WITH_VPX
- EbmlGlobal ebml;
- vpx_codec_ctx_t mVpxCodec;
- vpx_codec_enc_cfg_t mVpxConfig;
- FILE * mOutputFile;
- unsigned long mDuration;
- uint32_t mFrameCount;
-
-#else
- /** Pointer to ffmpeg's format information context */
- AVFormatContext *mpFormatContext;
- /** ffmpeg context containing information about the stream */
- AVStream *mpStream;
- /** Information for ffmpeg describing the current frame */
- AVFrame *mFrame;
-
- HRESULT setup_library();
- HRESULT setup_output_format();
- HRESULT list_formats();
-#endif
- /** true if url_fopen actually succeeded */
- bool mfUrlOpen;
- /** Guest framebuffer width */
- ULONG mGuestWidth;
- /** Guest framebuffer height */
- ULONG mGuestHeight;
- /** Bit rate used for encoding */
- ULONG mBitRate;
- /** Guest framebuffer pixel format */
- ULONG mPixelFormat;
- /** Guest framebuffer color depth */
- ULONG mBitsPerPixel;
- /** Name of the file we will write to */
- com::Bstr mFileName;
- /** Guest framebuffer line length */
- ULONG mBytesPerLine;
- /** MPEG frame framebuffer width */
- ULONG mFrameWidth;
- /** MPEG frame framebuffer height */
- ULONG mFrameHeight;
- /** The size of one YUV frame */
- ULONG mYUVFrameSize;
- /** If we can't use the video RAM directly, we allocate our own
- * buffer */
- uint8_t *mRGBBuffer;
- /** The address of the buffer - can be either mRGBBuffer or the
- * guests VRAM (HC address) if we can handle that directly */
- uint8_t *mBufferAddress;
- /** An intermediary RGB buffer with the same dimensions */
- uint8_t *mTempRGBBuffer;
- /** Frame buffer translated into YUV420 for the mpeg codec */
- uint8_t *mYUVBuffer;
- /** Temporary buffer into which the codec writes frames to be
- * written into the file */
- uint8_t *mOutBuf;
- RTCRITSECT mCritSect;
- /** File where we store the mpeg stream */
- RTFILE mFile;
- /** time at which the last "real" frame was created */
- int64_t mLastTime;
- /** ffmpeg pixel format of guest framebuffer */
- int mFFMPEGPixelFormat;
- /** Since we are building without exception support, we use this
- to signal allocation failure in the constructor */
- bool mOutOfMemory;
- /** A hack: ffmpeg mpeg2 only writes a frame if something has
- changed. So we flip the low luminance bit of the first
- pixel every frame. */
- bool mToggle;
-
-
- HRESULT open_codec();
- HRESULT open_output_file();
- void copy_to_intermediate_buffer(ULONG x, ULONG y, ULONG w, ULONG h);
- HRESULT do_rgb_to_yuv_conversion();
- HRESULT do_encoding_and_write();
- HRESULT write_png();
-#ifndef VBOX_WITH_XPCOM
- long refcnt;
-#endif
-};
-
-/**
- * Iterator class for running through an BGRA32 image buffer and converting
- * it to RGB.
- */
-class FFmpegBGRA32Iter
-{
-private:
- enum { PIX_SIZE = 4 };
-public:
- FFmpegBGRA32Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuffer)
- {
- mPos = 0;
- mSize = aWidth * aHeight * PIX_SIZE;
- mBuffer = aBuffer;
- }
- /**
- * Convert the next pixel to RGB.
- * @returns true on success, false if we have reached the end of the buffer
- * @param aRed where to store the red value
- * @param aGreen where to store the green value
- * @param aBlue where to store the blue value
- */
- bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue)
- {
- bool rc = false;
- if (mPos + PIX_SIZE <= mSize)
- {
- *aRed = mBuffer[mPos + 2];
- *aGreen = mBuffer[mPos + 1];
- *aBlue = mBuffer[mPos];
- mPos += PIX_SIZE;
- rc = true;
- }
- return rc;
- }
-
- /**
- * Skip forward by a certain number of pixels
- * @param aPixels how many pixels to skip
- */
- void skip(unsigned aPixels)
- {
- mPos += PIX_SIZE * aPixels;
- }
-private:
- /** Size of the picture buffer */
- unsigned mSize;
- /** Current position in the picture buffer */
- unsigned mPos;
- /** Address of the picture buffer */
- uint8_t *mBuffer;
-};
-
-/**
- * Iterator class for running through an BGR24 image buffer and converting
- * it to RGB.
- */
-class FFmpegBGR24Iter
-{
-private:
- enum { PIX_SIZE = 3 };
-public:
- FFmpegBGR24Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuffer)
- {
- mPos = 0;
- mSize = aWidth * aHeight * PIX_SIZE;
- mBuffer = aBuffer;
- }
- /**
- * Convert the next pixel to RGB.
- * @returns true on success, false if we have reached the end of the buffer
- * @param aRed where to store the red value
- * @param aGreen where to store the green value
- * @param aBlue where to store the blue value
- */
- bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue)
- {
- bool rc = false;
- if (mPos + PIX_SIZE <= mSize)
- {
- *aRed = mBuffer[mPos + 2];
- *aGreen = mBuffer[mPos + 1];
- *aBlue = mBuffer[mPos];
- mPos += PIX_SIZE;
- rc = true;
- }
- return rc;
- }
-
- /**
- * Skip forward by a certain number of pixels
- * @param aPixels how many pixels to skip
- */
- void skip(unsigned aPixels)
- {
- mPos += PIX_SIZE * aPixels;
- }
-private:
- /** Size of the picture buffer */
- unsigned mSize;
- /** Current position in the picture buffer */
- unsigned mPos;
- /** Address of the picture buffer */
- uint8_t *mBuffer;
-};
-
-/**
- * Iterator class for running through an BGR565 image buffer and converting
- * it to RGB.
- */
-class FFmpegBGR565Iter
-{
-private:
- enum { PIX_SIZE = 2 };
-public:
- FFmpegBGR565Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuffer)
- {
- mPos = 0;
- mSize = aWidth * aHeight * PIX_SIZE;
- mBuffer = aBuffer;
- }
- /**
- * Convert the next pixel to RGB.
- * @returns true on success, false if we have reached the end of the buffer
- * @param aRed where to store the red value
- * @param aGreen where to store the green value
- * @param aBlue where to store the blue value
- */
- bool getRGB(unsigned *aRed, unsigned *aGreen, unsigned *aBlue)
- {
- bool rc = false;
- if (mPos + PIX_SIZE <= mSize)
- {
- unsigned uFull = (((unsigned) mBuffer[mPos + 1]) << 8)
- | ((unsigned) mBuffer[mPos]);
- *aRed = (uFull >> 8) & ~7;
- *aGreen = (uFull >> 3) & ~3 & 0xff;
- *aBlue = (uFull << 3) & ~7 & 0xff;
- mPos += PIX_SIZE;
- rc = true;
- }
- return rc;
- }
-
- /**
- * Skip forward by a certain number of pixels
- * @param aPixels how many pixels to skip
- */
- void skip(unsigned aPixels)
- {
- mPos += PIX_SIZE * aPixels;
- }
-private:
- /** Size of the picture buffer */
- unsigned mSize;
- /** Current position in the picture buffer */
- unsigned mPos;
- /** Address of the picture buffer */
- uint8_t *mBuffer;
-};
-
-
-/**
- * Convert an image to YUV420p format
- * @returns true on success, false on failure
- * @param aWidth width of image
- * @param aHeight height of image
- * @param aDestBuf an allocated memory buffer large enough to hold the
- * destination image (i.e. width * height * 12bits)
- * @param aSrcBuf the source image as an array of bytes
- */
-template <class T>
-inline bool FFmpegWriteYUV420p(unsigned aWidth, unsigned aHeight, uint8_t *aDestBuf,
- uint8_t *aSrcBuf)
-{
- AssertReturn(0 == (aWidth & 1), false);
- AssertReturn(0 == (aHeight & 1), false);
- bool rc = true;
- T iter1(aWidth, aHeight, aSrcBuf);
- T iter2 = iter1;
- iter2.skip(aWidth);
- unsigned cPixels = aWidth * aHeight;
- unsigned offY = 0;
- unsigned offU = cPixels;
- unsigned offV = cPixels + cPixels / 4;
- for (unsigned i = 0; (i < aHeight / 2) && rc; ++i)
- {
- for (unsigned j = 0; (j < aWidth / 2) && rc; ++j)
- {
- unsigned red, green, blue, u, v;
- rc = iter1.getRGB(&red, &green, &blue);
- if (rc)
- {
- aDestBuf[offY] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
- u = (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
- v = (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
- rc = iter1.getRGB(&red, &green, &blue);
- }
- if (rc)
- {
- aDestBuf[offY + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
- u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
- v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
- rc = iter2.getRGB(&red, &green, &blue);
- }
- if (rc)
- {
- aDestBuf[offY + aWidth] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
- u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
- v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
- rc = iter2.getRGB(&red, &green, &blue);
- }
- if (rc)
- {
- aDestBuf[offY + aWidth + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
- u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
- v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4;
- aDestBuf[offU] = u;
- aDestBuf[offV] = v;
- offY += 2;
- ++offU;
- ++offV;
- }
- }
- if (rc)
- {
- iter1.skip(aWidth);
- iter2.skip(aWidth);
- offY += aWidth;
- }
- }
- return rc;
-}
-
-
-/**
- * Convert an image to RGB24 format
- * @returns true on success, false on failure
- * @param aWidth width of image
- * @param aHeight height of image
- * @param aDestBuf an allocated memory buffer large enough to hold the
- * destination image (i.e. width * height * 12bits)
- * @param aSrcBuf the source image as an array of bytes
- */
-template <class T>
-inline bool FFmpegWriteRGB24(unsigned aWidth, unsigned aHeight, uint8_t *aDestBuf,
- uint8_t *aSrcBuf)
-{
- enum { PIX_SIZE = 3 };
- bool rc = true;
- AssertReturn(0 == (aWidth & 1), false);
- AssertReturn(0 == (aHeight & 1), false);
- T iter(aWidth, aHeight, aSrcBuf);
- unsigned cPixels = aWidth * aHeight;
- for (unsigned i = 0; (i < cPixels) && rc; ++i)
- {
- unsigned red, green, blue;
- rc = iter.getRGB(&red, &green, &blue);
- if (rc)
- {
- aDestBuf[i * PIX_SIZE] = red;
- aDestBuf[i * PIX_SIZE + 1] = green;
- aDestBuf[i * PIX_SIZE + 2] = blue;
- }
- }
- return rc;
-}
-
-#endif /* !_H_FFMPEGFB */
diff --git a/src/VBox/Frontends/VBoxHeadless/VideoCapture/Makefile.kmk b/src/VBox/Frontends/VBoxHeadless/VideoCapture/Makefile.kmk
deleted file mode 100644
index 88a39325..00000000
--- a/src/VBox/Frontends/VBoxHeadless/VideoCapture/Makefile.kmk
+++ /dev/null
@@ -1,32 +0,0 @@
-# $Id: Makefile.kmk $
-## @file
-# Sub-Makefile for the ffmpeg frame buffer module.
-#
-
-#
-# Copyright (C) 2006-2012 Oracle Corporation
-#
-# This file is part of VirtualBox Open Source Edition (OSE), as
-# available from http://www.virtualbox.org. This file is free software;
-# you can redistribute it and/or modify it under the terms of the GNU
-# General Public License (GPL) as published by the Free Software
-# Foundation, in version 2 as it comes in the "COPYING" file of the
-# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
-# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
-#
-
-SUB_DEPTH = ../../../../..
-include $(KBUILD_PATH)/subheader.kmk
-
-DLLS += VBoxVideoRecFB
-VBoxVideoRecFB_TEMPLATE = VBOXMAINCLIENTDLL
-
-VBoxVideoRecFB_SDKS = VBOX_FFMPEG VBOX_LIBPNG VBOX_ZLIB
-
-VBoxVideoRecFB_SOURCES += \
- VideoRecFB.cpp
-
-VBoxVideoRecFB_CXXFLAGS.linux += -fPIC
-
-include $(FILE_KBUILD_SUB_FOOTER)
-