summaryrefslogtreecommitdiff
path: root/src/VBox/Frontends/VBoxHeadless
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
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')
-rw-r--r--src/VBox/Frontends/VBoxHeadless/Framebuffer.cpp5
-rw-r--r--src/VBox/Frontends/VBoxHeadless/Framebuffer.h3
-rw-r--r--src/VBox/Frontends/VBoxHeadless/Makefile.kmk5
-rw-r--r--src/VBox/Frontends/VBoxHeadless/NullFramebuffer.h7
-rw-r--r--src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp211
-rw-r--r--src/VBox/Frontends/VBoxHeadless/VBoxHeadless.h2
-rw-r--r--src/VBox/Frontends/VBoxHeadless/VBoxHeadlessHardened.cpp2
-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
-rw-r--r--src/VBox/Frontends/VBoxHeadless/testcase/Makefile.kmk2
-rw-r--r--src/VBox/Frontends/VBoxHeadless/testcase/tstHeadless.cpp96
12 files changed, 192 insertions, 1854 deletions
diff --git a/src/VBox/Frontends/VBoxHeadless/Framebuffer.cpp b/src/VBox/Frontends/VBoxHeadless/Framebuffer.cpp
index 96f2d65f..c30e61f1 100644
--- a/src/VBox/Frontends/VBoxHeadless/Framebuffer.cpp
+++ b/src/VBox/Frontends/VBoxHeadless/Framebuffer.cpp
@@ -293,3 +293,8 @@ STDMETHODIMP VRDPFramebuffer::ProcessVHWACommand(BYTE *pCommand)
{
return E_NOTIMPL;
}
+
+STDMETHODIMP VRDPFramebuffer::Notify3DEvent(ULONG uType, BYTE *pReserved)
+{
+ return E_NOTIMPL;
+}
diff --git a/src/VBox/Frontends/VBoxHeadless/Framebuffer.h b/src/VBox/Frontends/VBoxHeadless/Framebuffer.h
index 525852c3..58384ac1 100644
--- a/src/VBox/Frontends/VBoxHeadless/Framebuffer.h
+++ b/src/VBox/Frontends/VBoxHeadless/Framebuffer.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-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;
@@ -69,6 +69,7 @@ public:
STDMETHOD(ProcessVHWACommand)(BYTE *pCommand);
+ STDMETHOD(Notify3DEvent)(ULONG uType, BYTE *pReserved);
private:
/* If the format is Opaque, then internal memory buffer is used.
* Otherwise guest VRAM is used directly.
diff --git a/src/VBox/Frontends/VBoxHeadless/Makefile.kmk b/src/VBox/Frontends/VBoxHeadless/Makefile.kmk
index 1bf2aa20..8cae020a 100644
--- a/src/VBox/Frontends/VBoxHeadless/Makefile.kmk
+++ b/src/VBox/Frontends/VBoxHeadless/Makefile.kmk
@@ -19,9 +19,6 @@ SUB_DEPTH = ../../../..
include $(KBUILD_PATH)/subheader.kmk
include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk
-ifdef VBOX_WITH_FFMPEG
- include $(PATH_SUB_CURRENT)/VideoCapture/Makefile.kmk
-endif
#
# Targets.
@@ -47,7 +44,7 @@ VBoxHeadlessHardened_NAME = VBoxHeadless
#
VBoxHeadless_TEMPLATE := $(if $(VBOX_WITH_HARDENING),VBOXMAINCLIENTDLL,VBOXMAINCLIENTEXE)
VBoxHeadless_DEFS += \
- VBOX_WITH_VIDEO_REC
+ VBOX_WITH_VIDEO_REC
VBoxHeadless_SOURCES = VBoxHeadless.cpp
VBoxHeadless_SOURCES += Framebuffer.cpp
ifdef VBOX_WITH_GUEST_PROPS
diff --git a/src/VBox/Frontends/VBoxHeadless/NullFramebuffer.h b/src/VBox/Frontends/VBoxHeadless/NullFramebuffer.h
index 2c082234..346add4a 100644
--- a/src/VBox/Frontends/VBoxHeadless/NullFramebuffer.h
+++ b/src/VBox/Frontends/VBoxHeadless/NullFramebuffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Oracle Corporation
+ * Copyright (C) 2010-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;
@@ -205,6 +205,11 @@ public:
return E_NOTIMPL;
}
+ STDMETHOD(Notify3DEvent)(ULONG uType, BYTE *pReserved)
+ {
+ return E_NOTIMPL;
+ }
+
private:
/** Guest framebuffer pixel format */
ULONG mPixelFormat;
diff --git a/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp b/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp
index 4a6d62f5..bca3b245 100644
--- a/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp
+++ b/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp
@@ -21,7 +21,7 @@
#include <VBox/com/Guid.h>
#include <VBox/com/ErrorInfo.h>
#include <VBox/com/errorprint.h>
-#include <VBox/com/EventQueue.h>
+#include <VBox/com/NativeEventQueue.h>
#include <VBox/com/VirtualBox.h>
#include <VBox/com/listeners.h>
@@ -73,7 +73,7 @@ using namespace com;
/* global weak references (for event handlers) */
static IConsole *gConsole = NULL;
-static EventQueue *gEventQ = NULL;
+static NativeEventQueue *gEventQ = NULL;
/* flag whether frontend should terminate */
static volatile bool g_fTerminateFE = false;
@@ -164,93 +164,129 @@ public:
{
case VBoxEventType_OnGuestPropertyChanged:
{
- ComPtr<IGuestPropertyChangedEvent> gpcev = aEvent;
- Assert(gpcev);
+ ComPtr<IGuestPropertyChangedEvent> pChangedEvent = aEvent;
+ Assert(pChangedEvent);
- Bstr aKey;
- gpcev->COMGETTER(Name)(aKey.asOutParam());
+ HRESULT hrc;
- if (aKey == Bstr("/VirtualBox/GuestInfo/OS/NoLoggedInUsers"))
+ ComPtr <IMachine> pMachine;
+ if (gConsole)
{
- /* Check if this is our machine and the "disconnect on logout feature" is enabled. */
- BOOL fProcessDisconnectOnGuestLogout = FALSE;
- ComPtr <IMachine> machine;
- HRESULT hrc = S_OK;
-
- if (gConsole)
+ hrc = gConsole->COMGETTER(Machine)(pMachine.asOutParam());
+ if (SUCCEEDED(hrc) && pMachine)
{
- hrc = gConsole->COMGETTER(Machine)(machine.asOutParam());
- if (SUCCEEDED(hrc) && machine)
- {
- Bstr id, machineId;
- hrc = machine->COMGETTER(Id)(id.asOutParam());
- gpcev->COMGETTER(MachineId)(machineId.asOutParam());
- if (id == machineId)
- {
- Bstr value1;
- hrc = machine->GetExtraData(Bstr("VRDP/DisconnectOnGuestLogout").raw(),
- value1.asOutParam());
- if (SUCCEEDED(hrc) && value1 == "1")
- {
- fProcessDisconnectOnGuestLogout = TRUE;
- }
- }
- }
+ Bstr gpMachineId, machineId;
+ hrc = pMachine->COMGETTER(Id)(gpMachineId.asOutParam());
+ AssertComRC(hrc);
+ hrc = pChangedEvent->COMGETTER(MachineId)(machineId.asOutParam());
+ AssertComRC(hrc);
+ if (gpMachineId != machineId)
+ hrc = VBOX_E_OBJECT_NOT_FOUND;
}
+ }
+ else
+ hrc = VBOX_E_INVALID_VM_STATE;
+
+ if (SUCCEEDED(hrc))
+ {
+ Bstr strKey;
+ hrc = pChangedEvent->COMGETTER(Name)(strKey.asOutParam());
+ AssertComRC(hrc);
+
+ Bstr strValue;
+ hrc = pChangedEvent->COMGETTER(Value)(strValue.asOutParam());
+ AssertComRC(hrc);
- if (fProcessDisconnectOnGuestLogout)
+ Utf8Str utf8Key = strKey;
+ Utf8Str utf8Value = strValue;
+ LogRelFlow(("Guest property \"%s\" has been changed to \"%s\"\n",
+ utf8Key.c_str(), utf8Value.c_str()));
+
+ if (utf8Key.equals("/VirtualBox/GuestInfo/OS/NoLoggedInUsers"))
{
- bool fDropConnection = false;
+ LogRelFlow(("Guest indicates that there %s logged in users\n",
+ utf8Value.equals("true") ? "are no" : "are"));
- Bstr value;
- gpcev->COMGETTER(Value)(value.asOutParam());
- Utf8Str utf8Value = value;
+ /* Check if this is our machine and the "disconnect on logout feature" is enabled. */
+ BOOL fProcessDisconnectOnGuestLogout = FALSE;
- if (!mfNoLoggedInUsers) /* Only if the property really changes. */
+ /* Does the machine handle VRDP disconnects? */
+ Bstr strDiscon;
+ hrc = pMachine->GetExtraData(Bstr("VRDP/DisconnectOnGuestLogout").raw(),
+ strDiscon.asOutParam());
+ if (SUCCEEDED(hrc))
{
- if ( utf8Value == "true"
- /* Guest property got deleted due to reset,
- * so it has no value anymore. */
- || utf8Value.isEmpty())
- {
- mfNoLoggedInUsers = true;
- fDropConnection = true;
- }
+ Utf8Str utf8Discon = strDiscon;
+ fProcessDisconnectOnGuestLogout = utf8Discon.equals("1")
+ ? TRUE : FALSE;
}
- else if (utf8Value == "false")
- mfNoLoggedInUsers = false;
- /* Guest property got deleted due to reset,
- * take the shortcut without touching the mfNoLoggedInUsers
- * state. */
- else if (utf8Value.isEmpty())
- fDropConnection = true;
-
- if (fDropConnection)
+
+ LogRelFlow(("VRDE: hrc=%Rhrc: Host %s disconnecting clients (current host state known: %s)\n",
+ hrc, fProcessDisconnectOnGuestLogout ? "will handle" : "does not handle",
+ mfNoLoggedInUsers ? "No users logged in" : "Users logged in"));
+
+ if (fProcessDisconnectOnGuestLogout)
{
- /* If there is a connection, drop it. */
- ComPtr<IVRDEServerInfo> info;
- hrc = gConsole->COMGETTER(VRDEServerInfo)(info.asOutParam());
- if (SUCCEEDED(hrc) && info)
+ bool fDropConnection = false;
+ if (!mfNoLoggedInUsers) /* Only if the property really changes. */
+ {
+ if ( utf8Value == "true"
+ /* Guest property got deleted due to reset,
+ * so it has no value anymore. */
+ || utf8Value.isEmpty())
+ {
+ mfNoLoggedInUsers = true;
+ fDropConnection = true;
+ }
+ }
+ else if (utf8Value == "false")
+ mfNoLoggedInUsers = false;
+ /* Guest property got deleted due to reset,
+ * take the shortcut without touching the mfNoLoggedInUsers
+ * state. */
+ else if (utf8Value.isEmpty())
+ fDropConnection = true;
+
+ LogRelFlow(("VRDE: szNoLoggedInUsers=%s, mfNoLoggedInUsers=%RTbool, fDropConnection=%RTbool\n",
+ utf8Value.c_str(), mfNoLoggedInUsers, fDropConnection));
+
+ if (fDropConnection)
{
- ULONG cClients = 0;
- hrc = info->COMGETTER(NumberOfClients)(&cClients);
- if (SUCCEEDED(hrc) && cClients > 0)
+ /* If there is a connection, drop it. */
+ ComPtr<IVRDEServerInfo> info;
+ hrc = gConsole->COMGETTER(VRDEServerInfo)(info.asOutParam());
+ if (SUCCEEDED(hrc) && info)
{
- ComPtr <IVRDEServer> vrdeServer;
- hrc = machine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
- if (SUCCEEDED(hrc) && vrdeServer)
+ ULONG cClients = 0;
+ hrc = info->COMGETTER(NumberOfClients)(&cClients);
+
+ LogRelFlow(("VRDE: connected clients=%RU32\n", cClients));
+ if (SUCCEEDED(hrc) && cClients > 0)
{
- LogRel(("VRDE: the guest user has logged out, disconnecting remote clients.\n"));
- vrdeServer->COMSETTER(Enabled)(FALSE);
- vrdeServer->COMSETTER(Enabled)(TRUE);
+ ComPtr <IVRDEServer> vrdeServer;
+ hrc = pMachine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
+ if (SUCCEEDED(hrc) && vrdeServer)
+ {
+ LogRel(("VRDE: the guest user has logged out, disconnecting remote clients.\n"));
+ hrc = vrdeServer->COMSETTER(Enabled)(FALSE);
+ AssertComRC(hrc);
+ HRESULT hrc2 = vrdeServer->COMSETTER(Enabled)(TRUE);
+ if (SUCCEEDED(hrc))
+ hrc = hrc2;
+ }
}
}
}
}
}
+
+ if (FAILED(hrc))
+ LogRelFlow(("VRDE: returned error=%Rhrc\n", hrc));
}
+
break;
}
+
default:
AssertFailed();
}
@@ -259,6 +295,7 @@ public:
}
private:
+
bool mfNoLoggedInUsers;
};
@@ -295,7 +332,7 @@ public:
{
ComPtr<IMouseCapabilityChangedEvent> mccev = aEvent;
- Assert(mccev);
+ Assert(!mccev.isNull());
BOOL fSupportsAbsolute = false;
mccev->COMGETTER(SupportsAbsolute)(&fSupportsAbsolute);
@@ -496,7 +533,12 @@ static void parse_environ(unsigned long *pulFrameWidth, unsigned long *pulFrameH
unsigned long *pulBitRate, const char **ppszFileName)
{
const char *pszEnvTemp;
-
+/** @todo r=bird: This isn't up to scratch. The life time of an RTEnvGet
+ * return value is only up to the next RTEnv*, *getenv, *putenv,
+ * setenv call in _any_ process in the system and the it has known and
+ * documented code page issues.
+ *
+ * Use RTEnvGetEx instead! */
if ((pszEnvTemp = RTEnvGet("VBOX_CAPTUREWIDTH")) != 0)
{
errno = 0;
@@ -612,18 +654,18 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
unsigned fPATM = ~0U;
unsigned fCSAM = ~0U;
#ifdef VBOX_WITH_VIDEO_REC
- unsigned fVIDEOREC = 0;
+ bool fVideoRec = 0;
unsigned long ulFrameWidth = 800;
unsigned long ulFrameHeight = 600;
- unsigned long ulBitRate = 300000;
- char pszMPEGFile[RTPATH_MAX];
+ unsigned long ulBitRate = 300000; /** @todo r=bird: The COM type ULONG isn't unsigned long, it's 32-bit unsigned int. */
+ char szMpegFile[RTPATH_MAX];
const char *pszFileNameParam = "VBox-%d.vob";
#endif /* VBOX_WITH_VIDEO_REC */
- LogFlow (("VBoxHeadless STARTED.\n"));
- RTPrintf (VBOX_PRODUCT " Headless Interface " VBOX_VERSION_STRING "\n"
- "(C) 2008-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
- "All rights reserved.\n\n");
+ LogFlow(("VBoxHeadless STARTED.\n"));
+ RTPrintf(VBOX_PRODUCT " Headless Interface " VBOX_VERSION_STRING "\n"
+ "(C) 2008-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
+ "All rights reserved.\n\n");
#ifdef VBOX_WITH_VIDEO_REC
/* Parse the environment */
@@ -754,7 +796,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
break;
#ifdef VBOX_WITH_VIDEO_REC
case 'c':
- fVIDEOREC = true;
+ fVideoRec = true;
break;
case 'w':
ulFrameWidth = ValueUnion.u32;
@@ -818,7 +860,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
LogError("VBoxHeadless: ERROR: Only one format modifier is allowed in the capture file name.", -1);
return 1;
}
- RTStrPrintf(&pszMPEGFile[0], RTPATH_MAX, pszFileNameParam, RTProcSelf());
+ RTStrPrintf(&szMpegFile[0], RTPATH_MAX, pszFileNameParam, RTProcSelf());
#endif /* defined VBOX_WITH_VIDEO_REC */
if (!pcszNameOrUUID)
@@ -933,7 +975,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
RTLDRMOD hLdrVideoRecFB;
PFNREGISTERVIDEORECFB pfnRegisterVideoRecFB;
- if (fVIDEOREC)
+ if (fVideoRec)
{
HRESULT rcc = S_OK;
int rrc = VINF_SUCCESS;
@@ -957,7 +999,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
{
Log2(("VBoxHeadless: calling pfnRegisterVideoRecFB\n"));
rcc = pfnRegisterVideoRecFB(ulFrameWidth, ulFrameHeight, ulBitRate,
- pszMPEGFile, &pFramebuffer);
+ szMpegFile, &pFramebuffer);
if (rcc != S_OK)
LogError("Failed to initialise video capturing - make sure that the file format\n"
"you wish to use is supported on your system\n", rcc);
@@ -983,7 +1025,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
for (uScreenId = 0; uScreenId < cMonitors; uScreenId++)
{
# ifdef VBOX_WITH_VIDEO_REC
- if (fVIDEOREC && uScreenId == 0)
+ if (fVideoRec && uScreenId == 0)
{
/* Already registered. */
continue;
@@ -1067,7 +1109,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
/* initialize global references */
gConsole = console;
- gEventQ = com::EventQueue::getMainEventQueue();
+ gEventQ = com::NativeEventQueue::getMainEventQueue();
/* VirtualBoxClient events registration. */
{
@@ -1251,6 +1293,13 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
vboxListener = listener;
com::SafeArray<VBoxEventType_T> eventTypes;
eventTypes.push_back(VBoxEventType_OnGuestPropertyChanged);
+
+ /**
+ * @todo Set the notification pattern to "/VirtualBox/GuestInfo/OS/ *Logged*"
+ * to not cause too much load. The current API is broken as
+ * IMachine::GuestPropertyNotificationPatterns() would change the
+ * filter for _all_ clients. This is not what we want!
+ */
CHECK_ERROR(es, RegisterListener(vboxListener, ComSafeArrayAsInParam(eventTypes), true));
}
diff --git a/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.h b/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.h
index c241f5b5..03a3e576 100644
--- a/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.h
+++ b/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.h
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * 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;
diff --git a/src/VBox/Frontends/VBoxHeadless/VBoxHeadlessHardened.cpp b/src/VBox/Frontends/VBoxHeadless/VBoxHeadlessHardened.cpp
index abb18eea..2d05ed74 100644
--- a/src/VBox/Frontends/VBoxHeadless/VBoxHeadlessHardened.cpp
+++ b/src/VBox/Frontends/VBoxHeadless/VBoxHeadlessHardened.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
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)
-
diff --git a/src/VBox/Frontends/VBoxHeadless/testcase/Makefile.kmk b/src/VBox/Frontends/VBoxHeadless/testcase/Makefile.kmk
index c14eb4ae..02e7d092 100644
--- a/src/VBox/Frontends/VBoxHeadless/testcase/Makefile.kmk
+++ b/src/VBox/Frontends/VBoxHeadless/testcase/Makefile.kmk
@@ -20,7 +20,7 @@ include $(KBUILD_PATH)/subheader.kmk
ifdef VBOX_WITH_TESTCASES
PROGRAMS += tstHeadless
- tstHeadless_TEMPLATE = VBOXMAINCLIENTEXE
+ tstHeadless_TEMPLATE = VBOXMAINCLIENTTSTEXE
tstHeadless_SOURCES = tstHeadless.cpp
endif
diff --git a/src/VBox/Frontends/VBoxHeadless/testcase/tstHeadless.cpp b/src/VBox/Frontends/VBoxHeadless/testcase/tstHeadless.cpp
index 4d94438a..3e40a75b 100644
--- a/src/VBox/Frontends/VBoxHeadless/testcase/tstHeadless.cpp
+++ b/src/VBox/Frontends/VBoxHeadless/testcase/tstHeadless.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -21,7 +21,6 @@
#include <VBox/com/Guid.h>
#include <VBox/com/ErrorInfo.h>
#include <VBox/com/errorprint.h>
-#include <VBox/com/EventQueue.h>
#include <VBox/com/VirtualBox.h>
@@ -37,7 +36,7 @@ using namespace com;
/**
* Entry point.
*/
-int main (int argc, char **argv)
+int main(int argc, char **argv)
{
// initialize VBox Runtime
RTR3InitExe(argc, &argv, 0);
@@ -55,18 +54,18 @@ int main (int argc, char **argv)
if (!name || !operation)
{
- RTPrintf ("\nUsage:\n\n"
- "%s <machine_name> [on|off|pause|resume]\n\n",
- argv [0]);
- return -1;
+ RTPrintf("\nUsage:\n\n"
+ "%s <machine_name> [on|off|pause|resume]\n\n",
+ argv [0]);
+ return 0;
}
- RTPrintf ("\n");
- RTPrintf ("tstHeadless STARTED.\n");
+ RTPrintf("\n");
+ RTPrintf("tstHeadless STARTED.\n");
- RTPrintf ("VM name : {%s}\n"
- "Operation : %s\n\n",
- name, operation);
+ RTPrintf("VM name : {%s}\n"
+ "Operation : %s\n\n",
+ name, operation);
HRESULT rc;
@@ -82,8 +81,8 @@ int main (int argc, char **argv)
ComPtr <IVirtualBox> virtualBox;
ComPtr <ISession> session;
- RTPrintf ("Creating VirtualBox object...\n");
- rc = virtualBox.createLocalObject (CLSID_VirtualBox);
+ RTPrintf("Creating VirtualBox object...\n");
+ rc = virtualBox.createLocalObject(CLSID_VirtualBox);
if (FAILED(rc))
RTPrintf("ERROR: failed to create the VirtualBox object!\n");
else
@@ -93,7 +92,7 @@ int main (int argc, char **argv)
RTPrintf("ERROR: failed to create a session object!\n");
}
- if (FAILED (rc))
+ if (FAILED(rc))
{
com::ErrorInfo info;
if (!info.isFullAvailable() && !info.isBasicAvailable())
@@ -106,11 +105,6 @@ int main (int argc, char **argv)
break;
}
- // create the event queue
- // (here it is necessary only to process remaining XPCOM/IPC events
- // after the session is closed)
- EventQueue eventQ;
-
ComPtr <IMachine> m;
// find ID by name
@@ -120,78 +114,78 @@ int main (int argc, char **argv)
if (!strcmp(operation, "on"))
{
ComPtr <IProgress> progress;
- RTPrintf ("Opening a new (remote) session...\n");
- CHECK_ERROR_BREAK (m,
- LaunchVMProcess(session, Bstr("vrdp").raw(),
- NULL, progress.asOutParam()));
+ RTPrintf("Opening a new (remote) session...\n");
+ CHECK_ERROR_BREAK(m,
+ LaunchVMProcess(session, Bstr("vrdp").raw(),
+ NULL, progress.asOutParam()));
- RTPrintf ("Waiting for the remote session to open...\n");
- CHECK_ERROR_BREAK (progress, WaitForCompletion (-1));
+ RTPrintf("Waiting for the remote session to open...\n");
+ CHECK_ERROR_BREAK(progress, WaitForCompletion(-1));
BOOL completed;
- CHECK_ERROR_BREAK (progress, COMGETTER(Completed) (&completed));
- ASSERT (completed);
+ CHECK_ERROR_BREAK(progress, COMGETTER(Completed)(&completed));
+ ASSERT(completed);
LONG resultCode;
- CHECK_ERROR_BREAK (progress, COMGETTER(ResultCode) (&resultCode));
- if (FAILED (resultCode))
+ CHECK_ERROR_BREAK(progress, COMGETTER(ResultCode)(&resultCode));
+ if (FAILED(resultCode))
{
ProgressErrorInfo info(progress);
com::GluePrintErrorInfo(info);
}
else
{
- RTPrintf ("Remote session has been successfully opened.\n");
+ RTPrintf("Remote session has been successfully opened.\n");
}
}
else
{
- RTPrintf ("Opening an existing session...\n");
+ RTPrintf("Opening an existing session...\n");
CHECK_ERROR_BREAK(m, LockMachine(session, LockType_Shared));
ComPtr <IConsole> console;
CHECK_ERROR_BREAK(session, COMGETTER(Console)(console.asOutParam()));
- if (!strcmp (operation, "off"))
+ if (!strcmp(operation, "off"))
{
ComPtr <IProgress> progress;
- RTPrintf ("Powering the VM off...\n");
- CHECK_ERROR_BREAK (console, PowerDown(progress.asOutParam()));
+ RTPrintf("Powering the VM off...\n");
+ CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
- RTPrintf ("Waiting for the VM to power down...\n");
- CHECK_ERROR_BREAK (progress, WaitForCompletion (-1));
+ RTPrintf("Waiting for the VM to power down...\n");
+ CHECK_ERROR_BREAK(progress, WaitForCompletion(-1));
BOOL completed;
- CHECK_ERROR_BREAK (progress, COMGETTER(Completed) (&completed));
- ASSERT (completed);
+ CHECK_ERROR_BREAK(progress, COMGETTER(Completed)(&completed));
+ ASSERT(completed);
LONG resultCode;
- CHECK_ERROR_BREAK (progress, COMGETTER(ResultCode) (&resultCode));
- if (FAILED (resultCode))
+ CHECK_ERROR_BREAK(progress, COMGETTER(ResultCode)(&resultCode));
+ if (FAILED(resultCode))
{
ProgressErrorInfo info(progress);
com::GluePrintErrorInfo(info);
}
else
{
- RTPrintf ("VM is powered down.\n");
+ RTPrintf("VM is powered down.\n");
}
}
else
- if (!strcmp (operation, "pause"))
+ if (!strcmp(operation, "pause"))
{
- RTPrintf ("Pausing the VM...\n");
- CHECK_ERROR_BREAK (console, Pause());
+ RTPrintf("Pausing the VM...\n");
+ CHECK_ERROR_BREAK(console, Pause());
}
else
- if (!strcmp (operation, "resume"))
+ if (!strcmp(operation, "resume"))
{
- RTPrintf ("Resuming the VM...\n");
- CHECK_ERROR_BREAK (console, Resume());
+ RTPrintf("Resuming the VM...\n");
+ CHECK_ERROR_BREAK(console, Resume());
}
else
{
- RTPrintf ("Invalid operation!\n");
+ RTPrintf("Invalid operation!\n");
}
}
@@ -199,11 +193,11 @@ int main (int argc, char **argv)
CHECK_ERROR(session, UnlockMachine());
}
while (0);
- RTPrintf ("\n");
+ RTPrintf("\n");
com::Shutdown();
- RTPrintf ("tstHeadless FINISHED.\n");
+ RTPrintf("tstHeadless FINISHED.\n");
return rc;
}