Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 75343)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 75344)
@@ -804,10 +804,10 @@
    VBoxC_DEFS += VBOX_WITH_LIBVPX
    VBoxC_SOURCES += \
-	src-client/VideoRec.cpp \
-	src-client/VideoRecInternals.cpp \
-	src-client/VideoRecStream.cpp \
-	src-client/VideoRecUtils.cpp
+	src-client/Recording.cpp \
+	src-client/RecordingInternals.cpp \
+	src-client/RecordingStream.cpp \
+	src-client/RecordingUtils.cpp
   else
-   $(error "VBox: No alternative for VPX when using video capturing support yet")
+   $(error "VBox: No alternative for VPX when using recording support yet")
   endif
 endif
@@ -818,5 +818,5 @@
    VBoxC_DEFS += VBOX_WITH_LIBOPUS
   else
-   $(error "VBox: No alternative for Opus when using audio support for video capturing yet")
+   $(error "VBox: No alternative for Opus when using audio support for recording yet")
   endif
 endif
@@ -933,5 +933,5 @@
 	src-client/AudioDriver.cpp \
 	$(if $(VBOX_WITH_AUDIO_VRDE),src-client/DrvAudioVRDE.cpp,) \
-	$(if $(VBOX_WITH_AUDIO_VIDEOREC),src-client/DrvAudioVideoRec.cpp,)
+	$(if $(VBOX_WITH_AUDIO_VIDEOREC),src-client/DrvAudioRec.cpp,)
 
 VBoxC_SOURCES.win = \
Index: /trunk/src/VBox/Main/include/ConsoleImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/ConsoleImpl.h	(revision 75343)
+++ /trunk/src/VBox/Main/include/ConsoleImpl.h	(revision 75344)
@@ -25,5 +25,5 @@
 #include "ConsoleWrap.h"
 #ifdef VBOX_WITH_VIDEOREC
-# include "VideoRec.h"
+# include "Recording.h"
 #endif
 
Index: /trunk/src/VBox/Main/include/DrvAudioRec.h
===================================================================
--- /trunk/src/VBox/Main/include/DrvAudioRec.h	(revision 75344)
+++ /trunk/src/VBox/Main/include/DrvAudioRec.h	(revision 75344)
@@ -0,0 +1,67 @@
+/* $Id$ */
+/** @file
+ * VirtualBox driver interface video recording audio backend.
+ */
+
+/*
+ * Copyright (C) 2017-2018 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_DRVAUDIOVIDEOREC
+#define ____H_DRVAUDIOVIDEOREC
+
+#include <VBox/com/ptr.h>
+#include <VBox/settings.h>
+#include <VBox/vmm/pdmdrv.h>
+#include <VBox/vmm/pdmifs.h>
+
+#include "AudioDriver.h"
+#include "Recording.h"
+
+using namespace com;
+
+class Console;
+
+class AudioVideoRec : public AudioDriver
+{
+
+public:
+
+    AudioVideoRec(Console *pConsole);
+    virtual ~AudioVideoRec(void);
+
+public:
+
+    static const PDMDRVREG DrvReg;
+
+public:
+
+    int applyConfiguration(const settings::RecordSettings &Settings);
+
+public:
+
+    static DECLCALLBACK(int)  drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags);
+    static DECLCALLBACK(void) drvDestruct(PPDMDRVINS pDrvIns);
+    static DECLCALLBACK(int)  drvAttach(PPDMDRVINS pDrvIns, uint32_t fFlags);
+    static DECLCALLBACK(void) drvDetach(PPDMDRVINS pDrvIns, uint32_t fFlags);
+
+private:
+
+    int configureDriver(PCFGMNODE pLunCfg);
+
+    /** Pointer to the associated video recording audio driver. */
+    struct DRVAUDIOVIDEOREC         *mpDrv;
+    /** Capturing configuration used for configuring the driver. */
+    struct settings::RecordSettings mVideoRecCfg;
+};
+
+#endif /* !____H_DRVAUDIOVIDEOREC */
+
Index: unk/src/VBox/Main/include/DrvAudioVideoRec.h
===================================================================
--- /trunk/src/VBox/Main/include/DrvAudioVideoRec.h	(revision 75343)
+++ 	(revision )
@@ -1,67 +1,0 @@
-/* $Id$ */
-/** @file
- * VirtualBox driver interface video recording audio backend.
- */
-
-/*
- * Copyright (C) 2017-2018 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_DRVAUDIOVIDEOREC
-#define ____H_DRVAUDIOVIDEOREC
-
-#include <VBox/com/ptr.h>
-#include <VBox/settings.h>
-#include <VBox/vmm/pdmdrv.h>
-#include <VBox/vmm/pdmifs.h>
-
-#include "AudioDriver.h"
-#include "VideoRec.h"
-
-using namespace com;
-
-class Console;
-
-class AudioVideoRec : public AudioDriver
-{
-
-public:
-
-    AudioVideoRec(Console *pConsole);
-    virtual ~AudioVideoRec(void);
-
-public:
-
-    static const PDMDRVREG DrvReg;
-
-public:
-
-    int applyConfiguration(const settings::RecordSettings &Settings);
-
-public:
-
-    static DECLCALLBACK(int)  drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags);
-    static DECLCALLBACK(void) drvDestruct(PPDMDRVINS pDrvIns);
-    static DECLCALLBACK(int)  drvAttach(PPDMDRVINS pDrvIns, uint32_t fFlags);
-    static DECLCALLBACK(void) drvDetach(PPDMDRVINS pDrvIns, uint32_t fFlags);
-
-private:
-
-    int configureDriver(PCFGMNODE pLunCfg);
-
-    /** Pointer to the associated video recording audio driver. */
-    struct DRVAUDIOVIDEOREC         *mpDrv;
-    /** Capturing configuration used for configuring the driver. */
-    struct settings::RecordSettings mVideoRecCfg;
-};
-
-#endif /* !____H_DRVAUDIOVIDEOREC */
-
Index: /trunk/src/VBox/Main/include/Recording.h
===================================================================
--- /trunk/src/VBox/Main/include/Recording.h	(revision 75344)
+++ /trunk/src/VBox/Main/include/Recording.h	(revision 75344)
@@ -0,0 +1,132 @@
+/* $Id$ */
+/** @file
+ * Recording code header.
+ */
+
+/*
+ * Copyright (C) 2012-2018 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_VIDEOREC
+#define ____H_VIDEOREC
+
+#include <VBox/com/array.h>
+#include <VBox/com/string.h>
+#include <VBox/com/VirtualBox.h>
+#include <VBox/err.h>
+#include <VBox/settings.h>
+
+using namespace com;
+
+#include "RecordingInternals.h"
+#include "RecordingStream.h"
+
+class Console;
+
+/**
+ * Class for managing a capturing context.
+ */
+class CaptureContext
+{
+public:
+
+    CaptureContext(Console *pConsole);
+
+    CaptureContext(Console *pConsole, const settings::RecordSettings &a_Settings);
+
+    virtual ~CaptureContext(void);
+
+public:
+
+    const settings::RecordSettings &GetConfig(void) const;
+    CaptureStream *GetStream(unsigned uScreen) const;
+    size_t GetStreamCount(void) const;
+
+    int Create(const settings::RecordSettings &a_Settings);
+    int Destroy(void);
+
+    int Start(void);
+    int Stop(void);
+
+    int SendAudioFrame(const void *pvData, size_t cbData, uint64_t uTimestampMs);
+    int SendVideoFrame(uint32_t uScreen,
+                       uint32_t x, uint32_t y, uint32_t uPixelFormat, uint32_t uBPP,
+                       uint32_t uBytesPerLine, uint32_t uSrcWidth, uint32_t uSrcHeight,
+                       uint8_t *puSrcData, uint64_t uTimeStampMs);
+public:
+
+    bool IsFeatureEnabled(RecordFeature_T enmFeature) const;
+    bool IsReady(void) const;
+    bool IsReady(uint32_t uScreen, uint64_t uTimeStampMs) const;
+    bool IsStarted(void) const;
+    bool IsLimitReached(uint32_t uScreen, uint64_t tsNowMs) const;
+
+protected:
+
+    int createInternal(const settings::RecordSettings &a_Settings);
+    int startInternal(void);
+    int stopInternal(void);
+
+    int destroyInternal(void);
+
+    CaptureStream *getStreamInternal(unsigned uScreen) const;
+
+    static DECLCALLBACK(int) threadMain(RTTHREAD hThreadSelf, void *pvUser);
+
+    int threadNotify(void);
+
+protected:
+
+    /**
+     * Enumeration for a recording context state.
+     */
+    enum VIDEORECSTS
+    {
+        /** Context not initialized. */
+        VIDEORECSTS_UNINITIALIZED = 0,
+        /** Context was created. */
+        VIDEORECSTS_CREATED       = 1,
+        /** Context was started. */
+        VIDEORECSTS_STARTED       = 2,
+        /** The usual 32-bit hack. */
+        VIDEORECSTS_32BIT_HACK    = 0x7fffffff
+    };
+
+    /** Pointer to the console object. */
+    Console                  *pConsole;
+    /** Used recording configuration. */
+    settings::RecordSettings Settings;
+    /** The current state. */
+    VIDEORECSTS               enmState;
+    /** Critical section to serialize access. */
+    RTCRITSECT                CritSect;
+    /** Semaphore to signal the encoding worker thread. */
+    RTSEMEVENT                WaitEvent;
+    /** Shutdown indicator. */
+    bool                      fShutdown;
+    /** Worker thread. */
+    RTTHREAD                  Thread;
+    /** Vector of current recording streams.
+     *  Per VM screen (display) one recording stream is being used. */
+    VideoRecStreams           vecStreams;
+    /** Timestamp (in ms) of when recording has been started. */
+    uint64_t                  tsStartMs;
+    /** Block map of common blocks which need to get multiplexed
+     *  to all recording streams. This common block maps should help
+     *  reducing the time spent in EMT and avoid doing the (expensive)
+     *  multiplexing work in there.
+     *
+     *  For now this only affects audio, e.g. all recording streams
+     *  need to have the same audio data at a specific point in time. */
+    VideoRecBlockMap          mapBlocksCommon;
+};
+#endif /* !____H_VIDEOREC */
+
Index: /trunk/src/VBox/Main/include/RecordingInternals.h
===================================================================
--- /trunk/src/VBox/Main/include/RecordingInternals.h	(revision 75344)
+++ /trunk/src/VBox/Main/include/RecordingInternals.h	(revision 75344)
@@ -0,0 +1,143 @@
+/* $Id$ */
+/** @file
+ * Recording internals header.
+ */
+
+/*
+ * Copyright (C) 2012-2018 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_VIDEOREC_INTERNALS
+#define ____H_VIDEOREC_INTERNALS
+
+#include <iprt/types.h> /* drag in stdint.h before vpx does it. */
+#include <list>
+
+#ifdef VBOX_WITH_LIBVPX
+# define VPX_CODEC_DISABLE_COMPAT 1
+# include "vpx/vp8cx.h"
+# include "vpx/vpx_image.h"
+# include "vpx/vpx_encoder.h"
+#endif /* VBOX_WITH_LIBVPX */
+
+/**
+ * Structure for keeping specific video recording codec data.
+ */
+typedef struct VIDEORECVIDEOCODEC
+{
+#ifdef VBOX_WITH_LIBVPX
+    union
+    {
+        struct
+        {
+            /** VPX codec context. */
+            vpx_codec_ctx_t     Ctx;
+            /** VPX codec configuration. */
+            vpx_codec_enc_cfg_t Cfg;
+            /** VPX image context. */
+            vpx_image_t         RawImage;
+            /** Pointer to the codec's internal YUV buffer. */
+            uint8_t            *pu8YuvBuf;
+            unsigned int        uEncoderDeadline;
+        } VPX;
+    };
+#endif /* VBOX_WITH_LIBVPX */
+} VIDEORECVIDEOCODEC, *PVIDEORECVIDEOCODEC;
+
+/**
+ * Enumeration for supported pixel formats.
+ */
+enum VIDEORECPIXELFMT
+{
+    /** Unknown pixel format. */
+    VIDEORECPIXELFMT_UNKNOWN    = 0,
+    /** RGB 24. */
+    VIDEORECPIXELFMT_RGB24      = 1,
+    /** RGB 24. */
+    VIDEORECPIXELFMT_RGB32      = 2,
+    /** RGB 565. */
+    VIDEORECPIXELFMT_RGB565     = 3,
+    /** The usual 32-bit hack. */
+    VIDEORECPIXELFMT_32BIT_HACK = 0x7fffffff
+};
+
+/**
+ * Structure for keeping a single video recording video frame.
+ */
+typedef struct VIDEORECVIDEOFRAME
+{
+    /** X resolution of this frame. */
+    uint32_t            uWidth;
+    /** Y resolution of this frame. */
+    uint32_t            uHeight;
+    /** Pixel format of this frame. */
+    uint32_t            uPixelFormat;
+    /** RGB buffer containing the unmodified frame buffer data from Main's display. */
+    uint8_t            *pu8RGBBuf;
+    /** Size (in bytes) of the RGB buffer. */
+    size_t              cbRGBBuf;
+} VIDEORECVIDEOFRAME, *PVIDEORECVIDEOFRAME;
+
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+/**
+ * Structure for keeping a single video recording audio frame.
+ */
+typedef struct VIDEORECAUDIOFRAME
+{
+    /** Pointer to audio data. */
+    uint8_t            *pvBuf;
+    /** Size (in bytes) of audio data. */
+    size_t              cbBuf;
+} VIDEORECAUDIOFRAME, *PVIDEORECAUDIOFRAME;
+#endif
+
+/**
+ * Enumeration for specifying a video recording block type.
+ */
+typedef enum VIDEORECBLOCKTYPE
+{
+    /** Uknown block type, do not use. */
+    VIDEORECBLOCKTYPE_UNKNOWN = 0,
+    /** The block is a video frame. */
+    VIDEORECBLOCKTYPE_VIDEO,
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+    /** The block is an audio frame. */
+    VIDEORECBLOCKTYPE_AUDIO
+#endif
+} VIDEORECBLOCKTYPE;
+
+/**
+ * Generic structure for keeping a single video recording (data) block.
+ */
+typedef struct VIDEORECBLOCK
+{
+    /** The block's type. */
+    VIDEORECBLOCKTYPE  enmType;
+    /** Number of references held of this block. */
+    uint16_t           cRefs;
+    /** The (absolute) time stamp (in ms, PTS) of this block. */
+    uint64_t           uTimeStampMs;
+    /** Opaque data block to the actual block data, depending on the block's type. */
+    void              *pvData;
+    /** Size (in bytes) of the (opaque) data block. */
+    size_t             cbData;
+} VIDEORECBLOCK, *PVIDEORECBLOCK;
+
+/** List for keeping video recording (data) blocks. */
+typedef std::list<PVIDEORECBLOCK> VideoRecBlockList;
+
+void VideoRecBlockFree(PVIDEORECBLOCK pBlock);
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+void VideoRecAudioFrameFree(PVIDEORECAUDIOFRAME pFrame);
+#endif
+void VideoRecVideoFrameFree(PVIDEORECVIDEOFRAME pFrame);
+
+#endif /* ____H_VIDEOREC_INTERNALS */
Index: /trunk/src/VBox/Main/include/RecordingStream.h
===================================================================
--- /trunk/src/VBox/Main/include/RecordingStream.h	(revision 75344)
+++ /trunk/src/VBox/Main/include/RecordingStream.h	(revision 75344)
@@ -0,0 +1,217 @@
+/* $Id$ */
+/** @file
+ * Recording stream code header.
+ */
+
+/*
+ * Copyright (C) 2012-2018 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_VIDEOREC_STREAM
+#define ____H_VIDEOREC_STREAM
+
+#include <map>
+#include <vector>
+
+#include <iprt/critsect.h>
+
+#include <VBox/com/array.h>
+#include <VBox/com/VirtualBox.h>
+#include <VBox/err.h>
+#include <VBox/settings.h>
+
+#include "RecordingInternals.h"
+
+class WebMWriter;
+class CaptureContext;
+
+/** Structure for queuing all blocks bound to a single timecode.
+ *  This can happen if multiple tracks are being involved. */
+struct CaptureBlocks
+{
+    virtual ~CaptureBlocks()
+    {
+        Clear();
+    }
+
+    /**
+     * Resets a video recording block list by removing (destroying)
+     * all current elements.
+     */
+    void Clear()
+    {
+        while (!List.empty())
+        {
+            PVIDEORECBLOCK pBlock = List.front();
+            VideoRecBlockFree(pBlock);
+            List.pop_front();
+        }
+
+        Assert(List.size() == 0);
+    }
+
+    /** The actual block list for this timecode. */
+    VideoRecBlockList List;
+};
+
+/** A block map containing all currently queued blocks.
+ *  The key specifies a unique timecode, whereas the value
+ *  is a list of blocks which all correlate to the same key (timecode). */
+typedef std::map<uint64_t, CaptureBlocks *> VideoRecBlockMap;
+
+/**
+ * Structure for holding a set of recording (data) blocks.
+ */
+struct CaptureBlockSet
+{
+    virtual ~CaptureBlockSet()
+    {
+        Clear();
+    }
+
+    /**
+     * Resets a recording block set by removing (destroying)
+     * all current elements.
+     */
+    void Clear(void)
+    {
+        VideoRecBlockMap::iterator it = Map.begin();
+        while (it != Map.end())
+        {
+            it->second->Clear();
+            delete it->second;
+            Map.erase(it);
+            it = Map.begin();
+        }
+
+        Assert(Map.size() == 0);
+    }
+
+    /** Timestamp (in ms) when this set was last processed. */
+    uint64_t         tsLastProcessedMs;
+    /** All blocks related to this block set. */
+    VideoRecBlockMap Map;
+};
+
+/**
+ * Class for managing a recording stream.
+ */
+class CaptureStream
+{
+public:
+
+    CaptureStream(CaptureContext *pCtx);
+
+    CaptureStream(CaptureContext *pCtx, uint32_t uScreen, const settings::RecordScreenSettings &Settings);
+
+    virtual ~CaptureStream(void);
+
+public:
+
+    int Init(CaptureContext *pCtx, uint32_t uScreen, const settings::RecordScreenSettings &Settings);
+    int Uninit(void);
+
+    int Process(VideoRecBlockMap &mapBlocksCommon);
+    int SendVideoFrame(uint32_t x, uint32_t y, uint32_t uPixelFormat, uint32_t uBPP, uint32_t uBytesPerLine,
+                       uint32_t uSrcWidth, uint32_t uSrcHeight, uint8_t *puSrcData, uint64_t uTimeStampMs);
+
+    const settings::RecordScreenSettings &GetConfig(void) const;
+    bool IsLimitReached(uint64_t tsNowMs) const;
+    bool IsReady(void) const;
+
+protected:
+
+    int open(const settings::RecordScreenSettings &Settings);
+    int close(void);
+
+    int initInternal(CaptureContext *pCtx, uint32_t uScreen, const settings::RecordScreenSettings &Settings);
+    int uninitInternal(void);
+
+    int initVideo(void);
+    int unitVideo(void);
+
+    int initAudio(void);
+
+#ifdef VBOX_WITH_LIBVPX
+    int initVideoVPX(void);
+    int uninitVideoVPX(void);
+    int writeVideoVPX(uint64_t uTimeStampMs, PVIDEORECVIDEOFRAME pFrame);
+#endif
+    void lock(void);
+    void unlock(void);
+
+    int parseOptionsString(const com::Utf8Str &strOptions);
+
+protected:
+
+    /**
+     * Enumeration for a recording stream state.
+     */
+    enum RECORDINGSTREAMSTATE
+    {
+        /** Stream not initialized. */
+        RECORDINGSTREAMSTATE_UNINITIALIZED = 0,
+        /** Stream was initialized. */
+        RECORDINGSTREAMSTATE_INITIALIZED   = 1,
+        /** The usual 32-bit hack. */
+        RECORDINGSTREAMSTATE_32BIT_HACK    = 0x7fffffff
+    };
+
+    /** Recording context this stream is associated to. */
+    CaptureContext         *pCtx;
+    /** The current state. */
+    RECORDINGSTREAMSTATE    enmState;
+    struct
+    {
+        /** File handle to use for writing. */
+        RTFILE              hFile;
+        /** File name being used for this stream. */
+        Utf8Str             strName;
+        /** Pointer to WebM writer instance being used. */
+        WebMWriter         *pWEBM;
+    } File;
+    bool                fEnabled;
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+    /** Track number of audio stream. */
+    uint8_t             uTrackAudio;
+#endif
+    /** Track number of video stream. */
+    uint8_t             uTrackVideo;
+    /** Screen ID. */
+    uint16_t            uScreenID;
+    /** Critical section to serialize access. */
+    RTCRITSECT          CritSect;
+    /** Timestamp (in ms) of when recording has been start. */
+    uint64_t            tsStartMs;
+
+    struct
+    {
+        /** Minimal delay (in ms) between two video frames.
+         *  This value is based on the configured FPS rate. */
+        uint32_t            uDelayMs;
+        /** Time stamp (in ms) of the last video frame we encoded. */
+        uint64_t            uLastTimeStampMs;
+        /** Number of failed attempts to encode the current video frame in a row. */
+        uint16_t            cFailedEncodingFrames;
+        VIDEORECVIDEOCODEC  Codec;
+    } Video;
+
+    settings::RecordScreenSettings ScreenSettings;
+    /** Common set of video recording (data) blocks, needed for
+     *  multiplexing to all recording streams. */
+    CaptureBlockSet                 Blocks;
+};
+
+/** Vector of video recording streams. */
+typedef std::vector <CaptureStream *> VideoRecStreams;
+
+#endif /* ____H_VIDEOREC_STREAM */
+
Index: /trunk/src/VBox/Main/include/RecordingUtils.h
===================================================================
--- /trunk/src/VBox/Main/include/RecordingUtils.h	(revision 75344)
+++ /trunk/src/VBox/Main/include/RecordingUtils.h	(revision 75344)
@@ -0,0 +1,199 @@
+/* $Id$ */
+/** @file
+ * Recording utility header.
+ */
+
+/*
+ * Copyright (C) 2012-2018 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.
+ */
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <iprt/path.h>
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+
+
+/**
+ * Iterator class for running through a BGRA32 image buffer and converting
+ * it to RGB.
+ */
+class ColorConvBGRA32Iter
+{
+private:
+    enum { PIX_SIZE = 4 };
+public:
+    ColorConvBGRA32Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuf)
+    {
+        mPos = 0;
+        mSize = aWidth * aHeight * PIX_SIZE;
+        mBuf = aBuf;
+    }
+
+    /**
+     * 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   = mBuf[mPos + 2];
+            *aGreen = mBuf[mPos + 1];
+            *aBlue  = mBuf[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 *mBuf;
+};
+
+/**
+ * Iterator class for running through an BGR24 image buffer and converting
+ * it to RGB.
+ */
+class ColorConvBGR24Iter
+{
+private:
+    enum { PIX_SIZE = 3 };
+public:
+    ColorConvBGR24Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuf)
+    {
+        mPos = 0;
+        mSize = aWidth * aHeight * PIX_SIZE;
+        mBuf = aBuf;
+    }
+
+    /**
+     * 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   = mBuf[mPos + 2];
+            *aGreen = mBuf[mPos + 1];
+            *aBlue  = mBuf[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 *mBuf;
+};
+
+/**
+ * Iterator class for running through an BGR565 image buffer and converting
+ * it to RGB.
+ */
+class ColorConvBGR565Iter
+{
+private:
+    enum { PIX_SIZE = 2 };
+public:
+    ColorConvBGR565Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuf)
+    {
+        mPos = 0;
+        mSize = aWidth * aHeight * PIX_SIZE;
+        mBuf = aBuf;
+    }
+
+    /**
+     * 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) mBuf[mPos + 1]) << 8)
+                             | ((unsigned) mBuf[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 *mBuf;
+};
+
+int videoRecRGBToYUV(uint32_t uPixelFormat,
+                     uint8_t *paDst, uint32_t uDstWidth, uint32_t uDstHeight,
+                     uint8_t *paSrc, uint32_t uSrcWidth, uint32_t uSrcHeight);
Index: unk/src/VBox/Main/include/VideoRec.h
===================================================================
--- /trunk/src/VBox/Main/include/VideoRec.h	(revision 75343)
+++ 	(revision )
@@ -1,132 +1,0 @@
-/* $Id$ */
-/** @file
- * Video recording code header.
- */
-
-/*
- * Copyright (C) 2012-2018 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_VIDEOREC
-#define ____H_VIDEOREC
-
-#include <VBox/com/array.h>
-#include <VBox/com/string.h>
-#include <VBox/com/VirtualBox.h>
-#include <VBox/err.h>
-#include <VBox/settings.h>
-
-using namespace com;
-
-#include "VideoRecInternals.h"
-#include "VideoRecStream.h"
-
-class Console;
-
-/**
- * Class for managing a capturing context.
- */
-class CaptureContext
-{
-public:
-
-    CaptureContext(Console *pConsole);
-
-    CaptureContext(Console *pConsole, const settings::RecordSettings &a_Settings);
-
-    virtual ~CaptureContext(void);
-
-public:
-
-    const settings::RecordSettings &GetConfig(void) const;
-    CaptureStream *GetStream(unsigned uScreen) const;
-    size_t GetStreamCount(void) const;
-
-    int Create(const settings::RecordSettings &a_Settings);
-    int Destroy(void);
-
-    int Start(void);
-    int Stop(void);
-
-    int SendAudioFrame(const void *pvData, size_t cbData, uint64_t uTimestampMs);
-    int SendVideoFrame(uint32_t uScreen,
-                       uint32_t x, uint32_t y, uint32_t uPixelFormat, uint32_t uBPP,
-                       uint32_t uBytesPerLine, uint32_t uSrcWidth, uint32_t uSrcHeight,
-                       uint8_t *puSrcData, uint64_t uTimeStampMs);
-public:
-
-    bool IsFeatureEnabled(RecordFeature_T enmFeature) const;
-    bool IsReady(void) const;
-    bool IsReady(uint32_t uScreen, uint64_t uTimeStampMs) const;
-    bool IsStarted(void) const;
-    bool IsLimitReached(uint32_t uScreen, uint64_t tsNowMs) const;
-
-protected:
-
-    int createInternal(const settings::RecordSettings &a_Settings);
-    int startInternal(void);
-    int stopInternal(void);
-
-    int destroyInternal(void);
-
-    CaptureStream *getStreamInternal(unsigned uScreen) const;
-
-    static DECLCALLBACK(int) threadMain(RTTHREAD hThreadSelf, void *pvUser);
-
-    int threadNotify(void);
-
-protected:
-
-    /**
-     * Enumeration for a recording context state.
-     */
-    enum VIDEORECSTS
-    {
-        /** Context not initialized. */
-        VIDEORECSTS_UNINITIALIZED = 0,
-        /** Context was created. */
-        VIDEORECSTS_CREATED       = 1,
-        /** Context was started. */
-        VIDEORECSTS_STARTED       = 2,
-        /** The usual 32-bit hack. */
-        VIDEORECSTS_32BIT_HACK    = 0x7fffffff
-    };
-
-    /** Pointer to the console object. */
-    Console                  *pConsole;
-    /** Used recording configuration. */
-    settings::RecordSettings Settings;
-    /** The current state. */
-    VIDEORECSTS               enmState;
-    /** Critical section to serialize access. */
-    RTCRITSECT                CritSect;
-    /** Semaphore to signal the encoding worker thread. */
-    RTSEMEVENT                WaitEvent;
-    /** Shutdown indicator. */
-    bool                      fShutdown;
-    /** Worker thread. */
-    RTTHREAD                  Thread;
-    /** Vector of current recording streams.
-     *  Per VM screen (display) one recording stream is being used. */
-    VideoRecStreams           vecStreams;
-    /** Timestamp (in ms) of when recording has been started. */
-    uint64_t                  tsStartMs;
-    /** Block map of common blocks which need to get multiplexed
-     *  to all recording streams. This common block maps should help
-     *  reducing the time spent in EMT and avoid doing the (expensive)
-     *  multiplexing work in there.
-     *
-     *  For now this only affects audio, e.g. all recording streams
-     *  need to have the same audio data at a specific point in time. */
-    VideoRecBlockMap          mapBlocksCommon;
-};
-#endif /* !____H_VIDEOREC */
-
Index: unk/src/VBox/Main/include/VideoRecInternals.h
===================================================================
--- /trunk/src/VBox/Main/include/VideoRecInternals.h	(revision 75343)
+++ 	(revision )
@@ -1,143 +1,0 @@
-/* $Id$ */
-/** @file
- * Video recording internals header.
- */
-
-/*
- * Copyright (C) 2012-2018 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_VIDEOREC_INTERNALS
-#define ____H_VIDEOREC_INTERNALS
-
-#include <iprt/types.h> /* drag in stdint.h before vpx does it. */
-#include <list>
-
-#ifdef VBOX_WITH_LIBVPX
-# define VPX_CODEC_DISABLE_COMPAT 1
-# include "vpx/vp8cx.h"
-# include "vpx/vpx_image.h"
-# include "vpx/vpx_encoder.h"
-#endif /* VBOX_WITH_LIBVPX */
-
-/**
- * Structure for keeping specific video recording codec data.
- */
-typedef struct VIDEORECVIDEOCODEC
-{
-#ifdef VBOX_WITH_LIBVPX
-    union
-    {
-        struct
-        {
-            /** VPX codec context. */
-            vpx_codec_ctx_t     Ctx;
-            /** VPX codec configuration. */
-            vpx_codec_enc_cfg_t Cfg;
-            /** VPX image context. */
-            vpx_image_t         RawImage;
-            /** Pointer to the codec's internal YUV buffer. */
-            uint8_t            *pu8YuvBuf;
-            unsigned int        uEncoderDeadline;
-        } VPX;
-    };
-#endif /* VBOX_WITH_LIBVPX */
-} VIDEORECVIDEOCODEC, *PVIDEORECVIDEOCODEC;
-
-/**
- * Enumeration for supported pixel formats.
- */
-enum VIDEORECPIXELFMT
-{
-    /** Unknown pixel format. */
-    VIDEORECPIXELFMT_UNKNOWN    = 0,
-    /** RGB 24. */
-    VIDEORECPIXELFMT_RGB24      = 1,
-    /** RGB 24. */
-    VIDEORECPIXELFMT_RGB32      = 2,
-    /** RGB 565. */
-    VIDEORECPIXELFMT_RGB565     = 3,
-    /** The usual 32-bit hack. */
-    VIDEORECPIXELFMT_32BIT_HACK = 0x7fffffff
-};
-
-/**
- * Structure for keeping a single video recording video frame.
- */
-typedef struct VIDEORECVIDEOFRAME
-{
-    /** X resolution of this frame. */
-    uint32_t            uWidth;
-    /** Y resolution of this frame. */
-    uint32_t            uHeight;
-    /** Pixel format of this frame. */
-    uint32_t            uPixelFormat;
-    /** RGB buffer containing the unmodified frame buffer data from Main's display. */
-    uint8_t            *pu8RGBBuf;
-    /** Size (in bytes) of the RGB buffer. */
-    size_t              cbRGBBuf;
-} VIDEORECVIDEOFRAME, *PVIDEORECVIDEOFRAME;
-
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-/**
- * Structure for keeping a single video recording audio frame.
- */
-typedef struct VIDEORECAUDIOFRAME
-{
-    /** Pointer to audio data. */
-    uint8_t            *pvBuf;
-    /** Size (in bytes) of audio data. */
-    size_t              cbBuf;
-} VIDEORECAUDIOFRAME, *PVIDEORECAUDIOFRAME;
-#endif
-
-/**
- * Enumeration for specifying a video recording block type.
- */
-typedef enum VIDEORECBLOCKTYPE
-{
-    /** Uknown block type, do not use. */
-    VIDEORECBLOCKTYPE_UNKNOWN = 0,
-    /** The block is a video frame. */
-    VIDEORECBLOCKTYPE_VIDEO,
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-    /** The block is an audio frame. */
-    VIDEORECBLOCKTYPE_AUDIO
-#endif
-} VIDEORECBLOCKTYPE;
-
-/**
- * Generic structure for keeping a single video recording (data) block.
- */
-typedef struct VIDEORECBLOCK
-{
-    /** The block's type. */
-    VIDEORECBLOCKTYPE  enmType;
-    /** Number of references held of this block. */
-    uint16_t           cRefs;
-    /** The (absolute) time stamp (in ms, PTS) of this block. */
-    uint64_t           uTimeStampMs;
-    /** Opaque data block to the actual block data, depending on the block's type. */
-    void              *pvData;
-    /** Size (in bytes) of the (opaque) data block. */
-    size_t             cbData;
-} VIDEORECBLOCK, *PVIDEORECBLOCK;
-
-/** List for keeping video recording (data) blocks. */
-typedef std::list<PVIDEORECBLOCK> VideoRecBlockList;
-
-void VideoRecBlockFree(PVIDEORECBLOCK pBlock);
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-void VideoRecAudioFrameFree(PVIDEORECAUDIOFRAME pFrame);
-#endif
-void VideoRecVideoFrameFree(PVIDEORECVIDEOFRAME pFrame);
-
-#endif /* ____H_VIDEOREC_INTERNALS */
Index: unk/src/VBox/Main/include/VideoRecStream.h
===================================================================
--- /trunk/src/VBox/Main/include/VideoRecStream.h	(revision 75343)
+++ 	(revision )
@@ -1,217 +1,0 @@
-/* $Id$ */
-/** @file
- * Video recording stream code header.
- */
-
-/*
- * Copyright (C) 2012-2018 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_VIDEOREC_STREAM
-#define ____H_VIDEOREC_STREAM
-
-#include <map>
-#include <vector>
-
-#include <iprt/critsect.h>
-
-#include <VBox/com/array.h>
-#include <VBox/com/VirtualBox.h>
-#include <VBox/err.h>
-#include <VBox/settings.h>
-
-#include "VideoRecInternals.h"
-
-class WebMWriter;
-class CaptureContext;
-
-/** Structure for queuing all blocks bound to a single timecode.
- *  This can happen if multiple tracks are being involved. */
-struct CaptureBlocks
-{
-    virtual ~CaptureBlocks()
-    {
-        Clear();
-    }
-
-    /**
-     * Resets a video recording block list by removing (destroying)
-     * all current elements.
-     */
-    void Clear()
-    {
-        while (!List.empty())
-        {
-            PVIDEORECBLOCK pBlock = List.front();
-            VideoRecBlockFree(pBlock);
-            List.pop_front();
-        }
-
-        Assert(List.size() == 0);
-    }
-
-    /** The actual block list for this timecode. */
-    VideoRecBlockList List;
-};
-
-/** A block map containing all currently queued blocks.
- *  The key specifies a unique timecode, whereas the value
- *  is a list of blocks which all correlate to the same key (timecode). */
-typedef std::map<uint64_t, CaptureBlocks *> VideoRecBlockMap;
-
-/**
- * Structure for holding a set of recording (data) blocks.
- */
-struct CaptureBlockSet
-{
-    virtual ~CaptureBlockSet()
-    {
-        Clear();
-    }
-
-    /**
-     * Resets a recording block set by removing (destroying)
-     * all current elements.
-     */
-    void Clear(void)
-    {
-        VideoRecBlockMap::iterator it = Map.begin();
-        while (it != Map.end())
-        {
-            it->second->Clear();
-            delete it->second;
-            Map.erase(it);
-            it = Map.begin();
-        }
-
-        Assert(Map.size() == 0);
-    }
-
-    /** Timestamp (in ms) when this set was last processed. */
-    uint64_t         tsLastProcessedMs;
-    /** All blocks related to this block set. */
-    VideoRecBlockMap Map;
-};
-
-/**
- * Class for managing a recording stream.
- */
-class CaptureStream
-{
-public:
-
-    CaptureStream(CaptureContext *pCtx);
-
-    CaptureStream(CaptureContext *pCtx, uint32_t uScreen, const settings::RecordScreenSettings &Settings);
-
-    virtual ~CaptureStream(void);
-
-public:
-
-    int Init(CaptureContext *pCtx, uint32_t uScreen, const settings::RecordScreenSettings &Settings);
-    int Uninit(void);
-
-    int Process(VideoRecBlockMap &mapBlocksCommon);
-    int SendVideoFrame(uint32_t x, uint32_t y, uint32_t uPixelFormat, uint32_t uBPP, uint32_t uBytesPerLine,
-                       uint32_t uSrcWidth, uint32_t uSrcHeight, uint8_t *puSrcData, uint64_t uTimeStampMs);
-
-    const settings::RecordScreenSettings &GetConfig(void) const;
-    bool IsLimitReached(uint64_t tsNowMs) const;
-    bool IsReady(void) const;
-
-protected:
-
-    int open(const settings::RecordScreenSettings &Settings);
-    int close(void);
-
-    int initInternal(CaptureContext *pCtx, uint32_t uScreen, const settings::RecordScreenSettings &Settings);
-    int uninitInternal(void);
-
-    int initVideo(void);
-    int unitVideo(void);
-
-    int initAudio(void);
-
-#ifdef VBOX_WITH_LIBVPX
-    int initVideoVPX(void);
-    int uninitVideoVPX(void);
-    int writeVideoVPX(uint64_t uTimeStampMs, PVIDEORECVIDEOFRAME pFrame);
-#endif
-    void lock(void);
-    void unlock(void);
-
-    int parseOptionsString(const com::Utf8Str &strOptions);
-
-protected:
-
-    /**
-     * Enumeration for a recording stream state.
-     */
-    enum RECORDINGSTREAMSTATE
-    {
-        /** Stream not initialized. */
-        RECORDINGSTREAMSTATE_UNINITIALIZED = 0,
-        /** Stream was initialized. */
-        RECORDINGSTREAMSTATE_INITIALIZED   = 1,
-        /** The usual 32-bit hack. */
-        RECORDINGSTREAMSTATE_32BIT_HACK    = 0x7fffffff
-    };
-
-    /** Recording context this stream is associated to. */
-    CaptureContext         *pCtx;
-    /** The current state. */
-    RECORDINGSTREAMSTATE    enmState;
-    struct
-    {
-        /** File handle to use for writing. */
-        RTFILE              hFile;
-        /** File name being used for this stream. */
-        Utf8Str             strName;
-        /** Pointer to WebM writer instance being used. */
-        WebMWriter         *pWEBM;
-    } File;
-    bool                fEnabled;
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-    /** Track number of audio stream. */
-    uint8_t             uTrackAudio;
-#endif
-    /** Track number of video stream. */
-    uint8_t             uTrackVideo;
-    /** Screen ID. */
-    uint16_t            uScreenID;
-    /** Critical section to serialize access. */
-    RTCRITSECT          CritSect;
-    /** Timestamp (in ms) of when recording has been start. */
-    uint64_t            tsStartMs;
-
-    struct
-    {
-        /** Minimal delay (in ms) between two video frames.
-         *  This value is based on the configured FPS rate. */
-        uint32_t            uDelayMs;
-        /** Time stamp (in ms) of the last video frame we encoded. */
-        uint64_t            uLastTimeStampMs;
-        /** Number of failed attempts to encode the current video frame in a row. */
-        uint16_t            cFailedEncodingFrames;
-        VIDEORECVIDEOCODEC  Codec;
-    } Video;
-
-    settings::RecordScreenSettings ScreenSettings;
-    /** Common set of video recording (data) blocks, needed for
-     *  multiplexing to all recording streams. */
-    CaptureBlockSet                 Blocks;
-};
-
-/** Vector of video recording streams. */
-typedef std::vector <CaptureStream *> VideoRecStreams;
-
-#endif /* ____H_VIDEOREC_STREAM */
-
Index: unk/src/VBox/Main/include/VideoRecUtils.h
===================================================================
--- /trunk/src/VBox/Main/include/VideoRecUtils.h	(revision 75343)
+++ 	(revision )
@@ -1,199 +1,0 @@
-/* $Id$ */
-/** @file
- * Video recording utility header.
- */
-
-/*
- * Copyright (C) 2012-2018 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.
- */
-
-#include <iprt/asm.h>
-#include <iprt/assert.h>
-#include <iprt/critsect.h>
-#include <iprt/path.h>
-#include <iprt/semaphore.h>
-#include <iprt/thread.h>
-#include <iprt/time.h>
-
-
-/**
- * Iterator class for running through a BGRA32 image buffer and converting
- * it to RGB.
- */
-class ColorConvBGRA32Iter
-{
-private:
-    enum { PIX_SIZE = 4 };
-public:
-    ColorConvBGRA32Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuf)
-    {
-        mPos = 0;
-        mSize = aWidth * aHeight * PIX_SIZE;
-        mBuf = aBuf;
-    }
-
-    /**
-     * 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   = mBuf[mPos + 2];
-            *aGreen = mBuf[mPos + 1];
-            *aBlue  = mBuf[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 *mBuf;
-};
-
-/**
- * Iterator class for running through an BGR24 image buffer and converting
- * it to RGB.
- */
-class ColorConvBGR24Iter
-{
-private:
-    enum { PIX_SIZE = 3 };
-public:
-    ColorConvBGR24Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuf)
-    {
-        mPos = 0;
-        mSize = aWidth * aHeight * PIX_SIZE;
-        mBuf = aBuf;
-    }
-
-    /**
-     * 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   = mBuf[mPos + 2];
-            *aGreen = mBuf[mPos + 1];
-            *aBlue  = mBuf[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 *mBuf;
-};
-
-/**
- * Iterator class for running through an BGR565 image buffer and converting
- * it to RGB.
- */
-class ColorConvBGR565Iter
-{
-private:
-    enum { PIX_SIZE = 2 };
-public:
-    ColorConvBGR565Iter(unsigned aWidth, unsigned aHeight, uint8_t *aBuf)
-    {
-        mPos = 0;
-        mSize = aWidth * aHeight * PIX_SIZE;
-        mBuf = aBuf;
-    }
-
-    /**
-     * 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) mBuf[mPos + 1]) << 8)
-                             | ((unsigned) mBuf[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 *mBuf;
-};
-
-int videoRecRGBToYUV(uint32_t uPixelFormat,
-                     uint8_t *paDst, uint32_t uDstWidth, uint32_t uDstHeight,
-                     uint8_t *paSrc, uint32_t uSrcWidth, uint32_t uSrcHeight);
Index: /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 75343)
+++ /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 75344)
@@ -63,5 +63,5 @@
 #endif
 #ifdef VBOX_WITH_AUDIO_VIDEOREC
-# include "DrvAudioVideoRec.h"
+# include "DrvAudioRec.h"
 #endif
 #include "Nvram.h"
@@ -84,5 +84,5 @@
 
 #ifdef VBOX_WITH_VIDEOREC
-# include "VideoRec.h"
+# include "Recording.h"
 #endif
 
@@ -5621,5 +5621,5 @@
         if (RT_BOOL(fEnable) != fIsEnabled)
         {
-            LogRel(("VideoRec: %s\n", fEnable ? "Enabling" : "Disabling"));
+            LogRel(("Recording: %s\n", fEnable ? "Enabling" : "Disabling"));
 
             pDisplay->i_videoRecInvalidate();
@@ -5657,5 +5657,5 @@
 
             if (RT_FAILURE(vrc))
-                LogRel(("VideoRec: %s failed with %Rrc\n", fEnable ? "Enabling" : "Disabling", vrc));
+                LogRel(("Recording: %s failed with %Rrc\n", fEnable ? "Enabling" : "Disabling", vrc));
         }
         else /* Should not happen. */
@@ -7009,5 +7009,5 @@
         return VINF_SUCCESS;
 
-    LogRel(("VideoRec: Starting ...\n"));
+    LogRel(("Recording: Starting ...\n"));
 
     int rc = Capture.mpVideoRecCtx->Start();
@@ -7019,5 +7019,5 @@
 
     if (RT_FAILURE(rc))
-        LogRel(("VideoRec: Failed to start video recording (%Rrc)\n", rc));
+        LogRel(("Recording: Failed to start video recording (%Rrc)\n", rc));
 
     LogFlowFuncLeaveRC(rc);
@@ -7034,5 +7034,5 @@
         return VINF_SUCCESS;
 
-    LogRel(("VideoRec: Stopping ...\n"));
+    LogRel(("Recording: Stopping ...\n"));
 
     int rc = Capture.mpVideoRecCtx->Stop();
@@ -7049,8 +7049,8 @@
         ComAssertComRC(hrc);
 
-        LogRel(("VideoRec: Stopped\n"));
+        LogRel(("Recording: Stopped\n"));
     }
     else
-        LogRel(("VideoRec: Failed to stop video recording (%Rrc)\n", rc));
+        LogRel(("Recording: Failed to stop video recording (%Rrc)\n", rc));
 
     LogFlowFuncLeaveRC(rc);
@@ -10162,5 +10162,5 @@
             }
             else
-               LogRel(("VideoRec: Failed with %Rrc on VM power up\n", vrc2));
+               LogRel(("Recording: Failed with %Rrc on VM power up\n", vrc2));
 
             /** Note: Do not use vrc here, as starting the video recording isn't critical to
Index: /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 75343)
+++ /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 75344)
@@ -126,5 +126,5 @@
 #endif
 #ifdef VBOX_WITH_AUDIO_VIDEOREC
-# include "DrvAudioVideoRec.h"
+# include "DrvAudioRec.h"
 #endif
 #include "NetworkServiceRunner.h"
Index: /trunk/src/VBox/Main/src-client/DisplayImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/DisplayImpl.cpp	(revision 75343)
+++ /trunk/src/VBox/Main/src-client/DisplayImpl.cpp	(revision 75344)
@@ -55,5 +55,5 @@
 #ifdef VBOX_WITH_VIDEOREC
 # include <iprt/path.h>
-# include "VideoRec.h"
+# include "Recording.h"
 
 # ifdef VBOX_WITH_LIBVPX
Index: /trunk/src/VBox/Main/src-client/DrvAudioRec.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/DrvAudioRec.cpp	(revision 75344)
+++ /trunk/src/VBox/Main/src-client/DrvAudioRec.cpp	(revision 75344)
@@ -0,0 +1,1353 @@
+/* $Id$ */
+/** @file
+ * Video recording audio backend for Main.
+ */
+
+/*
+ * Copyright (C) 2016-2018 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.
+ */
+
+/* This code makes use of the Opus codec (libopus):
+ *
+ * Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic,
+ *                     Jean-Marc Valin, Timothy B. Terriberry,
+ *                     CSIRO, Gregory Maxwell, Mark Borgerding,
+ *                     Erik de Castro Lopo
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Internet Society, IETF or IETF Trust, nor the
+ * names of specific contributors, may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Opus is subject to the royalty-free patent licenses which are
+ * specified at:
+ *
+ * Xiph.Org Foundation:
+ * https://datatracker.ietf.org/ipr/1524/
+ *
+ * Microsoft Corporation:
+ * https://datatracker.ietf.org/ipr/1914/
+ *
+ * Broadcom Corporation:
+ * https://datatracker.ietf.org/ipr/1526/
+ *
+ */
+
+/**
+ * This driver is part of Main and is responsible for providing audio
+ * data to Main's video capturing feature.
+ *
+ * The driver itself implements a PDM host audio backend, which in turn
+ * provides the driver with the required audio data and audio events.
+ *
+ * For now there is support for the following destinations (called "sinks"):
+ *
+ * - Direct writing of .webm files to the host.
+ * - Communicating with Main via the Console object to send the encoded audio data to.
+ *   The Console object in turn then will route the data to the Display / video capturing interface then.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
+#include "LoggingNew.h"
+
+#include "DrvAudioRec.h"
+#include "ConsoleImpl.h"
+
+#include "../../Devices/Audio/DrvAudio.h"
+#include "WebMWriter.h"
+
+#include <iprt/mem.h>
+#include <iprt/cdefs.h>
+
+#include <VBox/vmm/pdmaudioifs.h>
+#include <VBox/vmm/pdmdrv.h>
+#include <VBox/vmm/cfgm.h>
+#include <VBox/err.h>
+
+#ifdef VBOX_WITH_LIBOPUS
+# include <opus.h>
+#endif
+
+
+/*********************************************************************************************************************************
+*   Defines                                                                                                                      *
+*********************************************************************************************************************************/
+
+#define AVREC_OPUS_HZ_MAX               48000           /** Maximum sample rate (in Hz) Opus can handle. */
+#define AVREC_OPUS_FRAME_MS_DEFAULT     20              /** Default Opus frame size (in ms). */
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+
+/**
+ * Enumeration for specifying the recording container type.
+ */
+typedef enum AVRECCONTAINERTYPE
+{
+    /** Unknown / invalid container type. */
+    AVRECCONTAINERTYPE_UNKNOWN      = 0,
+    /** Recorded data goes to Main / Console. */
+    AVRECCONTAINERTYPE_MAIN_CONSOLE = 1,
+    /** Recorded data will be written to a .webm file. */
+    AVRECCONTAINERTYPE_WEBM         = 2
+} AVRECCONTAINERTYPE;
+
+/**
+ * Structure for keeping generic container parameters.
+ */
+typedef struct AVRECCONTAINERPARMS
+{
+    /** The container's type. */
+    AVRECCONTAINERTYPE      enmType;
+    union
+    {
+        /** WebM file specifics. */
+        struct
+        {
+            /** Allocated file name to write .webm file to. Must be free'd. */
+            char *pszFile;
+        } WebM;
+    };
+
+} AVRECCONTAINERPARMS, *PAVRECCONTAINERPARMS;
+
+/**
+ * Structure for keeping container-specific data.
+ */
+typedef struct AVRECCONTAINER
+{
+    /** Generic container parameters. */
+    AVRECCONTAINERPARMS     Parms;
+
+    union
+    {
+        struct
+        {
+            /** Pointer to Console. */
+            Console        *pConsole;
+        } Main;
+
+        struct
+        {
+            /** Pointer to WebM container to write recorded audio data to.
+             *  See the AVRECMODE enumeration for more information. */
+            WebMWriter     *pWebM;
+            /** Assigned track number from WebM container. */
+            uint8_t         uTrack;
+        } WebM;
+    };
+} AVRECCONTAINER, *PAVRECCONTAINER;
+
+/**
+ * Structure for keeping generic codec parameters.
+ */
+typedef struct AVRECCODECPARMS
+{
+    /** The codec's used PCM properties. */
+    PDMAUDIOPCMPROPS        PCMProps;
+    /** The codec's bitrate. 0 if not used / cannot be specified. */
+    uint32_t                uBitrate;
+
+} AVRECCODECPARMS, *PAVRECCODECPARMS;
+
+/**
+ * Structure for keeping codec-specific data.
+ */
+typedef struct AVRECCODEC
+{
+    /** Generic codec parameters. */
+    AVRECCODECPARMS         Parms;
+    union
+    {
+#ifdef VBOX_WITH_LIBOPUS
+        struct
+        {
+            /** Encoder we're going to use. */
+            OpusEncoder    *pEnc;
+            /** Time (in ms) an (encoded) frame takes.
+             *
+             *  For Opus, valid frame sizes are:
+             *  ms           Frame size
+             *  2.5          120
+             *  5            240
+             *  10           480
+             *  20 (Default) 960
+             *  40           1920
+             *  60           2880
+             */
+            uint32_t        msFrame;
+            /** The frame size in bytes (based on msFrame). */
+            uint32_t        cbFrame;
+            /** The frame size in samples per frame (based on msFrame). */
+            uint32_t        csFrame;
+        } Opus;
+#endif /* VBOX_WITH_LIBOPUS */
+    };
+
+#ifdef VBOX_WITH_STATISTICS /** @todo Make these real STAM values. */
+    struct
+    {
+        /** Number of frames encoded. */
+        uint64_t        cEncFrames;
+        /** Total time (in ms) of already encoded audio data. */
+        uint64_t        msEncTotal;
+    } STAM;
+#endif /* VBOX_WITH_STATISTICS */
+
+} AVRECCODEC, *PAVRECCODEC;
+
+typedef struct AVRECSINK
+{
+    /** @todo Add types for container / codec as soon as we implement more stuff. */
+
+    /** Container data to use for data processing. */
+    AVRECCONTAINER       Con;
+    /** Codec data this sink uses for encoding. */
+    AVRECCODEC           Codec;
+    /** Timestamp (in ms) of when the sink was created. */
+    uint64_t             tsStartMs;
+} AVRECSINK, *PAVRECSINK;
+
+/**
+ * Audio video recording (output) stream.
+ */
+typedef struct AVRECSTREAM
+{
+    /** The stream's acquired configuration. */
+    PPDMAUDIOSTREAMCFG   pCfg;
+    /** (Audio) frame buffer. */
+    PRTCIRCBUF           pCircBuf;
+    /** Pointer to sink to use for writing. */
+    PAVRECSINK           pSink;
+    /** Last encoded PTS (in ms). */
+    uint64_t             uLastPTSMs;
+    /** Temporary buffer for the input (source) data to encode. */
+    void                *pvSrcBuf;
+    /** Size (in bytes) of the temporary buffer holding the input (source) data to encode. */
+    size_t               cbSrcBuf;
+    /** Temporary buffer for the encoded output (destination) data. */
+    void                *pvDstBuf;
+    /** Size (in bytes) of the temporary buffer holding the encoded output (destination) data. */
+    size_t               cbDstBuf;
+} AVRECSTREAM, *PAVRECSTREAM;
+
+/**
+ * Video recording audio driver instance data.
+ */
+typedef struct DRVAUDIOVIDEOREC
+{
+    /** Pointer to audio video recording object. */
+    AudioVideoRec       *pAudioVideoRec;
+    /** Pointer to the driver instance structure. */
+    PPDMDRVINS           pDrvIns;
+    /** Pointer to host audio interface. */
+    PDMIHOSTAUDIO        IHostAudio;
+    /** Pointer to the console object. */
+    ComPtr<Console>      pConsole;
+    /** Pointer to the DrvAudio port interface that is above us. */
+    PPDMIAUDIOCONNECTOR  pDrvAudio;
+    /** The driver's configured container parameters. */
+    AVRECCONTAINERPARMS  ContainerParms;
+    /** The driver's configured codec parameters. */
+    AVRECCODECPARMS      CodecParms;
+    /** The driver's sink for writing output to. */
+    AVRECSINK            Sink;
+} DRVAUDIOVIDEOREC, *PDRVAUDIOVIDEOREC;
+
+/** Makes DRVAUDIOVIDEOREC out of PDMIHOSTAUDIO. */
+#define PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface) /* (clang doesn't think it is a POD, thus _DYN.) */ \
+    ( (PDRVAUDIOVIDEOREC)((uintptr_t)pInterface - RT_UOFFSETOF_DYN(DRVAUDIOVIDEOREC, IHostAudio)) )
+
+/**
+ * Initializes a recording sink.
+ *
+ * @returns IPRT status code.
+ * @param   pThis               Driver instance.
+ * @param   pSink               Sink to initialize.
+ * @param   pConParms           Container parameters to set.
+ * @param   pCodecParms         Codec parameters to set.
+ */
+static int avRecSinkInit(PDRVAUDIOVIDEOREC pThis, PAVRECSINK pSink, PAVRECCONTAINERPARMS pConParms, PAVRECCODECPARMS pCodecParms)
+{
+    uint32_t uHz       = pCodecParms->PCMProps.uHz;
+    uint8_t  cBytes    = pCodecParms->PCMProps.cBytes;
+    uint8_t  cChannels = pCodecParms->PCMProps.cChannels;
+    uint32_t uBitrate  = pCodecParms->uBitrate;
+
+    /* Opus only supports certain input sample rates in an efficient manner.
+     * So make sure that we use those by resampling the data to the requested rate. */
+    if      (uHz > 24000) uHz = AVREC_OPUS_HZ_MAX;
+    else if (uHz > 16000) uHz = 24000;
+    else if (uHz > 12000) uHz = 16000;
+    else if (uHz > 8000 ) uHz = 12000;
+    else     uHz = 8000;
+
+    if (cChannels > 2)
+    {
+        LogRel(("Recording: Warning: More than 2 (stereo) channels are not supported at the moment\n"));
+        cChannels = 2;
+    }
+
+    int orc;
+    OpusEncoder *pEnc = opus_encoder_create(uHz, cChannels, OPUS_APPLICATION_AUDIO, &orc);
+    if (orc != OPUS_OK)
+    {
+        LogRel(("Recording: Audio codec failed to initialize: %s\n", opus_strerror(orc)));
+        return VERR_AUDIO_BACKEND_INIT_FAILED;
+    }
+
+    AssertPtr(pEnc);
+
+    if (uBitrate) /* Only explicitly set the bitrate if we specified one. Otherwise let Opus decide. */
+    {
+        opus_encoder_ctl(pEnc, OPUS_SET_BITRATE(uBitrate));
+        if (orc != OPUS_OK)
+        {
+            opus_encoder_destroy(pEnc);
+            pEnc = NULL;
+
+            LogRel(("Recording: Audio codec failed to set bitrate (%RU32): %s\n", uBitrate, opus_strerror(orc)));
+            return VERR_AUDIO_BACKEND_INIT_FAILED;
+        }
+    }
+
+    const bool fUseVBR = true; /** Use Variable Bit Rate (VBR) by default. @todo Make this configurable? */
+
+    orc = opus_encoder_ctl(pEnc, OPUS_SET_VBR(fUseVBR ? 1 : 0));
+    if (orc != OPUS_OK)
+    {
+        opus_encoder_destroy(pEnc);
+        pEnc = NULL;
+
+        LogRel(("Recording: Audio codec failed to %s VBR mode: %s\n", fUseVBR ? "enable" : "disable", opus_strerror(orc)));
+        return VERR_AUDIO_BACKEND_INIT_FAILED;
+    }
+
+    int rc = VINF_SUCCESS;
+
+    try
+    {
+        switch (pConParms->enmType)
+        {
+            case AVRECCONTAINERTYPE_MAIN_CONSOLE:
+            {
+                if (pThis->pConsole)
+                {
+                    pSink->Con.Main.pConsole = pThis->pConsole;
+                }
+                else
+                    rc = VERR_NOT_SUPPORTED;
+                break;
+            }
+
+            case AVRECCONTAINERTYPE_WEBM:
+            {
+                /* If we only record audio, create our own WebM writer instance here. */
+                if (!pSink->Con.WebM.pWebM) /* Do we already have our WebM writer instance? */
+                {
+                    /** @todo Add sink name / number to file name. */
+                    const char *pszFile = pSink->Con.Parms.WebM.pszFile;
+                    AssertPtr(pszFile);
+
+                    pSink->Con.WebM.pWebM = new WebMWriter();
+                    rc = pSink->Con.WebM.pWebM->Open(pszFile,
+                                                     /** @todo Add option to add some suffix if file exists instead of overwriting? */
+                                                     RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE,
+                                                     WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_None);
+                    if (RT_SUCCESS(rc))
+                    {
+                        rc = pSink->Con.WebM.pWebM->AddAudioTrack(uHz, cChannels, cBytes * 8 /* Bits */,
+                                                                  &pSink->Con.WebM.uTrack);
+                        if (RT_SUCCESS(rc))
+                        {
+                            LogRel(("Recording: Recording audio to audio file '%s'\n", pszFile));
+                        }
+                        else
+                            LogRel(("Recording: Error creating audio track for audio file '%s' (%Rrc)\n", pszFile, rc));
+                    }
+                    else
+                        LogRel(("Recording: Error creating audio file '%s' (%Rrc)\n", pszFile, rc));
+                }
+                break;
+            }
+
+            default:
+                rc = VERR_NOT_SUPPORTED;
+                break;
+        }
+    }
+    catch (std::bad_alloc &)
+    {
+        rc = VERR_NO_MEMORY;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        pSink->Con.Parms.enmType     = pConParms->enmType;
+
+        PAVRECCODEC pCodec = &pSink->Codec;
+
+        pCodec->Parms.PCMProps.uHz       = uHz;
+        pCodec->Parms.PCMProps.cChannels = cChannels;
+        pCodec->Parms.PCMProps.cBytes    = cBytes;
+        pCodec->Parms.PCMProps.cShift    = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pSink->Codec.Parms.PCMProps.cBytes,
+                                                                             pSink->Codec.Parms.PCMProps.cChannels);
+        pCodec->Parms.uBitrate           = uBitrate;
+
+        pCodec->Opus.pEnc       = pEnc;
+        pCodec->Opus.msFrame    = AVREC_OPUS_FRAME_MS_DEFAULT;
+
+        if (!pCodec->Opus.msFrame)
+            pCodec->Opus.msFrame = AVREC_OPUS_FRAME_MS_DEFAULT; /* 20ms by default; to prevent division by zero. */
+        pCodec->Opus.csFrame = pSink->Codec.Parms.PCMProps.uHz / (1000 /* s in ms */ / pSink->Codec.Opus.msFrame);
+        pCodec->Opus.cbFrame = DrvAudioHlpFramesToBytes(pCodec->Opus.csFrame, &pSink->Codec.Parms.PCMProps);
+
+#ifdef VBOX_WITH_STATISTICS
+        pSink->Codec.STAM.cEncFrames = 0;
+        pSink->Codec.STAM.msEncTotal = 0;
+#endif
+        pSink->tsStartMs             = RTTimeMilliTS();
+    }
+    else
+    {
+        if (pEnc)
+        {
+            opus_encoder_destroy(pEnc);
+            pEnc = NULL;
+        }
+
+        LogRel(("Recording: Error creating sink (%Rrc)\n", rc));
+    }
+
+    return rc;
+}
+
+
+/**
+ * Shuts down (closes) a recording sink,
+ *
+ * @returns IPRT status code.
+ * @param   pSink               Recording sink to shut down.
+ */
+static void avRecSinkShutdown(PAVRECSINK pSink)
+{
+    AssertPtrReturnVoid(pSink);
+
+#ifdef VBOX_WITH_LIBOPUS
+    if (pSink->Codec.Opus.pEnc)
+    {
+        opus_encoder_destroy(pSink->Codec.Opus.pEnc);
+        pSink->Codec.Opus.pEnc = NULL;
+    }
+#endif
+    switch (pSink->Con.Parms.enmType)
+    {
+        case AVRECCONTAINERTYPE_WEBM:
+        {
+            if (pSink->Con.WebM.pWebM)
+            {
+                LogRel2(("Recording: Finished recording audio to file '%s' (%zu bytes)\n",
+                         pSink->Con.WebM.pWebM->GetFileName().c_str(), pSink->Con.WebM.pWebM->GetFileSize()));
+
+                int rc2 = pSink->Con.WebM.pWebM->Close();
+                AssertRC(rc2);
+
+                delete pSink->Con.WebM.pWebM;
+                pSink->Con.WebM.pWebM = NULL;
+            }
+            break;
+        }
+
+        case AVRECCONTAINERTYPE_MAIN_CONSOLE:
+        default:
+            break;
+    }
+}
+
+
+/**
+ * Creates an audio output stream and associates it with the specified recording sink.
+ *
+ * @returns IPRT status code.
+ * @param   pThis               Driver instance.
+ * @param   pStreamAV           Audio output stream to create.
+ * @param   pSink               Recording sink to associate audio output stream to.
+ * @param   pCfgReq             Requested configuration by the audio backend.
+ * @param   pCfgAcq             Acquired configuration by the audio output stream.
+ */
+static int avRecCreateStreamOut(PDRVAUDIOVIDEOREC pThis, PAVRECSTREAM pStreamAV,
+                                PAVRECSINK pSink, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+{
+    AssertPtrReturn(pThis,     VERR_INVALID_POINTER);
+    AssertPtrReturn(pStreamAV, VERR_INVALID_POINTER);
+    AssertPtrReturn(pSink,     VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgReq,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgAcq,   VERR_INVALID_POINTER);
+
+    if (pCfgReq->DestSource.Dest != PDMAUDIOPLAYBACKDEST_FRONT)
+    {
+        AssertFailed();
+
+        LogRel2(("Recording: Support for surround audio not implemented yet\n"));
+        return VERR_NOT_SUPPORTED;
+    }
+
+    int rc = VINF_SUCCESS;
+
+#ifdef VBOX_WITH_LIBOPUS
+    rc = RTCircBufCreate(&pStreamAV->pCircBuf, pSink->Codec.Opus.cbFrame * 2 /* Use "double buffering" */);
+    if (RT_SUCCESS(rc))
+    {
+        size_t cbScratchBuf = pSink->Codec.Opus.cbFrame;
+        pStreamAV->pvSrcBuf = RTMemAlloc(cbScratchBuf);
+        if (pStreamAV->pvSrcBuf)
+        {
+            pStreamAV->cbSrcBuf = cbScratchBuf;
+            pStreamAV->pvDstBuf = RTMemAlloc(cbScratchBuf);
+            if (pStreamAV->pvDstBuf)
+            {
+                pStreamAV->cbDstBuf = cbScratchBuf;
+
+                pStreamAV->pSink      = pSink; /* Assign sink to stream. */
+                pStreamAV->uLastPTSMs = 0;
+
+                if (pCfgAcq)
+                {
+                    /* Make sure to let the driver backend know that we need the audio data in
+                     * a specific sampling rate Opus is optimized for. */
+                    pCfgAcq->Props.uHz         = pSink->Codec.Parms.PCMProps.uHz;
+                    pCfgAcq->Props.cShift      = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfgAcq->Props.cBytes, pCfgAcq->Props.cChannels);
+
+                    /* Every Opus frame marks a period for now. Optimize this later. */
+                    pCfgAcq->Backend.cfPeriod     = DrvAudioHlpMilliToFrames(pSink->Codec.Opus.msFrame, &pCfgAcq->Props);
+                    pCfgAcq->Backend.cfBufferSize = DrvAudioHlpMilliToFrames(100 /* ms */, &pCfgAcq->Props); /** @todo Make this configurable. */
+                    pCfgAcq->Backend.cfPreBuf     = pCfgAcq->Backend.cfPeriod * 2;
+                }
+            }
+            else
+                rc = VERR_NO_MEMORY;
+        }
+        else
+            rc = VERR_NO_MEMORY;
+    }
+#else
+    RT_NOREF(pThis, pSink, pStreamAV, pCfgReq, pCfgAcq);
+    rc = VERR_NOT_SUPPORTED;
+#endif /* VBOX_WITH_LIBOPUS */
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+
+/**
+ * Destroys (closes) an audio output stream.
+ *
+ * @returns IPRT status code.
+ * @param   pThis               Driver instance.
+ * @param   pStreamAV           Audio output stream to destroy.
+ */
+static int avRecDestroyStreamOut(PDRVAUDIOVIDEOREC pThis, PAVRECSTREAM pStreamAV)
+{
+    RT_NOREF(pThis);
+
+    if (pStreamAV->pCircBuf)
+    {
+        RTCircBufDestroy(pStreamAV->pCircBuf);
+        pStreamAV->pCircBuf = NULL;
+    }
+
+    if (pStreamAV->pvSrcBuf)
+    {
+        Assert(pStreamAV->cbSrcBuf);
+        RTMemFree(pStreamAV->pvSrcBuf);
+        pStreamAV->cbSrcBuf = 0;
+    }
+
+    if (pStreamAV->pvDstBuf)
+    {
+        Assert(pStreamAV->cbDstBuf);
+        RTMemFree(pStreamAV->pvDstBuf);
+        pStreamAV->cbDstBuf = 0;
+    }
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Controls an audio output stream
+ *
+ * @returns IPRT status code.
+ * @param   pThis               Driver instance.
+ * @param   pStreamAV           Audio output stream to control.
+ * @param   enmStreamCmd        Stream command to issue.
+ */
+static int avRecControlStreamOut(PDRVAUDIOVIDEOREC pThis,
+                                 PAVRECSTREAM pStreamAV, PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    RT_NOREF(pThis, pStreamAV);
+
+    int rc = VINF_SUCCESS;
+
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        case PDMAUDIOSTREAMCMD_RESUME:
+        case PDMAUDIOSTREAMCMD_PAUSE:
+            break;
+
+        default:
+            rc = VERR_NOT_SUPPORTED;
+            break;
+    }
+
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
+ */
+static DECLCALLBACK(int) drvAudioVideoRecInit(PPDMIHOSTAUDIO pInterface)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+
+    LogFlowFuncEnter();
+
+    PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
+
+    LogRel(("Recording: Audio driver is using %RU32Hz, %RU16bit, %RU8 %s\n",
+            pThis->CodecParms.PCMProps.uHz, pThis->CodecParms.PCMProps.cBytes * 8,
+            pThis->CodecParms.PCMProps.cChannels, pThis->CodecParms.PCMProps.cChannels == 1 ? "channel" : "channels"));
+
+    int rc = avRecSinkInit(pThis, &pThis->Sink, &pThis->ContainerParms, &pThis->CodecParms);
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("Recording: Audio recording driver failed to initialize, rc=%Rrc\n", rc));
+    }
+    else
+        LogRel2(("Recording: Audio recording driver initialized\n"));
+
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
+ */
+static DECLCALLBACK(int) drvAudioVideoRecStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
+                                                       void *pvBuf, uint32_t cxBuf, uint32_t *pcxRead)
+{
+    RT_NOREF(pInterface, pStream, pvBuf, cxBuf);
+
+    if (pcxRead)
+        *pcxRead = 0;
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
+ */
+static DECLCALLBACK(int) drvAudioVideoRecStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
+                                                    const void *pvBuf, uint32_t cxBuf, uint32_t *pcxWritten)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+    AssertPtrReturn(pvBuf,      VERR_INVALID_POINTER);
+    AssertReturn(cxBuf,         VERR_INVALID_PARAMETER);
+    /* pcxWritten is optional. */
+
+    PDRVAUDIOVIDEOREC pThis     = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
+    RT_NOREF(pThis);
+    PAVRECSTREAM      pStreamAV = (PAVRECSTREAM)pStream;
+
+    int rc = VINF_SUCCESS;
+
+    uint32_t cbWrittenTotal = 0;
+
+    /*
+     * Call the encoder with the data.
+     */
+#ifdef VBOX_WITH_LIBOPUS
+    PAVRECSINK pSink    = pStreamAV->pSink;
+    AssertPtr(pSink);
+    PAVRECCODEC pCodec  = &pSink->Codec;
+    AssertPtr(pCodec);
+    PRTCIRCBUF pCircBuf = pStreamAV->pCircBuf;
+    AssertPtr(pCircBuf);
+
+    void  *pvCircBuf;
+    size_t cbCircBuf;
+
+    uint32_t cbToWrite = cxBuf;
+
+    /*
+     * Fetch as much as we can into our internal ring buffer.
+     */
+    while (   cbToWrite
+           && RTCircBufFree(pCircBuf))
+    {
+        RTCircBufAcquireWriteBlock(pCircBuf, cbToWrite, &pvCircBuf, &cbCircBuf);
+
+        if (cbCircBuf)
+        {
+            memcpy(pvCircBuf, (uint8_t *)pvBuf + cbWrittenTotal, cbCircBuf),
+            cbWrittenTotal += (uint32_t)cbCircBuf;
+            Assert(cbToWrite >= cbCircBuf);
+            cbToWrite      -= (uint32_t)cbCircBuf;
+        }
+
+        RTCircBufReleaseWriteBlock(pCircBuf, cbCircBuf);
+
+        if (   RT_FAILURE(rc)
+            || !cbCircBuf)
+        {
+            break;
+        }
+    }
+
+    /*
+     * Process our internal ring buffer and encode the data.
+     */
+
+    uint32_t cbSrc;
+
+    /* Only encode data if we have data for the given time period (or more). */
+    while (RTCircBufUsed(pCircBuf) >= pCodec->Opus.cbFrame)
+    {
+        LogFunc(("cbAvail=%zu, csFrame=%RU32, cbFrame=%RU32\n",
+                 RTCircBufUsed(pCircBuf), pCodec->Opus.csFrame, pCodec->Opus.cbFrame));
+
+        cbSrc = 0;
+
+        while (cbSrc < pCodec->Opus.cbFrame)
+        {
+            RTCircBufAcquireReadBlock(pCircBuf, pCodec->Opus.cbFrame - cbSrc, &pvCircBuf, &cbCircBuf);
+
+            if (cbCircBuf)
+            {
+                memcpy((uint8_t *)pStreamAV->pvSrcBuf + cbSrc, pvCircBuf, cbCircBuf);
+
+                cbSrc += (uint32_t)cbCircBuf;
+                Assert(cbSrc <= pStreamAV->cbSrcBuf);
+            }
+
+            RTCircBufReleaseReadBlock(pCircBuf, cbCircBuf);
+
+            if (!cbCircBuf)
+                break;
+        }
+
+# ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
+        RTFILE fh;
+        RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "DrvAudioVideoRec.pcm",
+                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+        RTFileWrite(fh, pStreamAV->pvSrcBuf, cbSrc, NULL);
+        RTFileClose(fh);
+# endif
+
+        Assert(cbSrc == pCodec->Opus.cbFrame);
+
+        /*
+         * Opus always encodes PER "OPUS FRAME", that is, exactly 2.5, 5, 10, 20, 40 or 60 ms of audio data.
+         *
+         * A packet can have up to 120ms worth of audio data.
+         * Anything > 120ms of data will result in a "corrupted package" error message by
+         * by decoding application.
+         */
+
+        /* Call the encoder to encode one "Opus frame" per iteration. */
+        opus_int32 cbWritten = opus_encode(pSink->Codec.Opus.pEnc,
+                                           (opus_int16 *)pStreamAV->pvSrcBuf, pCodec->Opus.csFrame,
+                                           (uint8_t *)pStreamAV->pvDstBuf, (opus_int32)pStreamAV->cbDstBuf);
+        if (cbWritten > 0)
+        {
+            /* Get overall frames encoded. */
+            const uint32_t cEncFrames     = opus_packet_get_nb_frames((uint8_t *)pStreamAV->pvDstBuf, cbWritten);
+
+# ifdef VBOX_WITH_STATISTICS
+            pSink->Codec.STAM.cEncFrames += cEncFrames;
+            pSink->Codec.STAM.msEncTotal += pSink->Codec.Opus.msFrame * cEncFrames;
+# endif
+            Assert((uint32_t)cbWritten <= (uint32_t)pStreamAV->cbDstBuf);
+            const uint32_t cbDst = RT_MIN((uint32_t)cbWritten, (uint32_t)pStreamAV->cbDstBuf);
+
+            Assert(cEncFrames == 1);
+
+            if (pStreamAV->uLastPTSMs == 0)
+                pStreamAV->uLastPTSMs = RTTimeProgramMilliTS(); /* We want the absolute time (in ms) since program start. */
+
+            const uint64_t uDurationMs = pSink->Codec.Opus.msFrame * cEncFrames;
+            const uint64_t uPTSMs      = pStreamAV->uLastPTSMs;
+
+            pStreamAV->uLastPTSMs += uDurationMs;
+
+            switch (pSink->Con.Parms.enmType)
+            {
+                case AVRECCONTAINERTYPE_MAIN_CONSOLE:
+                {
+                    HRESULT hr = pSink->Con.Main.pConsole->i_videoRecSendAudio(pStreamAV->pvDstBuf, cbDst, uPTSMs);
+                    Assert(hr == S_OK);
+                    RT_NOREF(hr);
+
+                    break;
+                }
+
+                case AVRECCONTAINERTYPE_WEBM:
+                {
+                    WebMWriter::BlockData_Opus blockData = { pStreamAV->pvDstBuf, cbDst, uPTSMs };
+                    rc = pSink->Con.WebM.pWebM->WriteBlock(pSink->Con.WebM.uTrack, &blockData, sizeof(blockData));
+                    AssertRC(rc);
+
+                    break;
+                }
+
+                default:
+                    AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
+                    break;
+            }
+        }
+        else if (cbWritten < 0)
+        {
+            AssertMsgFailed(("Encoding failed: %s\n", opus_strerror(cbWritten)));
+            rc = VERR_INVALID_PARAMETER;
+        }
+
+        if (RT_FAILURE(rc))
+            break;
+    }
+
+    if (pcxWritten)
+        *pcxWritten = cbWrittenTotal;
+#else
+    /* Report back all data as being processed. */
+    if (pcxWritten)
+        *pcxWritten = cxBuf;
+
+    rc = VERR_NOT_SUPPORTED;
+#endif /* VBOX_WITH_LIBOPUS */
+
+    LogFlowFunc(("csReadTotal=%RU32, rc=%Rrc\n", cbWrittenTotal, rc));
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
+ */
+static DECLCALLBACK(int) drvAudioVideoRecGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
+{
+    RT_NOREF(pInterface);
+    AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
+
+    RTStrPrintf2(pBackendCfg->szName, sizeof(pBackendCfg->szName), "Video recording audio driver");
+
+    pBackendCfg->cbStreamOut    = sizeof(AVRECSTREAM);
+    pBackendCfg->cbStreamIn     = 0;
+    pBackendCfg->cMaxStreamsIn  = 0;
+    pBackendCfg->cMaxStreamsOut = UINT32_MAX;
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
+ */
+static DECLCALLBACK(void) drvAudioVideoRecShutdown(PPDMIHOSTAUDIO pInterface)
+{
+    LogFlowFuncEnter();
+
+    PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
+
+    avRecSinkShutdown(&pThis->Sink);
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
+ */
+static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioVideoRecGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+    RT_NOREF(enmDir);
+    AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
+
+    return PDMAUDIOBACKENDSTS_RUNNING;
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
+ */
+static DECLCALLBACK(int) drvAudioVideoRecStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
+                                                      PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgAcq,    VERR_INVALID_POINTER);
+
+    if (pCfgReq->enmDir == PDMAUDIODIR_IN)
+        return VERR_NOT_SUPPORTED;
+
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+
+    PDRVAUDIOVIDEOREC pThis     = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
+    PAVRECSTREAM      pStreamAV = (PAVRECSTREAM)pStream;
+
+    /* For now we only have one sink, namely the driver's one.
+     * Later each stream could have its own one, to e.g. router different stream to different sinks .*/
+    PAVRECSINK pSink = &pThis->Sink;
+
+    int rc = avRecCreateStreamOut(pThis, pStreamAV, pSink, pCfgReq, pCfgAcq);
+    if (RT_SUCCESS(rc))
+    {
+        pStreamAV->pCfg = DrvAudioHlpStreamCfgDup(pCfgAcq);
+        if (!pStreamAV->pCfg)
+            rc = VERR_NO_MEMORY;
+    }
+
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
+ */
+static DECLCALLBACK(int) drvAudioVideoRecStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+
+    PDRVAUDIOVIDEOREC pThis     = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
+    PAVRECSTREAM      pStreamAV = (PAVRECSTREAM)pStream;
+
+    if (!pStreamAV->pCfg) /* Not (yet) configured? Skip. */
+        return VINF_SUCCESS;
+
+    int rc = VINF_SUCCESS;
+
+    if (pStreamAV->pCfg->enmDir == PDMAUDIODIR_OUT)
+        rc = avRecDestroyStreamOut(pThis, pStreamAV);
+
+    if (RT_SUCCESS(rc))
+    {
+        DrvAudioHlpStreamCfgFree(pStreamAV->pCfg);
+        pStreamAV->pCfg = NULL;
+    }
+
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
+ */
+static DECLCALLBACK(int) drvAudioVideoRecStreamControl(PPDMIHOSTAUDIO pInterface,
+                                                       PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+
+    PDRVAUDIOVIDEOREC pThis     = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
+    PAVRECSTREAM      pStreamAV = (PAVRECSTREAM)pStream;
+
+    if (!pStreamAV->pCfg) /* Not (yet) configured? Skip. */
+        return VINF_SUCCESS;
+
+    if (pStreamAV->pCfg->enmDir == PDMAUDIODIR_OUT)
+        return avRecControlStreamOut(pThis, pStreamAV, enmStreamCmd);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
+ */
+static DECLCALLBACK(uint32_t) drvAudioVideoRecStreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
+{
+    RT_NOREF(pInterface, pStream);
+
+    return 0; /* Video capturing does not provide any input. */
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
+ */
+static DECLCALLBACK(uint32_t) drvAudioVideoRecStreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
+{
+    RT_NOREF(pInterface, pStream);
+
+    return UINT32_MAX;
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
+ */
+static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvAudioVideoRecStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
+{
+    RT_NOREF(pInterface, pStream);
+
+    return (PDMAUDIOSTREAMSTS_FLAG_INITIALIZED | PDMAUDIOSTREAMSTS_FLAG_ENABLED);
+}
+
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
+ */
+static DECLCALLBACK(int) drvAudioVideoRecStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+
+    LogFlowFuncEnter();
+
+    /* Nothing to do here for video recording. */
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvAudioVideoRecQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
+
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
+    return NULL;
+}
+
+
+AudioVideoRec::AudioVideoRec(Console *pConsole)
+    : AudioDriver(pConsole)
+    , mpDrv(NULL)
+{
+}
+
+
+AudioVideoRec::~AudioVideoRec(void)
+{
+    if (mpDrv)
+    {
+        mpDrv->pAudioVideoRec = NULL;
+        mpDrv = NULL;
+    }
+}
+
+
+/**
+ * Applies a video recording configuration to this driver instance.
+ *
+ * @returns IPRT status code.
+ * @param   Settings        Capturing configuration to apply.
+ */
+int AudioVideoRec::applyConfiguration(const settings::RecordSettings &Settings)
+{
+    /** @todo Do some validation here. */
+    mVideoRecCfg = Settings; /* Note: Does have an own copy operator. */
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc AudioDriver::configureDriver
+ */
+int AudioVideoRec::configureDriver(PCFGMNODE pLunCfg)
+{
+    int rc = CFGMR3InsertInteger(pLunCfg, "Object",    (uintptr_t)mpConsole->i_videoRecGetAudioDrv());
+    AssertRCReturn(rc, rc);
+    rc = CFGMR3InsertInteger(pLunCfg, "ObjectConsole", (uintptr_t)mpConsole);
+    AssertRCReturn(rc, rc);
+
+    /** @todo For now we're using the configuration of the first screen here audio-wise. */
+    Assert(mVideoRecCfg.mapScreens.size() >= 1);
+    const settings::RecordScreenSettings &Screen0Settings = mVideoRecCfg.mapScreens[0];
+
+    rc = CFGMR3InsertInteger(pLunCfg, "ContainerType", (uint64_t)Screen0Settings.enmDest);
+    AssertRCReturn(rc, rc);
+    if (Screen0Settings.enmDest == RecordDestination_File)
+    {
+        rc = CFGMR3InsertString(pLunCfg, "ContainerFileName", Utf8Str(Screen0Settings.File.strName).c_str());
+        AssertRCReturn(rc, rc);
+    }
+    rc = CFGMR3InsertInteger(pLunCfg, "CodecHz", Screen0Settings.Audio.uHz);
+    AssertRCReturn(rc, rc);
+    rc = CFGMR3InsertInteger(pLunCfg, "CodecBits", Screen0Settings.Audio.cBits);
+    AssertRCReturn(rc, rc);
+    rc = CFGMR3InsertInteger(pLunCfg, "CodecChannels", Screen0Settings.Audio.cChannels);
+    AssertRCReturn(rc, rc);
+    rc = CFGMR3InsertInteger(pLunCfg, "CodecBitrate", 0); /* Let Opus decide for now. */
+    AssertRCReturn(rc, rc);
+
+    return AudioDriver::configureDriver(pLunCfg);
+}
+
+
+/**
+ * Construct a audio video recording driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+/* static */
+DECLCALLBACK(int) AudioVideoRec::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+    PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
+    RT_NOREF(fFlags);
+
+    LogRel(("Audio: Initializing video recording audio driver\n"));
+    LogFlowFunc(("fFlags=0x%x\n", fFlags));
+
+    AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
+                    ("Configuration error: Not possible to attach anything to this driver!\n"),
+                    VERR_PDM_DRVINS_NO_ATTACH);
+
+    /*
+     * Init the static parts.
+     */
+    pThis->pDrvIns                   = pDrvIns;
+    /* IBase */
+    pDrvIns->IBase.pfnQueryInterface = drvAudioVideoRecQueryInterface;
+    /* IHostAudio */
+    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVideoRec);
+
+    /*
+     * Get the Console object pointer.
+     */
+    void *pvUser;
+    int rc = CFGMR3QueryPtr(pCfg, "ObjectConsole", &pvUser); /** @todo r=andy Get rid of this hack and use IHostAudio::SetCallback. */
+    AssertRCReturn(rc, rc);
+
+    /* CFGM tree saves the pointer to Console in the Object node of AudioVideoRec. */
+    pThis->pConsole = (Console *)pvUser;
+    AssertReturn(!pThis->pConsole.isNull(), VERR_INVALID_POINTER);
+
+    /*
+     * Get the pointer to the audio driver instance.
+     */
+    rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser); /** @todo r=andy Get rid of this hack and use IHostAudio::SetCallback. */
+    AssertRCReturn(rc, rc);
+
+    pThis->pAudioVideoRec = (AudioVideoRec *)pvUser;
+    AssertPtrReturn(pThis->pAudioVideoRec, VERR_INVALID_POINTER);
+
+    /*
+     * Get the recording container and codec parameters from the audio driver instance.
+     */
+    PAVRECCONTAINERPARMS pConParams  = &pThis->ContainerParms;
+    PAVRECCODECPARMS     pCodecParms = &pThis->CodecParms;
+    PPDMAUDIOPCMPROPS    pPCMProps   = &pCodecParms->PCMProps;
+
+    RT_ZERO(pThis->ContainerParms);
+    RT_ZERO(pThis->CodecParms);
+
+    rc = CFGMR3QueryU32(pCfg, "ContainerType", (uint32_t *)&pConParams->enmType);
+    AssertRCReturn(rc, rc);
+
+    switch (pConParams->enmType)
+    {
+        case AVRECCONTAINERTYPE_WEBM:
+            rc = CFGMR3QueryStringAlloc(pCfg, "ContainerFileName", &pConParams->WebM.pszFile);
+            AssertRCReturn(rc, rc);
+            break;
+
+        default:
+            break;
+    }
+
+    rc = CFGMR3QueryU32(pCfg, "CodecHz", &pPCMProps->uHz);
+    AssertRCReturn(rc, rc);
+    rc = CFGMR3QueryU8(pCfg,  "CodecBits", &pPCMProps->cBytes);
+    AssertRCReturn(rc, rc);
+    rc = CFGMR3QueryU8(pCfg,  "CodecChannels", &pPCMProps->cChannels);
+    AssertRCReturn(rc, rc);
+    rc = CFGMR3QueryU32(pCfg, "CodecBitrate", &pCodecParms->uBitrate);
+    AssertRCReturn(rc, rc);
+
+    pPCMProps->cBytes      = pPCMProps->cBytes / 8; /* Bits to bytes. */
+    pPCMProps->cShift      = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pPCMProps->cBytes, pPCMProps->cChannels);
+    pPCMProps->fSigned     = true;
+    pPCMProps->fSwapEndian = false;
+
+    AssertMsgReturn(DrvAudioHlpPCMPropsAreValid(pPCMProps),
+                    ("Configuration error: Audio configuration is invalid!\n"), VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES);
+
+    pThis->pAudioVideoRec = (AudioVideoRec *)pvUser;
+    AssertPtrReturn(pThis->pAudioVideoRec, VERR_INVALID_POINTER);
+
+    pThis->pAudioVideoRec->mpDrv = pThis;
+
+    /*
+     * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
+     * Described in CFGM tree.
+     */
+    pThis->pDrvAudio = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
+    AssertMsgReturn(pThis->pDrvAudio, ("Configuration error: No upper interface specified!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
+
+#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
+    RTFileDelete(VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "DrvAudioVideoRec.webm");
+    RTFileDelete(VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "DrvAudioVideoRec.pcm");
+#endif
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMDRVREG,pfnDestruct}
+ */
+/* static */
+DECLCALLBACK(void) AudioVideoRec::drvDestruct(PPDMDRVINS pDrvIns)
+{
+    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+    PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
+
+    LogFlowFuncEnter();
+
+    switch (pThis->ContainerParms.enmType)
+    {
+        case AVRECCONTAINERTYPE_WEBM:
+        {
+            avRecSinkShutdown(&pThis->Sink);
+            RTStrFree(pThis->ContainerParms.WebM.pszFile);
+            break;
+        }
+
+        default:
+            break;
+    }
+
+    /*
+     * If the AudioVideoRec object is still alive, we must clear it's reference to
+     * us since we'll be invalid when we return from this method.
+     */
+    if (pThis->pAudioVideoRec)
+    {
+        pThis->pAudioVideoRec->mpDrv = NULL;
+        pThis->pAudioVideoRec = NULL;
+    }
+
+    LogFlowFuncLeave();
+}
+
+
+/**
+ * @interface_method_impl{PDMDRVREG,pfnAttach}
+ */
+/* static */
+DECLCALLBACK(int) AudioVideoRec::drvAttach(PPDMDRVINS pDrvIns, uint32_t fFlags)
+{
+    RT_NOREF(pDrvIns, fFlags);
+
+    LogFlowFuncEnter();
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * @interface_method_impl{PDMDRVREG,pfnDetach}
+ */
+/* static */
+DECLCALLBACK(void) AudioVideoRec::drvDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
+{
+    RT_NOREF(pDrvIns, fFlags);
+
+    LogFlowFuncEnter();
+}
+
+/**
+ * Video recording audio driver registration record.
+ */
+const PDMDRVREG AudioVideoRec::DrvReg =
+{
+    PDM_DRVREG_VERSION,
+    /* szName */
+    "AudioVideoRec",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "Audio driver for video recording",
+    /* fFlags */
+    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+    /* fClass. */
+    PDM_DRVREG_CLASS_AUDIO,
+    /* cMaxInstances */
+    ~0U,
+    /* cbInstance */
+    sizeof(DRVAUDIOVIDEOREC),
+    /* pfnConstruct */
+    AudioVideoRec::drvConstruct,
+    /* pfnDestruct */
+    AudioVideoRec::drvDestruct,
+    /* pfnRelocate */
+    NULL,
+    /* pfnIOCtl */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    NULL,
+    /* pfnSuspend */
+    NULL,
+    /* pfnResume */
+    NULL,
+    /* pfnAttach */
+    AudioVideoRec::drvAttach,
+    /* pfnDetach */
+    AudioVideoRec::drvDetach,
+    /* pfnPowerOff */
+    NULL,
+    /* pfnSoftReset */
+    NULL,
+    /* u32EndVersion */
+    PDM_DRVREG_VERSION
+};
+
Index: unk/src/VBox/Main/src-client/DrvAudioVideoRec.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/DrvAudioVideoRec.cpp	(revision 75343)
+++ 	(revision )
@@ -1,1353 +1,0 @@
-/* $Id$ */
-/** @file
- * Video recording audio backend for Main.
- */
-
-/*
- * Copyright (C) 2016-2018 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.
- */
-
-/* This code makes use of the Opus codec (libopus):
- *
- * Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic,
- *                     Jean-Marc Valin, Timothy B. Terriberry,
- *                     CSIRO, Gregory Maxwell, Mark Borgerding,
- *                     Erik de Castro Lopo
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of Internet Society, IETF or IETF Trust, nor the
- * names of specific contributors, may be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Opus is subject to the royalty-free patent licenses which are
- * specified at:
- *
- * Xiph.Org Foundation:
- * https://datatracker.ietf.org/ipr/1524/
- *
- * Microsoft Corporation:
- * https://datatracker.ietf.org/ipr/1914/
- *
- * Broadcom Corporation:
- * https://datatracker.ietf.org/ipr/1526/
- *
- */
-
-/**
- * This driver is part of Main and is responsible for providing audio
- * data to Main's video capturing feature.
- *
- * The driver itself implements a PDM host audio backend, which in turn
- * provides the driver with the required audio data and audio events.
- *
- * For now there is support for the following destinations (called "sinks"):
- *
- * - Direct writing of .webm files to the host.
- * - Communicating with Main via the Console object to send the encoded audio data to.
- *   The Console object in turn then will route the data to the Display / video capturing interface then.
- */
-
-
-/*********************************************************************************************************************************
-*   Header Files                                                                                                                 *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
-#include "LoggingNew.h"
-
-#include "DrvAudioVideoRec.h"
-#include "ConsoleImpl.h"
-
-#include "../../Devices/Audio/DrvAudio.h"
-#include "WebMWriter.h"
-
-#include <iprt/mem.h>
-#include <iprt/cdefs.h>
-
-#include <VBox/vmm/pdmaudioifs.h>
-#include <VBox/vmm/pdmdrv.h>
-#include <VBox/vmm/cfgm.h>
-#include <VBox/err.h>
-
-#ifdef VBOX_WITH_LIBOPUS
-# include <opus.h>
-#endif
-
-
-/*********************************************************************************************************************************
-*   Defines                                                                                                                      *
-*********************************************************************************************************************************/
-
-#define AVREC_OPUS_HZ_MAX               48000           /** Maximum sample rate (in Hz) Opus can handle. */
-#define AVREC_OPUS_FRAME_MS_DEFAULT     20              /** Default Opus frame size (in ms). */
-
-
-/*********************************************************************************************************************************
-*   Structures and Typedefs                                                                                                      *
-*********************************************************************************************************************************/
-
-/**
- * Enumeration for specifying the recording container type.
- */
-typedef enum AVRECCONTAINERTYPE
-{
-    /** Unknown / invalid container type. */
-    AVRECCONTAINERTYPE_UNKNOWN      = 0,
-    /** Recorded data goes to Main / Console. */
-    AVRECCONTAINERTYPE_MAIN_CONSOLE = 1,
-    /** Recorded data will be written to a .webm file. */
-    AVRECCONTAINERTYPE_WEBM         = 2
-} AVRECCONTAINERTYPE;
-
-/**
- * Structure for keeping generic container parameters.
- */
-typedef struct AVRECCONTAINERPARMS
-{
-    /** The container's type. */
-    AVRECCONTAINERTYPE      enmType;
-    union
-    {
-        /** WebM file specifics. */
-        struct
-        {
-            /** Allocated file name to write .webm file to. Must be free'd. */
-            char *pszFile;
-        } WebM;
-    };
-
-} AVRECCONTAINERPARMS, *PAVRECCONTAINERPARMS;
-
-/**
- * Structure for keeping container-specific data.
- */
-typedef struct AVRECCONTAINER
-{
-    /** Generic container parameters. */
-    AVRECCONTAINERPARMS     Parms;
-
-    union
-    {
-        struct
-        {
-            /** Pointer to Console. */
-            Console        *pConsole;
-        } Main;
-
-        struct
-        {
-            /** Pointer to WebM container to write recorded audio data to.
-             *  See the AVRECMODE enumeration for more information. */
-            WebMWriter     *pWebM;
-            /** Assigned track number from WebM container. */
-            uint8_t         uTrack;
-        } WebM;
-    };
-} AVRECCONTAINER, *PAVRECCONTAINER;
-
-/**
- * Structure for keeping generic codec parameters.
- */
-typedef struct AVRECCODECPARMS
-{
-    /** The codec's used PCM properties. */
-    PDMAUDIOPCMPROPS        PCMProps;
-    /** The codec's bitrate. 0 if not used / cannot be specified. */
-    uint32_t                uBitrate;
-
-} AVRECCODECPARMS, *PAVRECCODECPARMS;
-
-/**
- * Structure for keeping codec-specific data.
- */
-typedef struct AVRECCODEC
-{
-    /** Generic codec parameters. */
-    AVRECCODECPARMS         Parms;
-    union
-    {
-#ifdef VBOX_WITH_LIBOPUS
-        struct
-        {
-            /** Encoder we're going to use. */
-            OpusEncoder    *pEnc;
-            /** Time (in ms) an (encoded) frame takes.
-             *
-             *  For Opus, valid frame sizes are:
-             *  ms           Frame size
-             *  2.5          120
-             *  5            240
-             *  10           480
-             *  20 (Default) 960
-             *  40           1920
-             *  60           2880
-             */
-            uint32_t        msFrame;
-            /** The frame size in bytes (based on msFrame). */
-            uint32_t        cbFrame;
-            /** The frame size in samples per frame (based on msFrame). */
-            uint32_t        csFrame;
-        } Opus;
-#endif /* VBOX_WITH_LIBOPUS */
-    };
-
-#ifdef VBOX_WITH_STATISTICS /** @todo Make these real STAM values. */
-    struct
-    {
-        /** Number of frames encoded. */
-        uint64_t        cEncFrames;
-        /** Total time (in ms) of already encoded audio data. */
-        uint64_t        msEncTotal;
-    } STAM;
-#endif /* VBOX_WITH_STATISTICS */
-
-} AVRECCODEC, *PAVRECCODEC;
-
-typedef struct AVRECSINK
-{
-    /** @todo Add types for container / codec as soon as we implement more stuff. */
-
-    /** Container data to use for data processing. */
-    AVRECCONTAINER       Con;
-    /** Codec data this sink uses for encoding. */
-    AVRECCODEC           Codec;
-    /** Timestamp (in ms) of when the sink was created. */
-    uint64_t             tsStartMs;
-} AVRECSINK, *PAVRECSINK;
-
-/**
- * Audio video recording (output) stream.
- */
-typedef struct AVRECSTREAM
-{
-    /** The stream's acquired configuration. */
-    PPDMAUDIOSTREAMCFG   pCfg;
-    /** (Audio) frame buffer. */
-    PRTCIRCBUF           pCircBuf;
-    /** Pointer to sink to use for writing. */
-    PAVRECSINK           pSink;
-    /** Last encoded PTS (in ms). */
-    uint64_t             uLastPTSMs;
-    /** Temporary buffer for the input (source) data to encode. */
-    void                *pvSrcBuf;
-    /** Size (in bytes) of the temporary buffer holding the input (source) data to encode. */
-    size_t               cbSrcBuf;
-    /** Temporary buffer for the encoded output (destination) data. */
-    void                *pvDstBuf;
-    /** Size (in bytes) of the temporary buffer holding the encoded output (destination) data. */
-    size_t               cbDstBuf;
-} AVRECSTREAM, *PAVRECSTREAM;
-
-/**
- * Video recording audio driver instance data.
- */
-typedef struct DRVAUDIOVIDEOREC
-{
-    /** Pointer to audio video recording object. */
-    AudioVideoRec       *pAudioVideoRec;
-    /** Pointer to the driver instance structure. */
-    PPDMDRVINS           pDrvIns;
-    /** Pointer to host audio interface. */
-    PDMIHOSTAUDIO        IHostAudio;
-    /** Pointer to the console object. */
-    ComPtr<Console>      pConsole;
-    /** Pointer to the DrvAudio port interface that is above us. */
-    PPDMIAUDIOCONNECTOR  pDrvAudio;
-    /** The driver's configured container parameters. */
-    AVRECCONTAINERPARMS  ContainerParms;
-    /** The driver's configured codec parameters. */
-    AVRECCODECPARMS      CodecParms;
-    /** The driver's sink for writing output to. */
-    AVRECSINK            Sink;
-} DRVAUDIOVIDEOREC, *PDRVAUDIOVIDEOREC;
-
-/** Makes DRVAUDIOVIDEOREC out of PDMIHOSTAUDIO. */
-#define PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface) /* (clang doesn't think it is a POD, thus _DYN.) */ \
-    ( (PDRVAUDIOVIDEOREC)((uintptr_t)pInterface - RT_UOFFSETOF_DYN(DRVAUDIOVIDEOREC, IHostAudio)) )
-
-/**
- * Initializes a recording sink.
- *
- * @returns IPRT status code.
- * @param   pThis               Driver instance.
- * @param   pSink               Sink to initialize.
- * @param   pConParms           Container parameters to set.
- * @param   pCodecParms         Codec parameters to set.
- */
-static int avRecSinkInit(PDRVAUDIOVIDEOREC pThis, PAVRECSINK pSink, PAVRECCONTAINERPARMS pConParms, PAVRECCODECPARMS pCodecParms)
-{
-    uint32_t uHz       = pCodecParms->PCMProps.uHz;
-    uint8_t  cBytes    = pCodecParms->PCMProps.cBytes;
-    uint8_t  cChannels = pCodecParms->PCMProps.cChannels;
-    uint32_t uBitrate  = pCodecParms->uBitrate;
-
-    /* Opus only supports certain input sample rates in an efficient manner.
-     * So make sure that we use those by resampling the data to the requested rate. */
-    if      (uHz > 24000) uHz = AVREC_OPUS_HZ_MAX;
-    else if (uHz > 16000) uHz = 24000;
-    else if (uHz > 12000) uHz = 16000;
-    else if (uHz > 8000 ) uHz = 12000;
-    else     uHz = 8000;
-
-    if (cChannels > 2)
-    {
-        LogRel(("VideoRec: Warning: More than 2 (stereo) channels are not supported at the moment\n"));
-        cChannels = 2;
-    }
-
-    int orc;
-    OpusEncoder *pEnc = opus_encoder_create(uHz, cChannels, OPUS_APPLICATION_AUDIO, &orc);
-    if (orc != OPUS_OK)
-    {
-        LogRel(("VideoRec: Audio codec failed to initialize: %s\n", opus_strerror(orc)));
-        return VERR_AUDIO_BACKEND_INIT_FAILED;
-    }
-
-    AssertPtr(pEnc);
-
-    if (uBitrate) /* Only explicitly set the bitrate if we specified one. Otherwise let Opus decide. */
-    {
-        opus_encoder_ctl(pEnc, OPUS_SET_BITRATE(uBitrate));
-        if (orc != OPUS_OK)
-        {
-            opus_encoder_destroy(pEnc);
-            pEnc = NULL;
-
-            LogRel(("VideoRec: Audio codec failed to set bitrate (%RU32): %s\n", uBitrate, opus_strerror(orc)));
-            return VERR_AUDIO_BACKEND_INIT_FAILED;
-        }
-    }
-
-    const bool fUseVBR = true; /** Use Variable Bit Rate (VBR) by default. @todo Make this configurable? */
-
-    orc = opus_encoder_ctl(pEnc, OPUS_SET_VBR(fUseVBR ? 1 : 0));
-    if (orc != OPUS_OK)
-    {
-        opus_encoder_destroy(pEnc);
-        pEnc = NULL;
-
-        LogRel(("VideoRec: Audio codec failed to %s VBR mode: %s\n", fUseVBR ? "enable" : "disable", opus_strerror(orc)));
-        return VERR_AUDIO_BACKEND_INIT_FAILED;
-    }
-
-    int rc = VINF_SUCCESS;
-
-    try
-    {
-        switch (pConParms->enmType)
-        {
-            case AVRECCONTAINERTYPE_MAIN_CONSOLE:
-            {
-                if (pThis->pConsole)
-                {
-                    pSink->Con.Main.pConsole = pThis->pConsole;
-                }
-                else
-                    rc = VERR_NOT_SUPPORTED;
-                break;
-            }
-
-            case AVRECCONTAINERTYPE_WEBM:
-            {
-                /* If we only record audio, create our own WebM writer instance here. */
-                if (!pSink->Con.WebM.pWebM) /* Do we already have our WebM writer instance? */
-                {
-                    /** @todo Add sink name / number to file name. */
-                    const char *pszFile = pSink->Con.Parms.WebM.pszFile;
-                    AssertPtr(pszFile);
-
-                    pSink->Con.WebM.pWebM = new WebMWriter();
-                    rc = pSink->Con.WebM.pWebM->Open(pszFile,
-                                                     /** @todo Add option to add some suffix if file exists instead of overwriting? */
-                                                     RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE,
-                                                     WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_None);
-                    if (RT_SUCCESS(rc))
-                    {
-                        rc = pSink->Con.WebM.pWebM->AddAudioTrack(uHz, cChannels, cBytes * 8 /* Bits */,
-                                                                  &pSink->Con.WebM.uTrack);
-                        if (RT_SUCCESS(rc))
-                        {
-                            LogRel(("VideoRec: Recording audio to audio file '%s'\n", pszFile));
-                        }
-                        else
-                            LogRel(("VideoRec: Error creating audio track for audio file '%s' (%Rrc)\n", pszFile, rc));
-                    }
-                    else
-                        LogRel(("VideoRec: Error creating audio file '%s' (%Rrc)\n", pszFile, rc));
-                }
-                break;
-            }
-
-            default:
-                rc = VERR_NOT_SUPPORTED;
-                break;
-        }
-    }
-    catch (std::bad_alloc &)
-    {
-        rc = VERR_NO_MEMORY;
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        pSink->Con.Parms.enmType     = pConParms->enmType;
-
-        PAVRECCODEC pCodec = &pSink->Codec;
-
-        pCodec->Parms.PCMProps.uHz       = uHz;
-        pCodec->Parms.PCMProps.cChannels = cChannels;
-        pCodec->Parms.PCMProps.cBytes    = cBytes;
-        pCodec->Parms.PCMProps.cShift    = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pSink->Codec.Parms.PCMProps.cBytes,
-                                                                             pSink->Codec.Parms.PCMProps.cChannels);
-        pCodec->Parms.uBitrate           = uBitrate;
-
-        pCodec->Opus.pEnc       = pEnc;
-        pCodec->Opus.msFrame    = AVREC_OPUS_FRAME_MS_DEFAULT;
-
-        if (!pCodec->Opus.msFrame)
-            pCodec->Opus.msFrame = AVREC_OPUS_FRAME_MS_DEFAULT; /* 20ms by default; to prevent division by zero. */
-        pCodec->Opus.csFrame = pSink->Codec.Parms.PCMProps.uHz / (1000 /* s in ms */ / pSink->Codec.Opus.msFrame);
-        pCodec->Opus.cbFrame = DrvAudioHlpFramesToBytes(pCodec->Opus.csFrame, &pSink->Codec.Parms.PCMProps);
-
-#ifdef VBOX_WITH_STATISTICS
-        pSink->Codec.STAM.cEncFrames = 0;
-        pSink->Codec.STAM.msEncTotal = 0;
-#endif
-        pSink->tsStartMs             = RTTimeMilliTS();
-    }
-    else
-    {
-        if (pEnc)
-        {
-            opus_encoder_destroy(pEnc);
-            pEnc = NULL;
-        }
-
-        LogRel(("VideoRec: Error creating sink (%Rrc)\n", rc));
-    }
-
-    return rc;
-}
-
-
-/**
- * Shuts down (closes) a recording sink,
- *
- * @returns IPRT status code.
- * @param   pSink               Recording sink to shut down.
- */
-static void avRecSinkShutdown(PAVRECSINK pSink)
-{
-    AssertPtrReturnVoid(pSink);
-
-#ifdef VBOX_WITH_LIBOPUS
-    if (pSink->Codec.Opus.pEnc)
-    {
-        opus_encoder_destroy(pSink->Codec.Opus.pEnc);
-        pSink->Codec.Opus.pEnc = NULL;
-    }
-#endif
-    switch (pSink->Con.Parms.enmType)
-    {
-        case AVRECCONTAINERTYPE_WEBM:
-        {
-            if (pSink->Con.WebM.pWebM)
-            {
-                LogRel2(("VideoRec: Finished recording audio to file '%s' (%zu bytes)\n",
-                         pSink->Con.WebM.pWebM->GetFileName().c_str(), pSink->Con.WebM.pWebM->GetFileSize()));
-
-                int rc2 = pSink->Con.WebM.pWebM->Close();
-                AssertRC(rc2);
-
-                delete pSink->Con.WebM.pWebM;
-                pSink->Con.WebM.pWebM = NULL;
-            }
-            break;
-        }
-
-        case AVRECCONTAINERTYPE_MAIN_CONSOLE:
-        default:
-            break;
-    }
-}
-
-
-/**
- * Creates an audio output stream and associates it with the specified recording sink.
- *
- * @returns IPRT status code.
- * @param   pThis               Driver instance.
- * @param   pStreamAV           Audio output stream to create.
- * @param   pSink               Recording sink to associate audio output stream to.
- * @param   pCfgReq             Requested configuration by the audio backend.
- * @param   pCfgAcq             Acquired configuration by the audio output stream.
- */
-static int avRecCreateStreamOut(PDRVAUDIOVIDEOREC pThis, PAVRECSTREAM pStreamAV,
-                                PAVRECSINK pSink, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
-    AssertPtrReturn(pThis,     VERR_INVALID_POINTER);
-    AssertPtrReturn(pStreamAV, VERR_INVALID_POINTER);
-    AssertPtrReturn(pSink,     VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfgReq,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfgAcq,   VERR_INVALID_POINTER);
-
-    if (pCfgReq->DestSource.Dest != PDMAUDIOPLAYBACKDEST_FRONT)
-    {
-        AssertFailed();
-
-        LogRel2(("VideoRec: Support for surround audio not implemented yet\n"));
-        return VERR_NOT_SUPPORTED;
-    }
-
-    int rc = VINF_SUCCESS;
-
-#ifdef VBOX_WITH_LIBOPUS
-    rc = RTCircBufCreate(&pStreamAV->pCircBuf, pSink->Codec.Opus.cbFrame * 2 /* Use "double buffering" */);
-    if (RT_SUCCESS(rc))
-    {
-        size_t cbScratchBuf = pSink->Codec.Opus.cbFrame;
-        pStreamAV->pvSrcBuf = RTMemAlloc(cbScratchBuf);
-        if (pStreamAV->pvSrcBuf)
-        {
-            pStreamAV->cbSrcBuf = cbScratchBuf;
-            pStreamAV->pvDstBuf = RTMemAlloc(cbScratchBuf);
-            if (pStreamAV->pvDstBuf)
-            {
-                pStreamAV->cbDstBuf = cbScratchBuf;
-
-                pStreamAV->pSink      = pSink; /* Assign sink to stream. */
-                pStreamAV->uLastPTSMs = 0;
-
-                if (pCfgAcq)
-                {
-                    /* Make sure to let the driver backend know that we need the audio data in
-                     * a specific sampling rate Opus is optimized for. */
-                    pCfgAcq->Props.uHz         = pSink->Codec.Parms.PCMProps.uHz;
-                    pCfgAcq->Props.cShift      = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfgAcq->Props.cBytes, pCfgAcq->Props.cChannels);
-
-                    /* Every Opus frame marks a period for now. Optimize this later. */
-                    pCfgAcq->Backend.cfPeriod     = DrvAudioHlpMilliToFrames(pSink->Codec.Opus.msFrame, &pCfgAcq->Props);
-                    pCfgAcq->Backend.cfBufferSize = DrvAudioHlpMilliToFrames(100 /* ms */, &pCfgAcq->Props); /** @todo Make this configurable. */
-                    pCfgAcq->Backend.cfPreBuf     = pCfgAcq->Backend.cfPeriod * 2;
-                }
-            }
-            else
-                rc = VERR_NO_MEMORY;
-        }
-        else
-            rc = VERR_NO_MEMORY;
-    }
-#else
-    RT_NOREF(pThis, pSink, pStreamAV, pCfgReq, pCfgAcq);
-    rc = VERR_NOT_SUPPORTED;
-#endif /* VBOX_WITH_LIBOPUS */
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-
-/**
- * Destroys (closes) an audio output stream.
- *
- * @returns IPRT status code.
- * @param   pThis               Driver instance.
- * @param   pStreamAV           Audio output stream to destroy.
- */
-static int avRecDestroyStreamOut(PDRVAUDIOVIDEOREC pThis, PAVRECSTREAM pStreamAV)
-{
-    RT_NOREF(pThis);
-
-    if (pStreamAV->pCircBuf)
-    {
-        RTCircBufDestroy(pStreamAV->pCircBuf);
-        pStreamAV->pCircBuf = NULL;
-    }
-
-    if (pStreamAV->pvSrcBuf)
-    {
-        Assert(pStreamAV->cbSrcBuf);
-        RTMemFree(pStreamAV->pvSrcBuf);
-        pStreamAV->cbSrcBuf = 0;
-    }
-
-    if (pStreamAV->pvDstBuf)
-    {
-        Assert(pStreamAV->cbDstBuf);
-        RTMemFree(pStreamAV->pvDstBuf);
-        pStreamAV->cbDstBuf = 0;
-    }
-
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Controls an audio output stream
- *
- * @returns IPRT status code.
- * @param   pThis               Driver instance.
- * @param   pStreamAV           Audio output stream to control.
- * @param   enmStreamCmd        Stream command to issue.
- */
-static int avRecControlStreamOut(PDRVAUDIOVIDEOREC pThis,
-                                 PAVRECSTREAM pStreamAV, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
-    RT_NOREF(pThis, pStreamAV);
-
-    int rc = VINF_SUCCESS;
-
-    switch (enmStreamCmd)
-    {
-        case PDMAUDIOSTREAMCMD_ENABLE:
-        case PDMAUDIOSTREAMCMD_DISABLE:
-        case PDMAUDIOSTREAMCMD_RESUME:
-        case PDMAUDIOSTREAMCMD_PAUSE:
-            break;
-
-        default:
-            rc = VERR_NOT_SUPPORTED;
-            break;
-    }
-
-    return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
- */
-static DECLCALLBACK(int) drvAudioVideoRecInit(PPDMIHOSTAUDIO pInterface)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-
-    LogFlowFuncEnter();
-
-    PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
-
-    LogRel(("VideoRec: Audio driver is using %RU32Hz, %RU16bit, %RU8 %s\n",
-            pThis->CodecParms.PCMProps.uHz, pThis->CodecParms.PCMProps.cBytes * 8,
-            pThis->CodecParms.PCMProps.cChannels, pThis->CodecParms.PCMProps.cChannels == 1 ? "channel" : "channels"));
-
-    int rc = avRecSinkInit(pThis, &pThis->Sink, &pThis->ContainerParms, &pThis->CodecParms);
-    if (RT_FAILURE(rc))
-    {
-        LogRel(("VideoRec: Audio recording driver failed to initialize, rc=%Rrc\n", rc));
-    }
-    else
-        LogRel2(("VideoRec: Audio recording driver initialized\n"));
-
-    return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
- */
-static DECLCALLBACK(int) drvAudioVideoRecStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
-                                                       void *pvBuf, uint32_t cxBuf, uint32_t *pcxRead)
-{
-    RT_NOREF(pInterface, pStream, pvBuf, cxBuf);
-
-    if (pcxRead)
-        *pcxRead = 0;
-
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
- */
-static DECLCALLBACK(int) drvAudioVideoRecStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
-                                                    const void *pvBuf, uint32_t cxBuf, uint32_t *pcxWritten)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
-    AssertPtrReturn(pvBuf,      VERR_INVALID_POINTER);
-    AssertReturn(cxBuf,         VERR_INVALID_PARAMETER);
-    /* pcxWritten is optional. */
-
-    PDRVAUDIOVIDEOREC pThis     = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
-    RT_NOREF(pThis);
-    PAVRECSTREAM      pStreamAV = (PAVRECSTREAM)pStream;
-
-    int rc = VINF_SUCCESS;
-
-    uint32_t cbWrittenTotal = 0;
-
-    /*
-     * Call the encoder with the data.
-     */
-#ifdef VBOX_WITH_LIBOPUS
-    PAVRECSINK pSink    = pStreamAV->pSink;
-    AssertPtr(pSink);
-    PAVRECCODEC pCodec  = &pSink->Codec;
-    AssertPtr(pCodec);
-    PRTCIRCBUF pCircBuf = pStreamAV->pCircBuf;
-    AssertPtr(pCircBuf);
-
-    void  *pvCircBuf;
-    size_t cbCircBuf;
-
-    uint32_t cbToWrite = cxBuf;
-
-    /*
-     * Fetch as much as we can into our internal ring buffer.
-     */
-    while (   cbToWrite
-           && RTCircBufFree(pCircBuf))
-    {
-        RTCircBufAcquireWriteBlock(pCircBuf, cbToWrite, &pvCircBuf, &cbCircBuf);
-
-        if (cbCircBuf)
-        {
-            memcpy(pvCircBuf, (uint8_t *)pvBuf + cbWrittenTotal, cbCircBuf),
-            cbWrittenTotal += (uint32_t)cbCircBuf;
-            Assert(cbToWrite >= cbCircBuf);
-            cbToWrite      -= (uint32_t)cbCircBuf;
-        }
-
-        RTCircBufReleaseWriteBlock(pCircBuf, cbCircBuf);
-
-        if (   RT_FAILURE(rc)
-            || !cbCircBuf)
-        {
-            break;
-        }
-    }
-
-    /*
-     * Process our internal ring buffer and encode the data.
-     */
-
-    uint32_t cbSrc;
-
-    /* Only encode data if we have data for the given time period (or more). */
-    while (RTCircBufUsed(pCircBuf) >= pCodec->Opus.cbFrame)
-    {
-        LogFunc(("cbAvail=%zu, csFrame=%RU32, cbFrame=%RU32\n",
-                 RTCircBufUsed(pCircBuf), pCodec->Opus.csFrame, pCodec->Opus.cbFrame));
-
-        cbSrc = 0;
-
-        while (cbSrc < pCodec->Opus.cbFrame)
-        {
-            RTCircBufAcquireReadBlock(pCircBuf, pCodec->Opus.cbFrame - cbSrc, &pvCircBuf, &cbCircBuf);
-
-            if (cbCircBuf)
-            {
-                memcpy((uint8_t *)pStreamAV->pvSrcBuf + cbSrc, pvCircBuf, cbCircBuf);
-
-                cbSrc += (uint32_t)cbCircBuf;
-                Assert(cbSrc <= pStreamAV->cbSrcBuf);
-            }
-
-            RTCircBufReleaseReadBlock(pCircBuf, cbCircBuf);
-
-            if (!cbCircBuf)
-                break;
-        }
-
-# ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
-        RTFILE fh;
-        RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "DrvAudioVideoRec.pcm",
-                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
-        RTFileWrite(fh, pStreamAV->pvSrcBuf, cbSrc, NULL);
-        RTFileClose(fh);
-# endif
-
-        Assert(cbSrc == pCodec->Opus.cbFrame);
-
-        /*
-         * Opus always encodes PER "OPUS FRAME", that is, exactly 2.5, 5, 10, 20, 40 or 60 ms of audio data.
-         *
-         * A packet can have up to 120ms worth of audio data.
-         * Anything > 120ms of data will result in a "corrupted package" error message by
-         * by decoding application.
-         */
-
-        /* Call the encoder to encode one "Opus frame" per iteration. */
-        opus_int32 cbWritten = opus_encode(pSink->Codec.Opus.pEnc,
-                                           (opus_int16 *)pStreamAV->pvSrcBuf, pCodec->Opus.csFrame,
-                                           (uint8_t *)pStreamAV->pvDstBuf, (opus_int32)pStreamAV->cbDstBuf);
-        if (cbWritten > 0)
-        {
-            /* Get overall frames encoded. */
-            const uint32_t cEncFrames     = opus_packet_get_nb_frames((uint8_t *)pStreamAV->pvDstBuf, cbWritten);
-
-# ifdef VBOX_WITH_STATISTICS
-            pSink->Codec.STAM.cEncFrames += cEncFrames;
-            pSink->Codec.STAM.msEncTotal += pSink->Codec.Opus.msFrame * cEncFrames;
-# endif
-            Assert((uint32_t)cbWritten <= (uint32_t)pStreamAV->cbDstBuf);
-            const uint32_t cbDst = RT_MIN((uint32_t)cbWritten, (uint32_t)pStreamAV->cbDstBuf);
-
-            Assert(cEncFrames == 1);
-
-            if (pStreamAV->uLastPTSMs == 0)
-                pStreamAV->uLastPTSMs = RTTimeProgramMilliTS(); /* We want the absolute time (in ms) since program start. */
-
-            const uint64_t uDurationMs = pSink->Codec.Opus.msFrame * cEncFrames;
-            const uint64_t uPTSMs      = pStreamAV->uLastPTSMs;
-
-            pStreamAV->uLastPTSMs += uDurationMs;
-
-            switch (pSink->Con.Parms.enmType)
-            {
-                case AVRECCONTAINERTYPE_MAIN_CONSOLE:
-                {
-                    HRESULT hr = pSink->Con.Main.pConsole->i_videoRecSendAudio(pStreamAV->pvDstBuf, cbDst, uPTSMs);
-                    Assert(hr == S_OK);
-                    RT_NOREF(hr);
-
-                    break;
-                }
-
-                case AVRECCONTAINERTYPE_WEBM:
-                {
-                    WebMWriter::BlockData_Opus blockData = { pStreamAV->pvDstBuf, cbDst, uPTSMs };
-                    rc = pSink->Con.WebM.pWebM->WriteBlock(pSink->Con.WebM.uTrack, &blockData, sizeof(blockData));
-                    AssertRC(rc);
-
-                    break;
-                }
-
-                default:
-                    AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
-                    break;
-            }
-        }
-        else if (cbWritten < 0)
-        {
-            AssertMsgFailed(("Encoding failed: %s\n", opus_strerror(cbWritten)));
-            rc = VERR_INVALID_PARAMETER;
-        }
-
-        if (RT_FAILURE(rc))
-            break;
-    }
-
-    if (pcxWritten)
-        *pcxWritten = cbWrittenTotal;
-#else
-    /* Report back all data as being processed. */
-    if (pcxWritten)
-        *pcxWritten = cxBuf;
-
-    rc = VERR_NOT_SUPPORTED;
-#endif /* VBOX_WITH_LIBOPUS */
-
-    LogFlowFunc(("csReadTotal=%RU32, rc=%Rrc\n", cbWrittenTotal, rc));
-    return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
- */
-static DECLCALLBACK(int) drvAudioVideoRecGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
-{
-    RT_NOREF(pInterface);
-    AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
-
-    RTStrPrintf2(pBackendCfg->szName, sizeof(pBackendCfg->szName), "Video recording audio driver");
-
-    pBackendCfg->cbStreamOut    = sizeof(AVRECSTREAM);
-    pBackendCfg->cbStreamIn     = 0;
-    pBackendCfg->cMaxStreamsIn  = 0;
-    pBackendCfg->cMaxStreamsOut = UINT32_MAX;
-
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
- */
-static DECLCALLBACK(void) drvAudioVideoRecShutdown(PPDMIHOSTAUDIO pInterface)
-{
-    LogFlowFuncEnter();
-
-    PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
-
-    avRecSinkShutdown(&pThis->Sink);
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioVideoRecGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
-    RT_NOREF(enmDir);
-    AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
-
-    return PDMAUDIOBACKENDSTS_RUNNING;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
- */
-static DECLCALLBACK(int) drvAudioVideoRecStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
-                                                      PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfgAcq,    VERR_INVALID_POINTER);
-
-    if (pCfgReq->enmDir == PDMAUDIODIR_IN)
-        return VERR_NOT_SUPPORTED;
-
-    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
-
-    PDRVAUDIOVIDEOREC pThis     = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
-    PAVRECSTREAM      pStreamAV = (PAVRECSTREAM)pStream;
-
-    /* For now we only have one sink, namely the driver's one.
-     * Later each stream could have its own one, to e.g. router different stream to different sinks .*/
-    PAVRECSINK pSink = &pThis->Sink;
-
-    int rc = avRecCreateStreamOut(pThis, pStreamAV, pSink, pCfgReq, pCfgAcq);
-    if (RT_SUCCESS(rc))
-    {
-        pStreamAV->pCfg = DrvAudioHlpStreamCfgDup(pCfgAcq);
-        if (!pStreamAV->pCfg)
-            rc = VERR_NO_MEMORY;
-    }
-
-    return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
- */
-static DECLCALLBACK(int) drvAudioVideoRecStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
-
-    PDRVAUDIOVIDEOREC pThis     = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
-    PAVRECSTREAM      pStreamAV = (PAVRECSTREAM)pStream;
-
-    if (!pStreamAV->pCfg) /* Not (yet) configured? Skip. */
-        return VINF_SUCCESS;
-
-    int rc = VINF_SUCCESS;
-
-    if (pStreamAV->pCfg->enmDir == PDMAUDIODIR_OUT)
-        rc = avRecDestroyStreamOut(pThis, pStreamAV);
-
-    if (RT_SUCCESS(rc))
-    {
-        DrvAudioHlpStreamCfgFree(pStreamAV->pCfg);
-        pStreamAV->pCfg = NULL;
-    }
-
-    return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
- */
-static DECLCALLBACK(int) drvAudioVideoRecStreamControl(PPDMIHOSTAUDIO pInterface,
-                                                       PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
-
-    PDRVAUDIOVIDEOREC pThis     = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
-    PAVRECSTREAM      pStreamAV = (PAVRECSTREAM)pStream;
-
-    if (!pStreamAV->pCfg) /* Not (yet) configured? Skip. */
-        return VINF_SUCCESS;
-
-    if (pStreamAV->pCfg->enmDir == PDMAUDIODIR_OUT)
-        return avRecControlStreamOut(pThis, pStreamAV, enmStreamCmd);
-
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
- */
-static DECLCALLBACK(uint32_t) drvAudioVideoRecStreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
-{
-    RT_NOREF(pInterface, pStream);
-
-    return 0; /* Video capturing does not provide any input. */
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
- */
-static DECLCALLBACK(uint32_t) drvAudioVideoRecStreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
-{
-    RT_NOREF(pInterface, pStream);
-
-    return UINT32_MAX;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvAudioVideoRecStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
-{
-    RT_NOREF(pInterface, pStream);
-
-    return (PDMAUDIOSTREAMSTS_FLAG_INITIALIZED | PDMAUDIOSTREAMSTS_FLAG_ENABLED);
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
- */
-static DECLCALLBACK(int) drvAudioVideoRecStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
-
-    LogFlowFuncEnter();
-
-    /* Nothing to do here for video recording. */
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvAudioVideoRecQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
-    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
-    PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
-
-    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
-    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
-    return NULL;
-}
-
-
-AudioVideoRec::AudioVideoRec(Console *pConsole)
-    : AudioDriver(pConsole)
-    , mpDrv(NULL)
-{
-}
-
-
-AudioVideoRec::~AudioVideoRec(void)
-{
-    if (mpDrv)
-    {
-        mpDrv->pAudioVideoRec = NULL;
-        mpDrv = NULL;
-    }
-}
-
-
-/**
- * Applies a video recording configuration to this driver instance.
- *
- * @returns IPRT status code.
- * @param   Settings        Capturing configuration to apply.
- */
-int AudioVideoRec::applyConfiguration(const settings::RecordSettings &Settings)
-{
-    /** @todo Do some validation here. */
-    mVideoRecCfg = Settings; /* Note: Does have an own copy operator. */
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @copydoc AudioDriver::configureDriver
- */
-int AudioVideoRec::configureDriver(PCFGMNODE pLunCfg)
-{
-    int rc = CFGMR3InsertInteger(pLunCfg, "Object",    (uintptr_t)mpConsole->i_videoRecGetAudioDrv());
-    AssertRCReturn(rc, rc);
-    rc = CFGMR3InsertInteger(pLunCfg, "ObjectConsole", (uintptr_t)mpConsole);
-    AssertRCReturn(rc, rc);
-
-    /** @todo For now we're using the configuration of the first screen here audio-wise. */
-    Assert(mVideoRecCfg.mapScreens.size() >= 1);
-    const settings::RecordScreenSettings &Screen0Settings = mVideoRecCfg.mapScreens[0];
-
-    rc = CFGMR3InsertInteger(pLunCfg, "ContainerType", (uint64_t)Screen0Settings.enmDest);
-    AssertRCReturn(rc, rc);
-    if (Screen0Settings.enmDest == RecordDestination_File)
-    {
-        rc = CFGMR3InsertString(pLunCfg, "ContainerFileName", Utf8Str(Screen0Settings.File.strName).c_str());
-        AssertRCReturn(rc, rc);
-    }
-    rc = CFGMR3InsertInteger(pLunCfg, "CodecHz", Screen0Settings.Audio.uHz);
-    AssertRCReturn(rc, rc);
-    rc = CFGMR3InsertInteger(pLunCfg, "CodecBits", Screen0Settings.Audio.cBits);
-    AssertRCReturn(rc, rc);
-    rc = CFGMR3InsertInteger(pLunCfg, "CodecChannels", Screen0Settings.Audio.cChannels);
-    AssertRCReturn(rc, rc);
-    rc = CFGMR3InsertInteger(pLunCfg, "CodecBitrate", 0); /* Let Opus decide for now. */
-    AssertRCReturn(rc, rc);
-
-    return AudioDriver::configureDriver(pLunCfg);
-}
-
-
-/**
- * Construct a audio video recording driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-/* static */
-DECLCALLBACK(int) AudioVideoRec::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
-{
-    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
-    PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
-    RT_NOREF(fFlags);
-
-    LogRel(("Audio: Initializing video recording audio driver\n"));
-    LogFlowFunc(("fFlags=0x%x\n", fFlags));
-
-    AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
-                    ("Configuration error: Not possible to attach anything to this driver!\n"),
-                    VERR_PDM_DRVINS_NO_ATTACH);
-
-    /*
-     * Init the static parts.
-     */
-    pThis->pDrvIns                   = pDrvIns;
-    /* IBase */
-    pDrvIns->IBase.pfnQueryInterface = drvAudioVideoRecQueryInterface;
-    /* IHostAudio */
-    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVideoRec);
-
-    /*
-     * Get the Console object pointer.
-     */
-    void *pvUser;
-    int rc = CFGMR3QueryPtr(pCfg, "ObjectConsole", &pvUser); /** @todo r=andy Get rid of this hack and use IHostAudio::SetCallback. */
-    AssertRCReturn(rc, rc);
-
-    /* CFGM tree saves the pointer to Console in the Object node of AudioVideoRec. */
-    pThis->pConsole = (Console *)pvUser;
-    AssertReturn(!pThis->pConsole.isNull(), VERR_INVALID_POINTER);
-
-    /*
-     * Get the pointer to the audio driver instance.
-     */
-    rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser); /** @todo r=andy Get rid of this hack and use IHostAudio::SetCallback. */
-    AssertRCReturn(rc, rc);
-
-    pThis->pAudioVideoRec = (AudioVideoRec *)pvUser;
-    AssertPtrReturn(pThis->pAudioVideoRec, VERR_INVALID_POINTER);
-
-    /*
-     * Get the recording container and codec parameters from the audio driver instance.
-     */
-    PAVRECCONTAINERPARMS pConParams  = &pThis->ContainerParms;
-    PAVRECCODECPARMS     pCodecParms = &pThis->CodecParms;
-    PPDMAUDIOPCMPROPS    pPCMProps   = &pCodecParms->PCMProps;
-
-    RT_ZERO(pThis->ContainerParms);
-    RT_ZERO(pThis->CodecParms);
-
-    rc = CFGMR3QueryU32(pCfg, "ContainerType", (uint32_t *)&pConParams->enmType);
-    AssertRCReturn(rc, rc);
-
-    switch (pConParams->enmType)
-    {
-        case AVRECCONTAINERTYPE_WEBM:
-            rc = CFGMR3QueryStringAlloc(pCfg, "ContainerFileName", &pConParams->WebM.pszFile);
-            AssertRCReturn(rc, rc);
-            break;
-
-        default:
-            break;
-    }
-
-    rc = CFGMR3QueryU32(pCfg, "CodecHz", &pPCMProps->uHz);
-    AssertRCReturn(rc, rc);
-    rc = CFGMR3QueryU8(pCfg,  "CodecBits", &pPCMProps->cBytes);
-    AssertRCReturn(rc, rc);
-    rc = CFGMR3QueryU8(pCfg,  "CodecChannels", &pPCMProps->cChannels);
-    AssertRCReturn(rc, rc);
-    rc = CFGMR3QueryU32(pCfg, "CodecBitrate", &pCodecParms->uBitrate);
-    AssertRCReturn(rc, rc);
-
-    pPCMProps->cBytes      = pPCMProps->cBytes / 8; /* Bits to bytes. */
-    pPCMProps->cShift      = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pPCMProps->cBytes, pPCMProps->cChannels);
-    pPCMProps->fSigned     = true;
-    pPCMProps->fSwapEndian = false;
-
-    AssertMsgReturn(DrvAudioHlpPCMPropsAreValid(pPCMProps),
-                    ("Configuration error: Audio configuration is invalid!\n"), VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES);
-
-    pThis->pAudioVideoRec = (AudioVideoRec *)pvUser;
-    AssertPtrReturn(pThis->pAudioVideoRec, VERR_INVALID_POINTER);
-
-    pThis->pAudioVideoRec->mpDrv = pThis;
-
-    /*
-     * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
-     * Described in CFGM tree.
-     */
-    pThis->pDrvAudio = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
-    AssertMsgReturn(pThis->pDrvAudio, ("Configuration error: No upper interface specified!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
-
-#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
-    RTFileDelete(VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "DrvAudioVideoRec.webm");
-    RTFileDelete(VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "DrvAudioVideoRec.pcm");
-#endif
-
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMDRVREG,pfnDestruct}
- */
-/* static */
-DECLCALLBACK(void) AudioVideoRec::drvDestruct(PPDMDRVINS pDrvIns)
-{
-    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
-    PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
-
-    LogFlowFuncEnter();
-
-    switch (pThis->ContainerParms.enmType)
-    {
-        case AVRECCONTAINERTYPE_WEBM:
-        {
-            avRecSinkShutdown(&pThis->Sink);
-            RTStrFree(pThis->ContainerParms.WebM.pszFile);
-            break;
-        }
-
-        default:
-            break;
-    }
-
-    /*
-     * If the AudioVideoRec object is still alive, we must clear it's reference to
-     * us since we'll be invalid when we return from this method.
-     */
-    if (pThis->pAudioVideoRec)
-    {
-        pThis->pAudioVideoRec->mpDrv = NULL;
-        pThis->pAudioVideoRec = NULL;
-    }
-
-    LogFlowFuncLeave();
-}
-
-
-/**
- * @interface_method_impl{PDMDRVREG,pfnAttach}
- */
-/* static */
-DECLCALLBACK(int) AudioVideoRec::drvAttach(PPDMDRVINS pDrvIns, uint32_t fFlags)
-{
-    RT_NOREF(pDrvIns, fFlags);
-
-    LogFlowFuncEnter();
-
-    return VINF_SUCCESS;
-}
-
-/**
- * @interface_method_impl{PDMDRVREG,pfnDetach}
- */
-/* static */
-DECLCALLBACK(void) AudioVideoRec::drvDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
-{
-    RT_NOREF(pDrvIns, fFlags);
-
-    LogFlowFuncEnter();
-}
-
-/**
- * Video recording audio driver registration record.
- */
-const PDMDRVREG AudioVideoRec::DrvReg =
-{
-    PDM_DRVREG_VERSION,
-    /* szName */
-    "AudioVideoRec",
-    /* szRCMod */
-    "",
-    /* szR0Mod */
-    "",
-    /* pszDescription */
-    "Audio driver for video recording",
-    /* fFlags */
-    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
-    /* fClass. */
-    PDM_DRVREG_CLASS_AUDIO,
-    /* cMaxInstances */
-    ~0U,
-    /* cbInstance */
-    sizeof(DRVAUDIOVIDEOREC),
-    /* pfnConstruct */
-    AudioVideoRec::drvConstruct,
-    /* pfnDestruct */
-    AudioVideoRec::drvDestruct,
-    /* pfnRelocate */
-    NULL,
-    /* pfnIOCtl */
-    NULL,
-    /* pfnPowerOn */
-    NULL,
-    /* pfnReset */
-    NULL,
-    /* pfnSuspend */
-    NULL,
-    /* pfnResume */
-    NULL,
-    /* pfnAttach */
-    AudioVideoRec::drvAttach,
-    /* pfnDetach */
-    AudioVideoRec::drvDetach,
-    /* pfnPowerOff */
-    NULL,
-    /* pfnSoftReset */
-    NULL,
-    /* u32EndVersion */
-    PDM_DRVREG_VERSION
-};
-
Index: /trunk/src/VBox/Main/src-client/Recording.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/Recording.cpp	(revision 75344)
+++ /trunk/src/VBox/Main/src-client/Recording.cpp	(revision 75344)
@@ -0,0 +1,583 @@
+/* $Id$ */
+/** @file
+ * Recording (with optional audio recording) code.
+ *
+ * This code employs a separate encoding thread per recording context
+ * to keep time spent in EMT as short as possible. Each configured VM display
+ * is represented by an own recording stream, which in turn has its own rendering
+ * queue. Common recording data across all recording streams is kept in a
+ * separate queue in the recording context to minimize data duplication and
+ * multiplexing overhead in EMT.
+ */
+
+/*
+ * Copyright (C) 2012-2018 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.
+ */
+
+#ifdef LOG_GROUP
+# undef LOG_GROUP
+#endif
+#define LOG_GROUP LOG_GROUP_MAIN_DISPLAY
+#include "LoggingNew.h"
+
+#include <stdexcept>
+#include <vector>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <iprt/path.h>
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+
+#include <VBox/err.h>
+#include <VBox/com/VirtualBox.h>
+
+#include "ConsoleImpl.h"
+#include "Recording.h"
+#include "RecordingInternals.h"
+#include "RecordingStream.h"
+#include "RecordingUtils.h"
+#include "WebMWriter.h"
+
+using namespace com;
+
+#ifdef DEBUG_andy
+/** Enables dumping audio / video data for debugging reasons. */
+//# define VBOX_VIDEOREC_DUMP
+#endif
+
+#ifdef VBOX_VIDEOREC_DUMP
+#pragma pack(push)
+#pragma pack(1)
+typedef struct
+{
+    uint16_t u16Magic;
+    uint32_t u32Size;
+    uint16_t u16Reserved1;
+    uint16_t u16Reserved2;
+    uint32_t u32OffBits;
+} VIDEORECBMPHDR, *PVIDEORECBMPHDR;
+AssertCompileSize(VIDEORECBMPHDR, 14);
+
+typedef struct
+{
+    uint32_t u32Size;
+    uint32_t u32Width;
+    uint32_t u32Height;
+    uint16_t u16Planes;
+    uint16_t u16BitCount;
+    uint32_t u32Compression;
+    uint32_t u32SizeImage;
+    uint32_t u32XPelsPerMeter;
+    uint32_t u32YPelsPerMeter;
+    uint32_t u32ClrUsed;
+    uint32_t u32ClrImportant;
+} VIDEORECBMPDIBHDR, *PVIDEORECBMPDIBHDR;
+AssertCompileSize(VIDEORECBMPDIBHDR, 40);
+
+#pragma pack(pop)
+#endif /* VBOX_VIDEOREC_DUMP */
+
+
+CaptureContext::CaptureContext(Console *a_pConsole)
+    : pConsole(a_pConsole)
+    , enmState(VIDEORECSTS_UNINITIALIZED) { }
+
+CaptureContext::CaptureContext(Console *a_pConsole, const settings::RecordSettings &a_Settings)
+    : pConsole(a_pConsole)
+    , enmState(VIDEORECSTS_UNINITIALIZED)
+{
+    int rc = CaptureContext::createInternal(a_Settings);
+    if (RT_FAILURE(rc))
+        throw rc;
+}
+
+CaptureContext::~CaptureContext(void)
+{
+    destroyInternal();
+}
+
+/**
+ * Worker thread for all streams of a video recording context.
+ *
+ * For video frames, this also does the RGB/YUV conversion and encoding.
+ */
+DECLCALLBACK(int) CaptureContext::threadMain(RTTHREAD hThreadSelf, void *pvUser)
+{
+    CaptureContext *pThis = (CaptureContext *)pvUser;
+
+    /* Signal that we're up and rockin'. */
+    RTThreadUserSignal(hThreadSelf);
+
+    LogFunc(("Thread started\n"));
+
+    for (;;)
+    {
+        int rc = RTSemEventWait(pThis->WaitEvent, RT_INDEFINITE_WAIT);
+        AssertRCBreak(rc);
+
+        Log2Func(("Processing %zu streams\n", pThis->vecStreams.size()));
+
+        /** @todo r=andy This is inefficient -- as we already wake up this thread
+         *               for every screen from Main, we here go again (on every wake up) through
+         *               all screens.  */
+        VideoRecStreams::iterator itStream = pThis->vecStreams.begin();
+        while (itStream != pThis->vecStreams.end())
+        {
+            CaptureStream *pStream = (*itStream);
+
+            rc = pStream->Process(pThis->mapBlocksCommon);
+            if (RT_FAILURE(rc))
+                break;
+
+            ++itStream;
+        }
+
+        if (RT_FAILURE(rc))
+            LogRel(("Recording: Encoding thread failed with rc=%Rrc\n", rc));
+
+        /* Keep going in case of errors. */
+
+        if (ASMAtomicReadBool(&pThis->fShutdown))
+        {
+            LogFunc(("Thread is shutting down ...\n"));
+            break;
+        }
+
+    } /* for */
+
+    LogFunc(("Thread ended\n"));
+    return VINF_SUCCESS;
+}
+
+/**
+ * Notifies a recording context's encoding thread.
+ *
+ * @returns IPRT status code.
+ */
+int CaptureContext::threadNotify(void)
+{
+    return RTSemEventSignal(this->WaitEvent);
+}
+
+/**
+ * Creates a video recording context.
+ *
+ * @returns IPRT status code.
+ * @param   a_Settings          Capture settings to use for context creation.
+ */
+int CaptureContext::createInternal(const settings::RecordSettings &a_Settings)
+{
+    int rc = RTCritSectInit(&this->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    settings::RecordScreenMap::const_iterator itScreen = a_Settings.mapScreens.begin();
+    while (itScreen != a_Settings.mapScreens.end())
+    {
+        CaptureStream *pStream = NULL;
+        try
+        {
+            pStream = new CaptureStream(this, itScreen->first /* Screen ID */, itScreen->second);
+            this->vecStreams.push_back(pStream);
+        }
+        catch (std::bad_alloc &)
+        {
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+
+        ++itScreen;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        this->tsStartMs = RTTimeMilliTS();
+        this->enmState  = VIDEORECSTS_CREATED;
+        this->fShutdown = false;
+
+        /* Copy the settings to our context. */
+        this->Settings  = a_Settings;
+
+        rc = RTSemEventCreate(&this->WaitEvent);
+        AssertRCReturn(rc, rc);
+    }
+
+    if (RT_FAILURE(rc))
+    {
+        int rc2 = destroyInternal();
+        AssertRC(rc2);
+    }
+
+    return rc;
+}
+
+int CaptureContext::startInternal(void)
+{
+    if (this->enmState == VIDEORECSTS_STARTED)
+        return VINF_SUCCESS;
+
+    Assert(this->enmState == VIDEORECSTS_CREATED);
+
+    int rc = RTThreadCreate(&this->Thread, CaptureContext::threadMain, (void *)this, 0,
+                            RTTHREADTYPE_MAIN_WORKER, RTTHREADFLAGS_WAITABLE, "Record");
+
+    if (RT_SUCCESS(rc)) /* Wait for the thread to start. */
+        rc = RTThreadUserWait(this->Thread, 30 * RT_MS_1SEC /* 30s timeout */);
+
+    if (RT_SUCCESS(rc))
+    {
+        this->enmState = VIDEORECSTS_STARTED;
+    }
+
+    return rc;
+}
+
+int CaptureContext::stopInternal(void)
+{
+    if (this->enmState != VIDEORECSTS_STARTED)
+        return VINF_SUCCESS;
+
+    LogThisFunc(("Shutting down thread ...\n"));
+
+    /* Set shutdown indicator. */
+    ASMAtomicWriteBool(&this->fShutdown, true);
+
+    /* Signal the thread and wait for it to shut down. */
+    int rc = threadNotify();
+    if (RT_SUCCESS(rc))
+        rc = RTThreadWait(this->Thread, 30 * 1000 /* 10s timeout */, NULL);
+
+    if (RT_SUCCESS(rc))
+    {
+        this->enmState = VIDEORECSTS_CREATED;
+    }
+
+    LogFlowThisFunc(("%Rrc\n", rc));
+    return rc;
+}
+
+/**
+ * Destroys a video recording context.
+ */
+int CaptureContext::destroyInternal(void)
+{
+    int rc = stopInternal();
+    if (RT_FAILURE(rc))
+        return rc;
+
+    rc = RTSemEventDestroy(this->WaitEvent);
+    AssertRC(rc);
+
+    this->WaitEvent = NIL_RTSEMEVENT;
+
+    rc = RTCritSectEnter(&this->CritSect);
+    if (RT_SUCCESS(rc))
+    {
+        VideoRecStreams::iterator it = this->vecStreams.begin();
+        while (it != this->vecStreams.end())
+        {
+            CaptureStream *pStream = (*it);
+
+            int rc2 = pStream->Uninit();
+            if (RT_SUCCESS(rc))
+                rc = rc2;
+
+            delete pStream;
+            pStream = NULL;
+
+            this->vecStreams.erase(it);
+            it = this->vecStreams.begin();
+
+            delete pStream;
+            pStream = NULL;
+        }
+
+        /* Sanity. */
+        Assert(this->vecStreams.empty());
+        Assert(this->mapBlocksCommon.size() == 0);
+
+        int rc2 = RTCritSectLeave(&this->CritSect);
+        AssertRC(rc2);
+
+        RTCritSectDelete(&this->CritSect);
+    }
+
+    LogFlowThisFunc(("%Rrc\n", rc));
+    return rc;
+}
+
+const settings::RecordSettings &CaptureContext::GetConfig(void) const
+{
+    return this->Settings;
+}
+
+CaptureStream *CaptureContext::getStreamInternal(unsigned uScreen) const
+{
+    CaptureStream *pStream;
+
+    try
+    {
+        pStream = this->vecStreams.at(uScreen);
+    }
+    catch (std::out_of_range &)
+    {
+        pStream = NULL;
+    }
+
+    return pStream;
+}
+
+/**
+ * Retrieves a specific recording stream of a recording context.
+ *
+ * @returns Pointer to recording stream if found, or NULL if not found.
+ * @param   uScreen             Screen number of recording stream to look up.
+ */
+CaptureStream *CaptureContext::GetStream(unsigned uScreen) const
+{
+    return getStreamInternal(uScreen);
+}
+
+size_t CaptureContext::GetStreamCount(void) const
+{
+    return this->vecStreams.size();
+}
+
+int CaptureContext::Create(const settings::RecordSettings &a_Settings)
+{
+    return createInternal(a_Settings);
+}
+
+int CaptureContext::Destroy(void)
+{
+    return destroyInternal();
+}
+
+int CaptureContext::Start(void)
+{
+    return startInternal();
+}
+
+int CaptureContext::Stop(void)
+{
+    return stopInternal();
+}
+
+bool CaptureContext::IsFeatureEnabled(RecordFeature_T enmFeature) const
+{
+    VideoRecStreams::const_iterator itStream = this->vecStreams.begin();
+    while (itStream != this->vecStreams.end())
+    {
+        if ((*itStream)->GetConfig().isFeatureEnabled(enmFeature))
+            return true;
+        ++itStream;
+    }
+
+    return false;
+}
+
+/**
+ * Returns if this recording context is ready to start recording.
+ *
+ * @returns @c true if recording context is ready, @c false if not.
+ */
+bool CaptureContext::IsReady(void) const
+{
+    return (this->enmState >= VIDEORECSTS_CREATED);
+}
+
+/**
+ * Returns if this recording context is ready to accept new recording data for a given screen.
+ *
+ * @returns @c true if the specified screen is ready, @c false if not.
+ * @param   uScreen             Screen ID.
+ * @param   uTimeStampMs        Current time stamp (in ms). Currently not being used.
+ */
+bool CaptureContext::IsReady(uint32_t uScreen, uint64_t uTimeStampMs) const
+{
+    RT_NOREF(uTimeStampMs);
+
+    if (this->enmState != VIDEORECSTS_STARTED)
+        return false;
+
+    bool fIsReady = false;
+
+    const CaptureStream *pStream = GetStream(uScreen);
+    if (pStream)
+        fIsReady = pStream->IsReady();
+
+    /* Note: Do not check for other constraints like the video FPS rate here,
+     *       as this check then also would affect other (non-FPS related) stuff
+     *       like audio data. */
+
+    return fIsReady;
+}
+
+/**
+ * Returns whether a given recording context has been started or not.
+ *
+ * @returns true if active, false if not.
+ */
+bool CaptureContext::IsStarted(void) const
+{
+    return (this->enmState == VIDEORECSTS_STARTED);
+}
+
+/**
+ * Checks if a specified limit for recording has been reached.
+ *
+ * @returns true if any limit has been reached.
+ * @param   uScreen             Screen ID.
+ * @param   tsNowMs             Current time stamp (in ms).
+ */
+bool CaptureContext::IsLimitReached(uint32_t uScreen, uint64_t tsNowMs) const
+{
+    const CaptureStream *pStream = GetStream(uScreen);
+    if (   !pStream
+        || pStream->IsLimitReached(tsNowMs))
+    {
+        return true;
+    }
+
+    return false;
+}
+
+/**
+ * Sends an audio frame to the video encoding thread.
+ *
+ * @thread  EMT
+ *
+ * @returns IPRT status code.
+ * @param   pvData              Audio frame data to send.
+ * @param   cbData              Size (in bytes) of (encoded) audio frame data.
+ * @param   uTimeStampMs        Time stamp (in ms) of audio playback.
+ */
+int CaptureContext::SendAudioFrame(const void *pvData, size_t cbData, uint64_t uTimeStampMs)
+{
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
+    AssertReturn(cbData, VERR_INVALID_PARAMETER);
+
+    /* To save time spent in EMT, do the required audio multiplexing in the encoding thread.
+     *
+     * The multiplexing is needed to supply all recorded (enabled) screens with the same
+     * audio data at the same given point in time.
+     */
+    PVIDEORECBLOCK pBlock = (PVIDEORECBLOCK)RTMemAlloc(sizeof(VIDEORECBLOCK));
+    AssertPtrReturn(pBlock, VERR_NO_MEMORY);
+    pBlock->enmType = VIDEORECBLOCKTYPE_AUDIO;
+
+    PVIDEORECAUDIOFRAME pFrame = (PVIDEORECAUDIOFRAME)RTMemAlloc(sizeof(VIDEORECAUDIOFRAME));
+    AssertPtrReturn(pFrame, VERR_NO_MEMORY);
+
+    pFrame->pvBuf = (uint8_t *)RTMemAlloc(cbData);
+    AssertPtrReturn(pFrame->pvBuf, VERR_NO_MEMORY);
+    pFrame->cbBuf = cbData;
+
+    memcpy(pFrame->pvBuf, pvData, cbData);
+
+    pBlock->pvData       = pFrame;
+    pBlock->cbData       = sizeof(VIDEORECAUDIOFRAME) + cbData;
+    pBlock->cRefs        = (uint16_t)this->vecStreams.size(); /* All streams need the same audio data. */
+    pBlock->uTimeStampMs = uTimeStampMs;
+
+    int rc = RTCritSectEnter(&this->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    try
+    {
+        VideoRecBlockMap::iterator itBlocks = this->mapBlocksCommon.find(uTimeStampMs);
+        if (itBlocks == this->mapBlocksCommon.end())
+        {
+            CaptureBlocks *pVideoRecBlocks = new CaptureBlocks();
+            pVideoRecBlocks->List.push_back(pBlock);
+
+            this->mapBlocksCommon.insert(std::make_pair(uTimeStampMs, pVideoRecBlocks));
+        }
+        else
+            itBlocks->second->List.push_back(pBlock);
+    }
+    catch (const std::exception &ex)
+    {
+        RT_NOREF(ex);
+        rc = VERR_NO_MEMORY;
+    }
+
+    int rc2 = RTCritSectLeave(&this->CritSect);
+    AssertRC(rc2);
+
+    if (RT_SUCCESS(rc))
+        rc = threadNotify();
+
+    return rc;
+#else
+    RT_NOREF(pCtx, pvData, cbData, uTimeStampMs);
+    return VINF_SUCCESS;
+#endif
+}
+
+/**
+ * Copies a source video frame to the intermediate RGB buffer.
+ * This function is executed only once per time.
+ *
+ * @thread  EMT
+ *
+ * @returns IPRT status code.
+ * @param   uScreen            Screen number to send video frame to.
+ * @param   x                  Starting x coordinate of the video frame.
+ * @param   y                  Starting y coordinate of the video frame.
+ * @param   uPixelFormat       Pixel format.
+ * @param   uBPP               Bits Per Pixel (BPP).
+ * @param   uBytesPerLine      Bytes per scanline.
+ * @param   uSrcWidth          Width of the video frame.
+ * @param   uSrcHeight         Height of the video frame.
+ * @param   puSrcData          Pointer to video frame data.
+ * @param   uTimeStampMs       Time stamp (in ms).
+ */
+int CaptureContext::SendVideoFrame(uint32_t uScreen, uint32_t x, uint32_t y,
+                                   uint32_t uPixelFormat, uint32_t uBPP, uint32_t uBytesPerLine,
+                                   uint32_t uSrcWidth, uint32_t uSrcHeight, uint8_t *puSrcData,
+                                   uint64_t uTimeStampMs)
+{
+    AssertReturn(uSrcWidth,  VERR_INVALID_PARAMETER);
+    AssertReturn(uSrcHeight, VERR_INVALID_PARAMETER);
+    AssertReturn(puSrcData,  VERR_INVALID_POINTER);
+
+    int rc = RTCritSectEnter(&this->CritSect);
+    AssertRC(rc);
+
+    CaptureStream *pStream = GetStream(uScreen);
+    if (!pStream)
+    {
+        rc = RTCritSectLeave(&this->CritSect);
+        AssertRC(rc);
+
+        return VERR_NOT_FOUND;
+    }
+
+    rc = pStream->SendVideoFrame(x, y, uPixelFormat, uBPP, uBytesPerLine, uSrcWidth, uSrcHeight, puSrcData, uTimeStampMs);
+
+    int rc2 = RTCritSectLeave(&this->CritSect);
+    AssertRC(rc2);
+
+    if (   RT_SUCCESS(rc)
+        && rc != VINF_TRY_AGAIN) /* Only signal the thread if operation was successful. */
+    {
+        threadNotify();
+    }
+
+    return rc;
+}
+
Index: /trunk/src/VBox/Main/src-client/RecordingInternals.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/RecordingInternals.cpp	(revision 75344)
+++ /trunk/src/VBox/Main/src-client/RecordingInternals.cpp	(revision 75344)
@@ -0,0 +1,93 @@
+/* $Id$ */
+/** @file
+ * Recording internals code.
+ */
+
+/*
+ * Copyright (C) 2012-2018 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.
+ */
+
+#include "RecordingInternals.h"
+
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+/**
+ * Frees a previously allocated video recording audio frame.
+ *
+ * @param   pFrame              Audio frame to free. The pointer will be invalid after return.
+ */
+void VideoRecAudioFrameFree(PVIDEORECAUDIOFRAME pFrame)
+{
+    if (!pFrame)
+        return;
+
+    if (pFrame->pvBuf)
+    {
+        Assert(pFrame->cbBuf);
+        RTMemFree(pFrame->pvBuf);
+    }
+    RTMemFree(pFrame);
+    pFrame = NULL;
+}
+#endif
+
+/**
+ * Frees a video recording video frame.
+ *
+ * @returns IPRT status code.
+ * @param   pFrame              Pointer to video frame to free. The pointer will be invalid after return.
+ */
+void VideoRecVideoFrameFree(PVIDEORECVIDEOFRAME pFrame)
+{
+    if (!pFrame)
+        return;
+
+    if (pFrame->pu8RGBBuf)
+    {
+        Assert(pFrame->cbRGBBuf);
+        RTMemFree(pFrame->pu8RGBBuf);
+    }
+    RTMemFree(pFrame);
+}
+
+/**
+ * Frees a video recording (data) block.
+ *
+ * @returns IPRT status code.
+ * @param   pBlock              Video recording (data) block to free. The pointer will be invalid after return.
+ */
+void VideoRecBlockFree(PVIDEORECBLOCK pBlock)
+{
+    if (!pBlock)
+        return;
+
+    switch (pBlock->enmType)
+    {
+        case VIDEORECBLOCKTYPE_VIDEO:
+            VideoRecVideoFrameFree((PVIDEORECVIDEOFRAME)pBlock->pvData);
+            break;
+
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+        case VIDEORECBLOCKTYPE_AUDIO:
+            VideoRecAudioFrameFree((PVIDEORECAUDIOFRAME)pBlock->pvData);
+            break;
+#endif
+        default:
+            AssertFailed();
+            break;
+    }
+
+    RTMemFree(pBlock);
+    pBlock = NULL;
+}
+
Index: /trunk/src/VBox/Main/src-client/RecordingStream.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/RecordingStream.cpp	(revision 75344)
+++ /trunk/src/VBox/Main/src-client/RecordingStream.cpp	(revision 75344)
@@ -0,0 +1,1119 @@
+/* $Id$ */
+/** @file
+ * Recording stream code.
+ */
+
+/*
+ * Copyright (C) 2012-2018 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.
+ */
+
+#ifdef LOG_GROUP
+# undef LOG_GROUP
+#endif
+#define LOG_GROUP LOG_GROUP_MAIN_DISPLAY
+#include "LoggingNew.h"
+
+#include <stdexcept>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <iprt/file.h>
+#include <iprt/path.h>
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+
+#include <VBox/err.h>
+#include <VBox/com/VirtualBox.h>
+
+#include "Recording.h"
+#include "RecordingStream.h"
+#include "RecordingUtils.h"
+#include "WebMWriter.h"
+
+
+CaptureStream::CaptureStream(CaptureContext *a_pCtx)
+    : pCtx(a_pCtx)
+    , enmState(RECORDINGSTREAMSTATE_UNINITIALIZED)
+    , tsStartMs(0)
+{
+    File.pWEBM = NULL;
+    File.hFile = NIL_RTFILE;
+}
+
+CaptureStream::CaptureStream(CaptureContext *a_pCtx, uint32_t uScreen, const settings::RecordScreenSettings &Settings)
+    : enmState(RECORDINGSTREAMSTATE_UNINITIALIZED)
+    , tsStartMs(0)
+{
+    File.pWEBM = NULL;
+    File.hFile = NIL_RTFILE;
+
+    int rc2 = initInternal(a_pCtx, uScreen, Settings);
+    if (RT_FAILURE(rc2))
+        throw rc2;
+}
+
+CaptureStream::~CaptureStream(void)
+{
+    int rc2 = uninitInternal();
+    AssertRC(rc2);
+}
+
+/**
+ * Opens a recording stream.
+ *
+ * @returns IPRT status code.
+ */
+int CaptureStream::open(const settings::RecordScreenSettings &Settings)
+{
+    /* Sanity. */
+    Assert(Settings.enmDest != RecordDestination_None);
+
+    int rc;
+
+    switch (Settings.enmDest)
+    {
+        case RecordDestination_File:
+        {
+            Assert(Settings.File.strName.isNotEmpty());
+
+            char *pszAbsPath = RTPathAbsDup(Settings.File.strName.c_str());
+            AssertPtrReturn(pszAbsPath, VERR_NO_MEMORY);
+
+            RTPathStripSuffix(pszAbsPath);
+
+            char *pszSuff = RTStrDup(".webm");
+            if (!pszSuff)
+            {
+                RTStrFree(pszAbsPath);
+                rc = VERR_NO_MEMORY;
+                break;
+            }
+
+            char *pszFile = NULL;
+
+            if (this->uScreenID > 0)
+                rc = RTStrAPrintf(&pszFile, "%s-%u%s", pszAbsPath, this->uScreenID + 1, pszSuff);
+            else
+                rc = RTStrAPrintf(&pszFile, "%s%s", pszAbsPath, pszSuff);
+
+            if (RT_SUCCESS(rc))
+            {
+                uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE;
+
+                /* Play safe: the file must not exist, overwriting is potentially
+                 * hazardous as nothing prevents the user from picking a file name of some
+                 * other important file, causing unintentional data loss. */
+                fOpen |= RTFILE_O_CREATE;
+
+                RTFILE hFile;
+                rc = RTFileOpen(&hFile, pszFile, fOpen);
+                if (rc == VERR_ALREADY_EXISTS)
+                {
+                    RTStrFree(pszFile);
+                    pszFile = NULL;
+
+                    RTTIMESPEC ts;
+                    RTTimeNow(&ts);
+                    RTTIME time;
+                    RTTimeExplode(&time, &ts);
+
+                    if (this->uScreenID > 0)
+                        rc = RTStrAPrintf(&pszFile, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ-%u%s",
+                                          pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay,
+                                          time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond,
+                                          this->uScreenID + 1, pszSuff);
+                    else
+                        rc = RTStrAPrintf(&pszFile, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ%s",
+                                          pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay,
+                                          time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond,
+                                          pszSuff);
+
+                    if (RT_SUCCESS(rc))
+                        rc = RTFileOpen(&hFile, pszFile, fOpen);
+                }
+
+                try
+                {
+                    Assert(File.pWEBM == NULL);
+                    File.pWEBM = new WebMWriter();
+                }
+                catch (std::bad_alloc &)
+               {
+                    rc = VERR_NO_MEMORY;
+                }
+
+                if (RT_SUCCESS(rc))
+                {
+                    this->File.hFile   = hFile;
+                    this->File.strName = pszFile;
+                }
+            }
+
+            RTStrFree(pszSuff);
+            RTStrFree(pszAbsPath);
+
+            if (RT_FAILURE(rc))
+            {
+                LogRel(("Recording: Failed to open file '%s' for screen %RU32, rc=%Rrc\n",
+                        pszFile ? pszFile : "<Unnamed>", this->uScreenID, rc));
+            }
+
+            RTStrFree(pszFile);
+            break;
+        }
+
+        default:
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+int CaptureStream::parseOptionsString(const com::Utf8Str &strOptions)
+{
+    size_t pos = 0;
+    com::Utf8Str key, value;
+    while ((pos = strOptions.parseKeyValue(key, value, pos)) != com::Utf8Str::npos)
+    {
+        if (key.compare("vc_quality", Utf8Str::CaseInsensitive) == 0)
+        {
+#ifdef VBOX_WITH_LIBVPX
+            Assert(this->ScreenSettings.Video.ulFPS);
+            if (value.compare("realtime", Utf8Str::CaseInsensitive) == 0)
+                this->Video.Codec.VPX.uEncoderDeadline = VPX_DL_REALTIME;
+            else if (value.compare("good", Utf8Str::CaseInsensitive) == 0)
+                this->Video.Codec.VPX.uEncoderDeadline = 1000000 / this->ScreenSettings.Video.ulFPS;
+            else if (value.compare("best", Utf8Str::CaseInsensitive) == 0)
+                this->Video.Codec.VPX.uEncoderDeadline = VPX_DL_BEST_QUALITY;
+            else
+            {
+                LogRel(("Recording: Setting encoder deadline to '%s'\n", value.c_str()));
+                this->Video.Codec.VPX.uEncoderDeadline = value.toUInt32();
+#endif
+            }
+        }
+        else if (key.compare("vc_enabled", Utf8Str::CaseInsensitive) == 0)
+        {
+            if (value.compare("false", Utf8Str::CaseInsensitive) == 0)
+            {
+                this->ScreenSettings.featureMap[RecordFeature_Video] = false;
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+                LogRel(("Recording: Only audio will be recorded\n"));
+#endif
+            }
+        }
+        else if (key.compare("ac_enabled", Utf8Str::CaseInsensitive) == 0)
+        {
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+            if (value.compare("true", Utf8Str::CaseInsensitive) == 0)
+            {
+                this->ScreenSettings.featureMap[RecordFeature_Audio] = true;
+            }
+            else
+                LogRel(("Recording: Only video will be recorded\n"));
+#endif
+        }
+        else if (key.compare("ac_profile", Utf8Str::CaseInsensitive) == 0)
+        {
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+            if (value.compare("low", Utf8Str::CaseInsensitive) == 0)
+            {
+                this->ScreenSettings.Audio.uHz       = 8000;
+                this->ScreenSettings.Audio.cBits     = 16;
+                this->ScreenSettings.Audio.cChannels = 1;
+            }
+            else if (value.startsWith("med" /* "med[ium]" */, Utf8Str::CaseInsensitive) == 0)
+            {
+                /* Stay with the default set above. */
+            }
+            else if (value.compare("high", Utf8Str::CaseInsensitive) == 0)
+            {
+                this->ScreenSettings.Audio.uHz       = 48000;
+                this->ScreenSettings.Audio.cBits     = 16;
+                this->ScreenSettings.Audio.cChannels = 2;
+            }
+#endif
+        }
+        else
+            LogRel(("Recording: Unknown option '%s' (value '%s'), skipping\n", key.c_str(), value.c_str()));
+
+    } /* while */
+
+    return VINF_SUCCESS;
+}
+
+const settings::RecordScreenSettings &CaptureStream::GetConfig(void) const
+{
+    return this->ScreenSettings;
+}
+
+/**
+ * Checks if a specified limit for recording has been reached.
+ *
+ * @returns true if any limit has been reached.
+ * @param   tsNowMs             Current time stamp (in ms).
+ */
+bool CaptureStream::IsLimitReached(uint64_t tsNowMs) const
+{
+    if (!IsReady())
+        return true;
+
+    if (   this->ScreenSettings.ulMaxTimeS
+        && tsNowMs >= this->tsStartMs + (this->ScreenSettings.ulMaxTimeS * RT_MS_1SEC))
+    {
+        return true;
+    }
+
+    if (this->ScreenSettings.enmDest == RecordDestination_File)
+    {
+
+        if (this->ScreenSettings.File.ulMaxSizeMB)
+        {
+            uint64_t sizeInMB = this->File.pWEBM->GetFileSize() / _1M;
+            if(sizeInMB >= this->ScreenSettings.File.ulMaxSizeMB)
+                return true;
+        }
+
+        /* Check for available free disk space */
+        if (   this->File.pWEBM
+            && this->File.pWEBM->GetAvailableSpace() < 0x100000) /** @todo r=andy WTF? Fix this. */
+        {
+            LogRel(("Recording: Not enough free storage space available, stopping video capture\n"));
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool CaptureStream::IsReady(void) const
+{
+    return this->fEnabled;
+}
+
+/**
+ * Processes a recording stream.
+ * This function takes care of the actual encoding and writing of a certain stream.
+ * As this can be very CPU intensive, this function usually is called from a separate thread.
+ *
+ * @returns IPRT status code.
+ * @param   mapBlocksCommon     Map of common block to process for this stream.
+ */
+int CaptureStream::Process(VideoRecBlockMap &mapBlocksCommon)
+{
+    lock();
+
+    if (!this->ScreenSettings.fEnabled)
+    {
+        unlock();
+        return VINF_SUCCESS;
+    }
+
+    int rc = VINF_SUCCESS;
+
+    VideoRecBlockMap::iterator itStreamBlocks = Blocks.Map.begin();
+    while (itStreamBlocks != Blocks.Map.end())
+    {
+        const uint64_t        uTimeStampMs = itStreamBlocks->first;
+              CaptureBlocks *pBlocks       = itStreamBlocks->second;
+
+        AssertPtr(pBlocks);
+
+        while (!pBlocks->List.empty())
+        {
+            PVIDEORECBLOCK pBlock = pBlocks->List.front();
+            AssertPtr(pBlock);
+
+#ifdef VBOX_WITH_LIBVPX
+            if (pBlock->enmType == VIDEORECBLOCKTYPE_VIDEO)
+            {
+                PVIDEORECVIDEOFRAME pVideoFrame  = (PVIDEORECVIDEOFRAME)pBlock->pvData;
+
+                rc = videoRecRGBToYUV(pVideoFrame->uPixelFormat,
+                                      /* Destination */
+                                      this->Video.Codec.VPX.pu8YuvBuf, pVideoFrame->uWidth, pVideoFrame->uHeight,
+                                      /* Source */
+                                      pVideoFrame->pu8RGBBuf, this->ScreenSettings.Video.ulWidth, this->ScreenSettings.Video.ulHeight);
+                if (RT_SUCCESS(rc))
+                {
+                    rc = writeVideoVPX(uTimeStampMs, pVideoFrame);
+                }
+                else
+                    break;
+            }
+#endif
+            VideoRecBlockFree(pBlock);
+            pBlock = NULL;
+
+            pBlocks->List.pop_front();
+        }
+
+        ++itStreamBlocks;
+    }
+
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+    AssertPtr(pCtx);
+
+    /* As each (enabled) screen has to get the same audio data, look for common (audio) data which needs to be
+     * written to the screen's assigned recording stream. */
+    VideoRecBlockMap::iterator itCommonBlocks = mapBlocksCommon.begin();
+    while (itCommonBlocks != mapBlocksCommon.end())
+    {
+        VideoRecBlockList::iterator itBlock = itCommonBlocks->second->List.begin();
+        while (itBlock != itCommonBlocks->second->List.end())
+        {
+            PVIDEORECBLOCK pBlockCommon = (PVIDEORECBLOCK)(*itBlock);
+            switch (pBlockCommon->enmType)
+            {
+                case VIDEORECBLOCKTYPE_AUDIO:
+                {
+                    PVIDEORECAUDIOFRAME pAudioFrame = (PVIDEORECAUDIOFRAME)pBlockCommon->pvData;
+                    AssertPtr(pAudioFrame);
+                    AssertPtr(pAudioFrame->pvBuf);
+                    Assert(pAudioFrame->cbBuf);
+
+                    WebMWriter::BlockData_Opus blockData = { pAudioFrame->pvBuf, pAudioFrame->cbBuf,
+                                                             pBlockCommon->uTimeStampMs };
+                    AssertPtr(this->File.pWEBM);
+                    rc = this->File.pWEBM->WriteBlock(this->uTrackAudio, &blockData, sizeof(blockData));
+                    break;
+                }
+
+                default:
+                    AssertFailed();
+                    break;
+            }
+
+            if (RT_FAILURE(rc))
+                break;
+
+            Assert(pBlockCommon->cRefs);
+            pBlockCommon->cRefs--;
+            if (pBlockCommon->cRefs == 0)
+            {
+                VideoRecBlockFree(pBlockCommon);
+                itCommonBlocks->second->List.erase(itBlock);
+                itBlock = itCommonBlocks->second->List.begin();
+            }
+            else
+                ++itBlock;
+        }
+
+        /* If no entries are left over in the block map, remove it altogether. */
+        if (itCommonBlocks->second->List.empty())
+        {
+            delete itCommonBlocks->second;
+            mapBlocksCommon.erase(itCommonBlocks);
+            itCommonBlocks = mapBlocksCommon.begin();
+        }
+        else
+            ++itCommonBlocks;
+
+        LogFunc(("Common blocks: %zu\n", mapBlocksCommon.size()));
+
+        if (RT_FAILURE(rc))
+            break;
+    }
+#endif
+
+    unlock();
+
+    return rc;
+}
+
+int CaptureStream::SendVideoFrame(uint32_t x, uint32_t y, uint32_t uPixelFormat, uint32_t uBPP, uint32_t uBytesPerLine,
+                                  uint32_t uSrcWidth, uint32_t uSrcHeight, uint8_t *puSrcData, uint64_t uTimeStampMs)
+{
+    lock();
+
+    PVIDEORECVIDEOFRAME pFrame = NULL;
+
+    int rc = VINF_SUCCESS;
+
+    do
+    {
+        if (!this->fEnabled)
+        {
+            rc = VINF_TRY_AGAIN; /* Not (yet) enabled. */
+            break;
+        }
+
+        if (uTimeStampMs < this->Video.uLastTimeStampMs + this->Video.uDelayMs)
+        {
+            rc = VINF_TRY_AGAIN; /* Respect maximum frames per second. */
+            break;
+        }
+
+        this->Video.uLastTimeStampMs = uTimeStampMs;
+
+        int xDiff = ((int)this->ScreenSettings.Video.ulWidth - (int)uSrcWidth) / 2;
+        uint32_t w = uSrcWidth;
+        if ((int)w + xDiff + (int)x <= 0)  /* Nothing visible. */
+        {
+            rc = VERR_INVALID_PARAMETER;
+            break;
+        }
+
+        uint32_t destX;
+        if ((int)x < -xDiff)
+        {
+            w += xDiff + x;
+            x = -xDiff;
+            destX = 0;
+        }
+        else
+            destX = x + xDiff;
+
+        uint32_t h = uSrcHeight;
+        int yDiff = ((int)this->ScreenSettings.Video.ulHeight - (int)uSrcHeight) / 2;
+        if ((int)h + yDiff + (int)y <= 0)  /* Nothing visible. */
+        {
+            rc = VERR_INVALID_PARAMETER;
+            break;
+        }
+
+        uint32_t destY;
+        if ((int)y < -yDiff)
+        {
+            h += yDiff + (int)y;
+            y = -yDiff;
+            destY = 0;
+        }
+        else
+            destY = y + yDiff;
+
+        if (   destX > this->ScreenSettings.Video.ulWidth
+            || destY > this->ScreenSettings.Video.ulHeight)
+        {
+            rc = VERR_INVALID_PARAMETER;  /* Nothing visible. */
+            break;
+        }
+
+        if (destX + w > this->ScreenSettings.Video.ulWidth)
+            w = this->ScreenSettings.Video.ulWidth - destX;
+
+        if (destY + h > this->ScreenSettings.Video.ulHeight)
+            h = this->ScreenSettings.Video.ulHeight - destY;
+
+        pFrame = (PVIDEORECVIDEOFRAME)RTMemAllocZ(sizeof(VIDEORECVIDEOFRAME));
+        AssertBreakStmt(pFrame, rc = VERR_NO_MEMORY);
+
+        /* Calculate bytes per pixel and set pixel format. */
+        const unsigned uBytesPerPixel = uBPP / 8;
+        if (uPixelFormat == BitmapFormat_BGR)
+        {
+            switch (uBPP)
+            {
+                case 32:
+                    pFrame->uPixelFormat = VIDEORECPIXELFMT_RGB32;
+                    break;
+                case 24:
+                    pFrame->uPixelFormat = VIDEORECPIXELFMT_RGB24;
+                    break;
+                case 16:
+                    pFrame->uPixelFormat = VIDEORECPIXELFMT_RGB565;
+                    break;
+                default:
+                    AssertMsgFailedBreakStmt(("Unknown color depth (%RU32)\n", uBPP), rc = VERR_NOT_SUPPORTED);
+                    break;
+            }
+        }
+        else
+            AssertMsgFailedBreakStmt(("Unknown pixel format (%RU32)\n", uPixelFormat), rc = VERR_NOT_SUPPORTED);
+
+        const size_t cbRGBBuf =   this->ScreenSettings.Video.ulWidth
+                                * this->ScreenSettings.Video.ulHeight
+                                * uBytesPerPixel;
+        AssertBreakStmt(cbRGBBuf, rc = VERR_INVALID_PARAMETER);
+
+        pFrame->pu8RGBBuf = (uint8_t *)RTMemAlloc(cbRGBBuf);
+        AssertBreakStmt(pFrame->pu8RGBBuf, rc = VERR_NO_MEMORY);
+        pFrame->cbRGBBuf  = cbRGBBuf;
+        pFrame->uWidth    = uSrcWidth;
+        pFrame->uHeight   = uSrcHeight;
+
+        /* If the current video frame is smaller than video resolution we're going to encode,
+         * clear the frame beforehand to prevent artifacts. */
+        if (   uSrcWidth  < this->ScreenSettings.Video.ulWidth
+            || uSrcHeight < this->ScreenSettings.Video.ulHeight)
+        {
+            RT_BZERO(pFrame->pu8RGBBuf, pFrame->cbRGBBuf);
+        }
+
+        /* Calculate start offset in source and destination buffers. */
+        uint32_t offSrc = y * uBytesPerLine + x * uBytesPerPixel;
+        uint32_t offDst = (destY * this->ScreenSettings.Video.ulWidth + destX) * uBytesPerPixel;
+
+#ifdef VBOX_VIDEOREC_DUMP
+        VIDEORECBMPHDR bmpHdr;
+        RT_ZERO(bmpHdr);
+
+        VIDEORECBMPDIBHDR bmpDIBHdr;
+        RT_ZERO(bmpDIBHdr);
+
+        bmpHdr.u16Magic   = 0x4d42; /* Magic */
+        bmpHdr.u32Size    = (uint32_t)(sizeof(VIDEORECBMPHDR) + sizeof(VIDEORECBMPDIBHDR) + (w * h * uBytesPerPixel));
+        bmpHdr.u32OffBits = (uint32_t)(sizeof(VIDEORECBMPHDR) + sizeof(VIDEORECBMPDIBHDR));
+
+        bmpDIBHdr.u32Size          = sizeof(VIDEORECBMPDIBHDR);
+        bmpDIBHdr.u32Width         = w;
+        bmpDIBHdr.u32Height        = h;
+        bmpDIBHdr.u16Planes        = 1;
+        bmpDIBHdr.u16BitCount      = uBPP;
+        bmpDIBHdr.u32XPelsPerMeter = 5000;
+        bmpDIBHdr.u32YPelsPerMeter = 5000;
+
+        char szFileName[RTPATH_MAX];
+        RTStrPrintf2(szFileName, sizeof(szFileName), "/tmp/VideoRecFrame-%RU32.bmp", this->uScreenID);
+
+        RTFILE fh;
+        int rc2 = RTFileOpen(&fh, szFileName,
+                             RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+        if (RT_SUCCESS(rc2))
+        {
+            RTFileWrite(fh, &bmpHdr,    sizeof(bmpHdr),    NULL);
+            RTFileWrite(fh, &bmpDIBHdr, sizeof(bmpDIBHdr), NULL);
+        }
+#endif
+        Assert(pFrame->cbRGBBuf >= w * h * uBytesPerPixel);
+
+        /* Do the copy. */
+        for (unsigned int i = 0; i < h; i++)
+        {
+            /* Overflow check. */
+            Assert(offSrc + w * uBytesPerPixel <= uSrcHeight * uBytesPerLine);
+            Assert(offDst + w * uBytesPerPixel <= this->ScreenSettings.Video.ulHeight * this->ScreenSettings.Video.ulWidth * uBytesPerPixel);
+
+            memcpy(pFrame->pu8RGBBuf + offDst, puSrcData + offSrc, w * uBytesPerPixel);
+
+#ifdef VBOX_VIDEOREC_DUMP
+            if (RT_SUCCESS(rc2))
+                RTFileWrite(fh, pFrame->pu8RGBBuf + offDst, w * uBytesPerPixel, NULL);
+#endif
+            offSrc += uBytesPerLine;
+            offDst += this->ScreenSettings.Video.ulWidth * uBytesPerPixel;
+        }
+
+#ifdef VBOX_VIDEOREC_DUMP
+        if (RT_SUCCESS(rc2))
+            RTFileClose(fh);
+#endif
+
+    } while (0);
+
+    if (rc == VINF_SUCCESS) /* Note: Also could be VINF_TRY_AGAIN. */
+    {
+        PVIDEORECBLOCK pBlock = (PVIDEORECBLOCK)RTMemAlloc(sizeof(VIDEORECBLOCK));
+        if (pBlock)
+        {
+            AssertPtr(pFrame);
+
+            pBlock->enmType = VIDEORECBLOCKTYPE_VIDEO;
+            pBlock->pvData  = pFrame;
+            pBlock->cbData  = sizeof(VIDEORECVIDEOFRAME) + pFrame->cbRGBBuf;
+
+            try
+            {
+                CaptureBlocks *pVideoRecBlocks = new CaptureBlocks();
+                pVideoRecBlocks->List.push_back(pBlock);
+
+                Assert(this->Blocks.Map.find(uTimeStampMs) == this->Blocks.Map.end());
+                this->Blocks.Map.insert(std::make_pair(uTimeStampMs, pVideoRecBlocks));
+            }
+            catch (const std::exception &ex)
+            {
+                RT_NOREF(ex);
+
+                RTMemFree(pBlock);
+                rc = VERR_NO_MEMORY;
+            }
+        }
+        else
+            rc = VERR_NO_MEMORY;
+    }
+
+    if (RT_FAILURE(rc))
+        VideoRecVideoFrameFree(pFrame);
+
+    unlock();
+
+    return rc;
+}
+
+/**
+ * Initializes a recording stream.
+ *
+ * @returns IPRT status code.
+ * @param   a_pCtx              Pointer to recording context.
+ * @param   uScreen             Screen number to use for this recording stream.
+ * @param   Settings            Capturing configuration to use for initialization.
+ */
+int CaptureStream::Init(CaptureContext *a_pCtx, uint32_t uScreen, const settings::RecordScreenSettings &Settings)
+{
+    return initInternal(a_pCtx, uScreen, Settings);
+}
+
+/**
+ * Initializes a recording stream, internal version.
+ *
+ * @returns IPRT status code.
+ * @param   a_pCtx              Pointer to recording context.
+ * @param   uScreen             Screen number to use for this recording stream.
+ * @param   Settings            Capturing configuration to use for initialization.
+ */
+int CaptureStream::initInternal(CaptureContext *a_pCtx, uint32_t uScreen, const settings::RecordScreenSettings &Settings)
+{
+    int rc = parseOptionsString(Settings.strOptions);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    rc = RTCritSectInit(&this->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    rc = open(Settings);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    const bool fVideoEnabled = Settings.isFeatureEnabled(RecordFeature_Video);
+    const bool fAudioEnabled = Settings.isFeatureEnabled(RecordFeature_Audio);
+
+    if (fVideoEnabled)
+        rc = initVideo();
+
+    if (fAudioEnabled)
+        rc = initAudio();
+
+    switch (this->ScreenSettings.enmDest)
+    {
+        case RecordDestination_File:
+        {
+            const char *pszFile = this->ScreenSettings.File.strName.c_str();
+
+            AssertPtr(File.pWEBM);
+            rc = File.pWEBM->OpenEx(pszFile, &this->File.hFile,
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+                                      Settings.isFeatureEnabled(RecordFeature_Audio)
+                                    ? WebMWriter::AudioCodec_Opus : WebMWriter::AudioCodec_None,
+#else
+                                      WebMWriter::AudioCodec_None,
+#endif
+                                      Settings.isFeatureEnabled(RecordFeature_Video)
+                                    ? WebMWriter::VideoCodec_VP8 : WebMWriter::VideoCodec_None);
+            if (RT_FAILURE(rc))
+            {
+                LogRel(("Recording: Failed to create the capture output file '%s' (%Rrc)\n", pszFile, rc));
+                break;
+            }
+
+            if (fVideoEnabled)
+            {
+                rc = this->File.pWEBM->AddVideoTrack(Settings.Video.ulWidth, Settings.Video.ulHeight,
+                                                     Settings.Video.ulFPS, &this->uTrackVideo);
+                if (RT_FAILURE(rc))
+                {
+                    LogRel(("Recording: Failed to add video track to output file '%s' (%Rrc)\n", pszFile, rc));
+                    break;
+                }
+
+                LogRel(("Recording: Recording video of screen #%u with %RU32x%RU32 @ %RU32 kbps, %RU32 FPS (track #%RU8)\n",
+                        this->uScreenID, Settings.Video.ulWidth, Settings.Video.ulHeight, Settings.Video.ulRate,
+                        Settings.Video.ulFPS, this->uTrackVideo));
+            }
+
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+            if (fAudioEnabled)
+            {
+                rc = this->File.pWEBM->AddAudioTrack(Settings.Audio.uHz, Settings.Audio.cChannels, Settings.Audio.cBits,
+                                                     &this->uTrackAudio);
+                if (RT_FAILURE(rc))
+                {
+                    LogRel(("Recording: Failed to add audio track to output file '%s' (%Rrc)\n", pszFile, rc));
+                    break;
+                }
+
+                LogRel(("Recording: Recording audio in %RU16Hz, %RU8 bit, %RU8 %s (track #%RU8)\n",
+                        Settings.Audio.uHz, Settings.Audio.cBits, Settings.Audio.cChannels,
+                        Settings.Audio.cChannels ? "channels" : "channel", this->uTrackAudio));
+            }
+#endif
+
+            if (   fVideoEnabled
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+                || fAudioEnabled
+#endif
+               )
+            {
+                char szWhat[32] = { 0 };
+                if (fVideoEnabled)
+                    RTStrCat(szWhat, sizeof(szWhat), "video");
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+                if (fAudioEnabled)
+                {
+                    if (fVideoEnabled)
+                        RTStrCat(szWhat, sizeof(szWhat), " + ");
+                    RTStrCat(szWhat, sizeof(szWhat), "audio");
+                }
+#endif
+                LogRel(("Recording: Recording %s to '%s'\n", szWhat, pszFile));
+            }
+
+            break;
+        }
+
+        default:
+            AssertFailed(); /* Should never happen. */
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        this->pCtx           = a_pCtx;
+        this->enmState       = RECORDINGSTREAMSTATE_INITIALIZED;
+        this->fEnabled       = true;
+        this->uScreenID      = uScreen;
+        this->tsStartMs      = RTTimeMilliTS();
+        this->ScreenSettings = Settings;
+    }
+    else
+    {
+        int rc2 = uninitInternal();
+        AssertRC(rc2);
+        return rc;
+    }
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Closes a recording stream.
+ * Depending on the stream's recording destination, this function closes all associated handles
+ * and finalizes recording.
+ *
+ * @returns IPRT status code.
+ */
+int CaptureStream::close(void)
+{
+    int rc = VINF_SUCCESS;
+
+    if (this->fEnabled)
+    {
+        switch (this->ScreenSettings.enmDest)
+        {
+            case RecordDestination_File:
+            {
+                if (this->File.pWEBM)
+                    rc = this->File.pWEBM->Close();
+                break;
+            }
+
+            default:
+                AssertFailed(); /* Should never happen. */
+                break;
+        }
+
+        this->Blocks.Clear();
+
+        LogRel(("Recording: Recording screen #%u stopped\n", this->uScreenID));
+    }
+
+    if (RT_FAILURE(rc))
+    {
+        LogRel(("Recording: Error stopping recording screen #%u, rc=%Rrc\n", this->uScreenID, rc));
+        return rc;
+    }
+
+    switch (this->ScreenSettings.enmDest)
+    {
+        case RecordDestination_File:
+        {
+            if (RTFileIsValid(this->File.hFile))
+            {
+                rc = RTFileClose(this->File.hFile);
+                if (RT_SUCCESS(rc))
+                {
+                    LogRel(("Recording: Closed file '%s'\n", this->ScreenSettings.File.strName.c_str()));
+                }
+                else
+                {
+                    LogRel(("Recording: Error closing file '%s', rc=%Rrc\n", this->ScreenSettings.File.strName.c_str(), rc));
+                    break;
+                }
+            }
+
+            if (this->File.pWEBM)
+            {
+                delete this->File.pWEBM;
+                this->File.pWEBM = NULL;
+            }
+            break;
+        }
+
+        default:
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+/**
+ * Uninitializes a recording stream.
+ *
+ * @returns IPRT status code.
+ */
+int CaptureStream::Uninit(void)
+{
+    return uninitInternal();
+}
+
+int CaptureStream::uninitInternal(void)
+{
+    if (this->enmState != RECORDINGSTREAMSTATE_INITIALIZED)
+        return VINF_SUCCESS;
+
+    int rc = close();
+    if (RT_FAILURE(rc))
+        return rc;
+
+    if (this->ScreenSettings.isFeatureEnabled(RecordFeature_Video))
+    {
+        int rc2 = unitVideo();
+        if (RT_SUCCESS(rc))
+            rc = rc2;
+    }
+
+    RTCritSectDelete(&this->CritSect);
+
+    this->enmState = RECORDINGSTREAMSTATE_UNINITIALIZED;
+    this->fEnabled = false;
+
+    return rc;
+}
+
+/**
+ * Uninitializes video recording for a certain recording stream.
+ *
+ * @returns IPRT status code.
+ */
+int CaptureStream::unitVideo(void)
+{
+#ifdef VBOX_WITH_LIBVPX
+    /* At the moment we only have VPX. */
+    return uninitVideoVPX();
+#else
+    return VERR_NOT_SUPPORTED;
+#endif
+}
+
+#ifdef VBOX_WITH_LIBVPX
+/**
+ * Uninitializes the VPX codec for a certain recording stream.
+ *
+ * @returns IPRT status code.
+ */
+int CaptureStream::uninitVideoVPX(void)
+{
+    PVIDEORECVIDEOCODEC pCodec = &this->Video.Codec;
+    vpx_img_free(&pCodec->VPX.RawImage);
+    pCodec->VPX.pu8YuvBuf = NULL; /* Was pointing to VPX.RawImage. */
+
+    vpx_codec_err_t rcv = vpx_codec_destroy(&this->Video.Codec.VPX.Ctx);
+    Assert(rcv == VPX_CODEC_OK); RT_NOREF(rcv);
+
+    return VINF_SUCCESS;
+}
+#endif
+
+/**
+ * Initializes the video recording for a certain recording stream.
+ *
+ * @returns IPRT status code.
+ */
+int CaptureStream::initVideo(void)
+{
+    /* Sanity. */
+    AssertReturn(this->ScreenSettings.Video.ulRate,   VERR_INVALID_PARAMETER);
+    AssertReturn(this->ScreenSettings.Video.ulWidth,  VERR_INVALID_PARAMETER);
+    AssertReturn(this->ScreenSettings.Video.ulHeight, VERR_INVALID_PARAMETER);
+    AssertReturn(this->ScreenSettings.Video.ulFPS,    VERR_INVALID_PARAMETER);
+
+    this->Video.cFailedEncodingFrames = 0;
+    this->Video.uDelayMs = RT_MS_1SEC / this->ScreenSettings.Video.ulFPS;
+
+#ifdef VBOX_WITH_LIBVPX
+    /* At the moment we only have VPX. */
+    return initVideoVPX();
+#else
+    return VINF_SUCCESS;
+#endif
+}
+
+#ifdef VBOX_WITH_LIBVPX
+/**
+ * Initializes the VPX codec for a certain recording stream.
+ *
+ * @returns IPRT status code.
+ */
+int CaptureStream::initVideoVPX(void)
+{
+# ifdef VBOX_WITH_LIBVPX_VP9
+    vpx_codec_iface_t *pCodecIface = vpx_codec_vp9_cx();
+# else /* Default is using VP8. */
+    vpx_codec_iface_t *pCodecIface = vpx_codec_vp8_cx();
+# endif
+
+    PVIDEORECVIDEOCODEC pCodec = &this->Video.Codec;
+
+    vpx_codec_err_t rcv = vpx_codec_enc_config_default(pCodecIface, &pCodec->VPX.Cfg, 0 /* Reserved */);
+    if (rcv != VPX_CODEC_OK)
+    {
+        LogRel(("Recording: Failed to get default config for VPX encoder: %s\n", vpx_codec_err_to_string(rcv)));
+        return VERR_AVREC_CODEC_INIT_FAILED;
+    }
+
+    /* Target bitrate in kilobits per second. */
+    pCodec->VPX.Cfg.rc_target_bitrate = this->ScreenSettings.Video.ulRate;
+    /* Frame width. */
+    pCodec->VPX.Cfg.g_w = this->ScreenSettings.Video.ulWidth;
+    /* Frame height. */
+    pCodec->VPX.Cfg.g_h = this->ScreenSettings.Video.ulHeight;
+    /* 1ms per frame. */
+    pCodec->VPX.Cfg.g_timebase.num = 1;
+    pCodec->VPX.Cfg.g_timebase.den = 1000;
+    /* Disable multithreading. */
+    pCodec->VPX.Cfg.g_threads = 0;
+
+    /* Initialize codec. */
+    rcv = vpx_codec_enc_init(&pCodec->VPX.Ctx, pCodecIface, &pCodec->VPX.Cfg, 0 /* Flags */);
+    if (rcv != VPX_CODEC_OK)
+    {
+        LogRel(("Recording: Failed to initialize VPX encoder: %s\n", vpx_codec_err_to_string(rcv)));
+        return VERR_AVREC_CODEC_INIT_FAILED;
+    }
+
+    if (!vpx_img_alloc(&pCodec->VPX.RawImage, VPX_IMG_FMT_I420,
+                       this->ScreenSettings.Video.ulWidth, this->ScreenSettings.Video.ulHeight, 1))
+    {
+        LogRel(("Recording: Failed to allocate image %RU32x%RU32\n",
+                this->ScreenSettings.Video.ulWidth, this->ScreenSettings.Video.ulHeight));
+        return VERR_NO_MEMORY;
+    }
+
+    /* Save a pointer to the first raw YUV plane. */
+    pCodec->VPX.pu8YuvBuf = pCodec->VPX.RawImage.planes[0];
+
+    return VINF_SUCCESS;
+}
+#endif
+
+int CaptureStream::initAudio(void)
+{
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+    if (this->ScreenSettings.isFeatureEnabled(RecordFeature_Audio))
+    {
+        /* Sanity. */
+        AssertReturn(this->ScreenSettings.Audio.uHz,       VERR_INVALID_PARAMETER);
+        AssertReturn(this->ScreenSettings.Audio.cBits,     VERR_INVALID_PARAMETER);
+        AssertReturn(this->ScreenSettings.Audio.cChannels, VERR_INVALID_PARAMETER);
+    }
+#endif
+
+    return VINF_SUCCESS;
+}
+
+#ifdef VBOX_WITH_LIBVPX
+/**
+ * Encodes the source image and write the encoded image to the stream's destination.
+ *
+ * @returns IPRT status code.
+ * @param   uTimeStampMs        Absolute timestamp (PTS) of frame (in ms) to encode.
+ * @param   pFrame              Frame to encode and submit.
+ */
+int CaptureStream::writeVideoVPX(uint64_t uTimeStampMs, PVIDEORECVIDEOFRAME pFrame)
+{
+    AssertPtrReturn(pFrame, VERR_INVALID_POINTER);
+
+    int rc;
+
+    PVIDEORECVIDEOCODEC pCodec = &this->Video.Codec;
+
+    /* Presentation Time Stamp (PTS). */
+    vpx_codec_pts_t pts = uTimeStampMs;
+    vpx_codec_err_t rcv = vpx_codec_encode(&pCodec->VPX.Ctx,
+                                           &pCodec->VPX.RawImage,
+                                           pts                          /* Time stamp */,
+                                           this->Video.uDelayMs         /* How long to show this frame */,
+                                           0                            /* Flags */,
+                                           pCodec->VPX.uEncoderDeadline /* Quality setting */);
+    if (rcv != VPX_CODEC_OK)
+    {
+        if (this->Video.cFailedEncodingFrames++ < 64) /** @todo Make this configurable. */
+        {
+            LogRel(("Recording: Failed to encode video frame: %s\n", vpx_codec_err_to_string(rcv)));
+            return VERR_GENERAL_FAILURE;
+        }
+    }
+
+    this->Video.cFailedEncodingFrames = 0;
+
+    vpx_codec_iter_t iter = NULL;
+    rc = VERR_NO_DATA;
+    for (;;)
+    {
+        const vpx_codec_cx_pkt_t *pPacket = vpx_codec_get_cx_data(&pCodec->VPX.Ctx, &iter);
+        if (!pPacket)
+            break;
+
+        switch (pPacket->kind)
+        {
+            case VPX_CODEC_CX_FRAME_PKT:
+            {
+                WebMWriter::BlockData_VP8 blockData = { &pCodec->VPX.Cfg, pPacket };
+                rc = this->File.pWEBM->WriteBlock(this->uTrackVideo, &blockData, sizeof(blockData));
+                break;
+            }
+
+            default:
+                AssertFailed();
+                LogFunc(("Unexpected video packet type %ld\n", pPacket->kind));
+                break;
+        }
+    }
+
+    return rc;
+}
+#endif /* VBOX_WITH_LIBVPX */
+
+/**
+ * Locks a recording stream.
+ */
+void CaptureStream::lock(void)
+{
+    int rc = RTCritSectEnter(&CritSect);
+    AssertRC(rc);
+}
+
+/**
+ * Unlocks a locked recording stream.
+ */
+void CaptureStream::unlock(void)
+{
+    int rc = RTCritSectLeave(&CritSect);
+    AssertRC(rc);
+}
+
Index: /trunk/src/VBox/Main/src-client/RecordingUtils.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/RecordingUtils.cpp	(revision 75344)
+++ /trunk/src/VBox/Main/src-client/RecordingUtils.cpp	(revision 75344)
@@ -0,0 +1,176 @@
+/* $Id$ */
+/** @file
+ * Recording utility code.
+ */
+
+/*
+ * Copyright (C) 2012-2018 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.
+ */
+
+#include "Recording.h"
+#include "RecordingUtils.h"
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <iprt/path.h>
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+
+
+/**
+ * Convert an image to YUV420p format.
+ *
+ * @return true on success, false on failure.
+ * @param  aDstBuf              The destination image buffer.
+ * @param  aDstWidth            Width (in pixel) of destination buffer.
+ * @param  aDstHeight           Height (in pixel) of destination buffer.
+ * @param  aSrcBuf              The source image buffer.
+ * @param  aSrcWidth            Width (in pixel) of source buffer.
+ * @param  aSrcHeight           Height (in pixel) of source buffer.
+ */
+template <class T>
+inline bool videoRecColorConvWriteYUV420p(uint8_t *aDstBuf, unsigned aDstWidth, unsigned aDstHeight,
+                                          uint8_t *aSrcBuf, unsigned aSrcWidth, unsigned aSrcHeight)
+{
+    RT_NOREF(aDstWidth, aDstHeight);
+
+    AssertReturn(!(aSrcWidth & 1),  false);
+    AssertReturn(!(aSrcHeight & 1), false);
+
+    bool fRc = true;
+    T iter1(aSrcWidth, aSrcHeight, aSrcBuf);
+    T iter2 = iter1;
+    iter2.skip(aSrcWidth);
+    unsigned cPixels = aSrcWidth * aSrcHeight;
+    unsigned offY = 0;
+    unsigned offU = cPixels;
+    unsigned offV = cPixels + cPixels / 4;
+    unsigned const cyHalf = aSrcHeight / 2;
+    unsigned const cxHalf = aSrcWidth  / 2;
+    for (unsigned i = 0; i < cyHalf && fRc; ++i)
+    {
+        for (unsigned j = 0; j < cxHalf; ++j)
+        {
+            unsigned red, green, blue;
+            fRc = iter1.getRGB(&red, &green, &blue);
+            AssertReturn(fRc, false);
+            aDstBuf[offY] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
+            unsigned u = (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
+            unsigned v = (((112 * red - 94 * green -  18 * blue + 128) >> 8) + 128) / 4;
+
+            fRc = iter1.getRGB(&red, &green, &blue);
+            AssertReturn(fRc, false);
+            aDstBuf[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;
+
+            fRc = iter2.getRGB(&red, &green, &blue);
+            AssertReturn(fRc, false);
+            aDstBuf[offY + aSrcWidth] = ((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;
+
+            fRc = iter2.getRGB(&red, &green, &blue);
+            AssertReturn(fRc, false);
+            aDstBuf[offY + aSrcWidth + 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;
+
+            aDstBuf[offU] = u;
+            aDstBuf[offV] = v;
+            offY += 2;
+            ++offU;
+            ++offV;
+        }
+
+        iter1.skip(aSrcWidth);
+        iter2.skip(aSrcWidth);
+        offY += aSrcWidth;
+    }
+
+    return true;
+}
+
+/**
+ * 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 videoRecColorConvWriteRGB24(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;
+}
+
+/**
+ * Converts a RGB to YUV buffer.
+ *
+ * @returns IPRT status code.
+ * @param   uPixelFormat        Pixel format to use for conversion.
+ * @param   paDst               Pointer to destination buffer.
+ * @param   uDstWidth           Width (X, in pixels) of destination buffer.
+ * @param   uDstHeight          Height (Y, in pixels) of destination buffer.
+ * @param   paSrc               Pointer to source buffer.
+ * @param   uSrcWidth           Width (X, in pixels) of source buffer.
+ * @param   uSrcHeight          Height (Y, in pixels) of source buffer.
+ */
+int videoRecRGBToYUV(uint32_t uPixelFormat,
+                     uint8_t *paDst, uint32_t uDstWidth, uint32_t uDstHeight,
+                     uint8_t *paSrc, uint32_t uSrcWidth, uint32_t uSrcHeight)
+{
+    switch (uPixelFormat)
+    {
+        case VIDEORECPIXELFMT_RGB32:
+            if (!videoRecColorConvWriteYUV420p<ColorConvBGRA32Iter>(paDst, uDstWidth, uDstHeight,
+                                                            paSrc, uSrcWidth, uSrcHeight))
+                return VERR_INVALID_PARAMETER;
+            break;
+        case VIDEORECPIXELFMT_RGB24:
+            if (!videoRecColorConvWriteYUV420p<ColorConvBGR24Iter>(paDst, uDstWidth, uDstHeight,
+                                                           paSrc, uSrcWidth, uSrcHeight))
+                return VERR_INVALID_PARAMETER;
+            break;
+        case VIDEORECPIXELFMT_RGB565:
+            if (!videoRecColorConvWriteYUV420p<ColorConvBGR565Iter>(paDst, uDstWidth, uDstHeight,
+                                                            paSrc, uSrcWidth, uSrcHeight))
+                return VERR_INVALID_PARAMETER;
+            break;
+        default:
+            AssertFailed();
+            return VERR_NOT_SUPPORTED;
+    }
+    return VINF_SUCCESS;
+}
+
Index: /trunk/src/VBox/Main/src-client/VBoxDriversRegister.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/VBoxDriversRegister.cpp	(revision 75343)
+++ /trunk/src/VBox/Main/src-client/VBoxDriversRegister.cpp	(revision 75344)
@@ -32,5 +32,5 @@
 #endif
 #ifdef VBOX_WITH_AUDIO_VIDEOREC
-# include "DrvAudioVideoRec.h"
+# include "DrvAudioRec.h"
 #endif
 #include "Nvram.h"
Index: unk/src/VBox/Main/src-client/VideoRec.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/VideoRec.cpp	(revision 75343)
+++ 	(revision )
@@ -1,583 +1,0 @@
-/* $Id$ */
-/** @file
- * Video recording (with optional audio recording) code.
- *
- * This code employs a separate encoding thread per recording context
- * to keep time spent in EMT as short as possible. Each configured VM display
- * is represented by an own recording stream, which in turn has its own rendering
- * queue. Common recording data across all recording streams is kept in a
- * separate queue in the recording context to minimize data duplication and
- * multiplexing overhead in EMT.
- */
-
-/*
- * Copyright (C) 2012-2018 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.
- */
-
-#ifdef LOG_GROUP
-# undef LOG_GROUP
-#endif
-#define LOG_GROUP LOG_GROUP_MAIN_DISPLAY
-#include "LoggingNew.h"
-
-#include <stdexcept>
-#include <vector>
-
-#include <iprt/asm.h>
-#include <iprt/assert.h>
-#include <iprt/critsect.h>
-#include <iprt/path.h>
-#include <iprt/semaphore.h>
-#include <iprt/thread.h>
-#include <iprt/time.h>
-
-#include <VBox/err.h>
-#include <VBox/com/VirtualBox.h>
-
-#include "ConsoleImpl.h"
-#include "VideoRec.h"
-#include "VideoRecInternals.h"
-#include "VideoRecStream.h"
-#include "VideoRecUtils.h"
-#include "WebMWriter.h"
-
-using namespace com;
-
-#ifdef DEBUG_andy
-/** Enables dumping audio / video data for debugging reasons. */
-//# define VBOX_VIDEOREC_DUMP
-#endif
-
-#ifdef VBOX_VIDEOREC_DUMP
-#pragma pack(push)
-#pragma pack(1)
-typedef struct
-{
-    uint16_t u16Magic;
-    uint32_t u32Size;
-    uint16_t u16Reserved1;
-    uint16_t u16Reserved2;
-    uint32_t u32OffBits;
-} VIDEORECBMPHDR, *PVIDEORECBMPHDR;
-AssertCompileSize(VIDEORECBMPHDR, 14);
-
-typedef struct
-{
-    uint32_t u32Size;
-    uint32_t u32Width;
-    uint32_t u32Height;
-    uint16_t u16Planes;
-    uint16_t u16BitCount;
-    uint32_t u32Compression;
-    uint32_t u32SizeImage;
-    uint32_t u32XPelsPerMeter;
-    uint32_t u32YPelsPerMeter;
-    uint32_t u32ClrUsed;
-    uint32_t u32ClrImportant;
-} VIDEORECBMPDIBHDR, *PVIDEORECBMPDIBHDR;
-AssertCompileSize(VIDEORECBMPDIBHDR, 40);
-
-#pragma pack(pop)
-#endif /* VBOX_VIDEOREC_DUMP */
-
-
-CaptureContext::CaptureContext(Console *a_pConsole)
-    : pConsole(a_pConsole)
-    , enmState(VIDEORECSTS_UNINITIALIZED) { }
-
-CaptureContext::CaptureContext(Console *a_pConsole, const settings::RecordSettings &a_Settings)
-    : pConsole(a_pConsole)
-    , enmState(VIDEORECSTS_UNINITIALIZED)
-{
-    int rc = CaptureContext::createInternal(a_Settings);
-    if (RT_FAILURE(rc))
-        throw rc;
-}
-
-CaptureContext::~CaptureContext(void)
-{
-    destroyInternal();
-}
-
-/**
- * Worker thread for all streams of a video recording context.
- *
- * For video frames, this also does the RGB/YUV conversion and encoding.
- */
-DECLCALLBACK(int) CaptureContext::threadMain(RTTHREAD hThreadSelf, void *pvUser)
-{
-    CaptureContext *pThis = (CaptureContext *)pvUser;
-
-    /* Signal that we're up and rockin'. */
-    RTThreadUserSignal(hThreadSelf);
-
-    LogFunc(("Thread started\n"));
-
-    for (;;)
-    {
-        int rc = RTSemEventWait(pThis->WaitEvent, RT_INDEFINITE_WAIT);
-        AssertRCBreak(rc);
-
-        Log2Func(("Processing %zu streams\n", pThis->vecStreams.size()));
-
-        /** @todo r=andy This is inefficient -- as we already wake up this thread
-         *               for every screen from Main, we here go again (on every wake up) through
-         *               all screens.  */
-        VideoRecStreams::iterator itStream = pThis->vecStreams.begin();
-        while (itStream != pThis->vecStreams.end())
-        {
-            CaptureStream *pStream = (*itStream);
-
-            rc = pStream->Process(pThis->mapBlocksCommon);
-            if (RT_FAILURE(rc))
-                break;
-
-            ++itStream;
-        }
-
-        if (RT_FAILURE(rc))
-            LogRel(("VideoRec: Encoding thread failed with rc=%Rrc\n", rc));
-
-        /* Keep going in case of errors. */
-
-        if (ASMAtomicReadBool(&pThis->fShutdown))
-        {
-            LogFunc(("Thread is shutting down ...\n"));
-            break;
-        }
-
-    } /* for */
-
-    LogFunc(("Thread ended\n"));
-    return VINF_SUCCESS;
-}
-
-/**
- * Notifies a recording context's encoding thread.
- *
- * @returns IPRT status code.
- */
-int CaptureContext::threadNotify(void)
-{
-    return RTSemEventSignal(this->WaitEvent);
-}
-
-/**
- * Creates a video recording context.
- *
- * @returns IPRT status code.
- * @param   a_Settings          Capture settings to use for context creation.
- */
-int CaptureContext::createInternal(const settings::RecordSettings &a_Settings)
-{
-    int rc = RTCritSectInit(&this->CritSect);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    settings::RecordScreenMap::const_iterator itScreen = a_Settings.mapScreens.begin();
-    while (itScreen != a_Settings.mapScreens.end())
-    {
-        CaptureStream *pStream = NULL;
-        try
-        {
-            pStream = new CaptureStream(this, itScreen->first /* Screen ID */, itScreen->second);
-            this->vecStreams.push_back(pStream);
-        }
-        catch (std::bad_alloc &)
-        {
-            rc = VERR_NO_MEMORY;
-            break;
-        }
-
-        ++itScreen;
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        this->tsStartMs = RTTimeMilliTS();
-        this->enmState  = VIDEORECSTS_CREATED;
-        this->fShutdown = false;
-
-        /* Copy the settings to our context. */
-        this->Settings  = a_Settings;
-
-        rc = RTSemEventCreate(&this->WaitEvent);
-        AssertRCReturn(rc, rc);
-    }
-
-    if (RT_FAILURE(rc))
-    {
-        int rc2 = destroyInternal();
-        AssertRC(rc2);
-    }
-
-    return rc;
-}
-
-int CaptureContext::startInternal(void)
-{
-    if (this->enmState == VIDEORECSTS_STARTED)
-        return VINF_SUCCESS;
-
-    Assert(this->enmState == VIDEORECSTS_CREATED);
-
-    int rc = RTThreadCreate(&this->Thread, CaptureContext::threadMain, (void *)this, 0,
-                            RTTHREADTYPE_MAIN_WORKER, RTTHREADFLAGS_WAITABLE, "Record");
-
-    if (RT_SUCCESS(rc)) /* Wait for the thread to start. */
-        rc = RTThreadUserWait(this->Thread, 30 * RT_MS_1SEC /* 30s timeout */);
-
-    if (RT_SUCCESS(rc))
-    {
-        this->enmState = VIDEORECSTS_STARTED;
-    }
-
-    return rc;
-}
-
-int CaptureContext::stopInternal(void)
-{
-    if (this->enmState != VIDEORECSTS_STARTED)
-        return VINF_SUCCESS;
-
-    LogThisFunc(("Shutting down thread ...\n"));
-
-    /* Set shutdown indicator. */
-    ASMAtomicWriteBool(&this->fShutdown, true);
-
-    /* Signal the thread and wait for it to shut down. */
-    int rc = threadNotify();
-    if (RT_SUCCESS(rc))
-        rc = RTThreadWait(this->Thread, 30 * 1000 /* 10s timeout */, NULL);
-
-    if (RT_SUCCESS(rc))
-    {
-        this->enmState = VIDEORECSTS_CREATED;
-    }
-
-    LogFlowThisFunc(("%Rrc\n", rc));
-    return rc;
-}
-
-/**
- * Destroys a video recording context.
- */
-int CaptureContext::destroyInternal(void)
-{
-    int rc = stopInternal();
-    if (RT_FAILURE(rc))
-        return rc;
-
-    rc = RTSemEventDestroy(this->WaitEvent);
-    AssertRC(rc);
-
-    this->WaitEvent = NIL_RTSEMEVENT;
-
-    rc = RTCritSectEnter(&this->CritSect);
-    if (RT_SUCCESS(rc))
-    {
-        VideoRecStreams::iterator it = this->vecStreams.begin();
-        while (it != this->vecStreams.end())
-        {
-            CaptureStream *pStream = (*it);
-
-            int rc2 = pStream->Uninit();
-            if (RT_SUCCESS(rc))
-                rc = rc2;
-
-            delete pStream;
-            pStream = NULL;
-
-            this->vecStreams.erase(it);
-            it = this->vecStreams.begin();
-
-            delete pStream;
-            pStream = NULL;
-        }
-
-        /* Sanity. */
-        Assert(this->vecStreams.empty());
-        Assert(this->mapBlocksCommon.size() == 0);
-
-        int rc2 = RTCritSectLeave(&this->CritSect);
-        AssertRC(rc2);
-
-        RTCritSectDelete(&this->CritSect);
-    }
-
-    LogFlowThisFunc(("%Rrc\n", rc));
-    return rc;
-}
-
-const settings::RecordSettings &CaptureContext::GetConfig(void) const
-{
-    return this->Settings;
-}
-
-CaptureStream *CaptureContext::getStreamInternal(unsigned uScreen) const
-{
-    CaptureStream *pStream;
-
-    try
-    {
-        pStream = this->vecStreams.at(uScreen);
-    }
-    catch (std::out_of_range &)
-    {
-        pStream = NULL;
-    }
-
-    return pStream;
-}
-
-/**
- * Retrieves a specific recording stream of a recording context.
- *
- * @returns Pointer to recording stream if found, or NULL if not found.
- * @param   uScreen             Screen number of recording stream to look up.
- */
-CaptureStream *CaptureContext::GetStream(unsigned uScreen) const
-{
-    return getStreamInternal(uScreen);
-}
-
-size_t CaptureContext::GetStreamCount(void) const
-{
-    return this->vecStreams.size();
-}
-
-int CaptureContext::Create(const settings::RecordSettings &a_Settings)
-{
-    return createInternal(a_Settings);
-}
-
-int CaptureContext::Destroy(void)
-{
-    return destroyInternal();
-}
-
-int CaptureContext::Start(void)
-{
-    return startInternal();
-}
-
-int CaptureContext::Stop(void)
-{
-    return stopInternal();
-}
-
-bool CaptureContext::IsFeatureEnabled(RecordFeature_T enmFeature) const
-{
-    VideoRecStreams::const_iterator itStream = this->vecStreams.begin();
-    while (itStream != this->vecStreams.end())
-    {
-        if ((*itStream)->GetConfig().isFeatureEnabled(enmFeature))
-            return true;
-        ++itStream;
-    }
-
-    return false;
-}
-
-/**
- * Returns if this recording context is ready to start recording.
- *
- * @returns @c true if recording context is ready, @c false if not.
- */
-bool CaptureContext::IsReady(void) const
-{
-    return (this->enmState >= VIDEORECSTS_CREATED);
-}
-
-/**
- * Returns if this recording context is ready to accept new recording data for a given screen.
- *
- * @returns @c true if the specified screen is ready, @c false if not.
- * @param   uScreen             Screen ID.
- * @param   uTimeStampMs        Current time stamp (in ms). Currently not being used.
- */
-bool CaptureContext::IsReady(uint32_t uScreen, uint64_t uTimeStampMs) const
-{
-    RT_NOREF(uTimeStampMs);
-
-    if (this->enmState != VIDEORECSTS_STARTED)
-        return false;
-
-    bool fIsReady = false;
-
-    const CaptureStream *pStream = GetStream(uScreen);
-    if (pStream)
-        fIsReady = pStream->IsReady();
-
-    /* Note: Do not check for other constraints like the video FPS rate here,
-     *       as this check then also would affect other (non-FPS related) stuff
-     *       like audio data. */
-
-    return fIsReady;
-}
-
-/**
- * Returns whether a given recording context has been started or not.
- *
- * @returns true if active, false if not.
- */
-bool CaptureContext::IsStarted(void) const
-{
-    return (this->enmState == VIDEORECSTS_STARTED);
-}
-
-/**
- * Checks if a specified limit for recording has been reached.
- *
- * @returns true if any limit has been reached.
- * @param   uScreen             Screen ID.
- * @param   tsNowMs             Current time stamp (in ms).
- */
-bool CaptureContext::IsLimitReached(uint32_t uScreen, uint64_t tsNowMs) const
-{
-    const CaptureStream *pStream = GetStream(uScreen);
-    if (   !pStream
-        || pStream->IsLimitReached(tsNowMs))
-    {
-        return true;
-    }
-
-    return false;
-}
-
-/**
- * Sends an audio frame to the video encoding thread.
- *
- * @thread  EMT
- *
- * @returns IPRT status code.
- * @param   pvData              Audio frame data to send.
- * @param   cbData              Size (in bytes) of (encoded) audio frame data.
- * @param   uTimeStampMs        Time stamp (in ms) of audio playback.
- */
-int CaptureContext::SendAudioFrame(const void *pvData, size_t cbData, uint64_t uTimeStampMs)
-{
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
-    AssertReturn(cbData, VERR_INVALID_PARAMETER);
-
-    /* To save time spent in EMT, do the required audio multiplexing in the encoding thread.
-     *
-     * The multiplexing is needed to supply all recorded (enabled) screens with the same
-     * audio data at the same given point in time.
-     */
-    PVIDEORECBLOCK pBlock = (PVIDEORECBLOCK)RTMemAlloc(sizeof(VIDEORECBLOCK));
-    AssertPtrReturn(pBlock, VERR_NO_MEMORY);
-    pBlock->enmType = VIDEORECBLOCKTYPE_AUDIO;
-
-    PVIDEORECAUDIOFRAME pFrame = (PVIDEORECAUDIOFRAME)RTMemAlloc(sizeof(VIDEORECAUDIOFRAME));
-    AssertPtrReturn(pFrame, VERR_NO_MEMORY);
-
-    pFrame->pvBuf = (uint8_t *)RTMemAlloc(cbData);
-    AssertPtrReturn(pFrame->pvBuf, VERR_NO_MEMORY);
-    pFrame->cbBuf = cbData;
-
-    memcpy(pFrame->pvBuf, pvData, cbData);
-
-    pBlock->pvData       = pFrame;
-    pBlock->cbData       = sizeof(VIDEORECAUDIOFRAME) + cbData;
-    pBlock->cRefs        = (uint16_t)this->vecStreams.size(); /* All streams need the same audio data. */
-    pBlock->uTimeStampMs = uTimeStampMs;
-
-    int rc = RTCritSectEnter(&this->CritSect);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    try
-    {
-        VideoRecBlockMap::iterator itBlocks = this->mapBlocksCommon.find(uTimeStampMs);
-        if (itBlocks == this->mapBlocksCommon.end())
-        {
-            CaptureBlocks *pVideoRecBlocks = new CaptureBlocks();
-            pVideoRecBlocks->List.push_back(pBlock);
-
-            this->mapBlocksCommon.insert(std::make_pair(uTimeStampMs, pVideoRecBlocks));
-        }
-        else
-            itBlocks->second->List.push_back(pBlock);
-    }
-    catch (const std::exception &ex)
-    {
-        RT_NOREF(ex);
-        rc = VERR_NO_MEMORY;
-    }
-
-    int rc2 = RTCritSectLeave(&this->CritSect);
-    AssertRC(rc2);
-
-    if (RT_SUCCESS(rc))
-        rc = threadNotify();
-
-    return rc;
-#else
-    RT_NOREF(pCtx, pvData, cbData, uTimeStampMs);
-    return VINF_SUCCESS;
-#endif
-}
-
-/**
- * Copies a source video frame to the intermediate RGB buffer.
- * This function is executed only once per time.
- *
- * @thread  EMT
- *
- * @returns IPRT status code.
- * @param   uScreen            Screen number to send video frame to.
- * @param   x                  Starting x coordinate of the video frame.
- * @param   y                  Starting y coordinate of the video frame.
- * @param   uPixelFormat       Pixel format.
- * @param   uBPP               Bits Per Pixel (BPP).
- * @param   uBytesPerLine      Bytes per scanline.
- * @param   uSrcWidth          Width of the video frame.
- * @param   uSrcHeight         Height of the video frame.
- * @param   puSrcData          Pointer to video frame data.
- * @param   uTimeStampMs       Time stamp (in ms).
- */
-int CaptureContext::SendVideoFrame(uint32_t uScreen, uint32_t x, uint32_t y,
-                                   uint32_t uPixelFormat, uint32_t uBPP, uint32_t uBytesPerLine,
-                                   uint32_t uSrcWidth, uint32_t uSrcHeight, uint8_t *puSrcData,
-                                   uint64_t uTimeStampMs)
-{
-    AssertReturn(uSrcWidth,  VERR_INVALID_PARAMETER);
-    AssertReturn(uSrcHeight, VERR_INVALID_PARAMETER);
-    AssertReturn(puSrcData,  VERR_INVALID_POINTER);
-
-    int rc = RTCritSectEnter(&this->CritSect);
-    AssertRC(rc);
-
-    CaptureStream *pStream = GetStream(uScreen);
-    if (!pStream)
-    {
-        rc = RTCritSectLeave(&this->CritSect);
-        AssertRC(rc);
-
-        return VERR_NOT_FOUND;
-    }
-
-    rc = pStream->SendVideoFrame(x, y, uPixelFormat, uBPP, uBytesPerLine, uSrcWidth, uSrcHeight, puSrcData, uTimeStampMs);
-
-    int rc2 = RTCritSectLeave(&this->CritSect);
-    AssertRC(rc2);
-
-    if (   RT_SUCCESS(rc)
-        && rc != VINF_TRY_AGAIN) /* Only signal the thread if operation was successful. */
-    {
-        threadNotify();
-    }
-
-    return rc;
-}
-
Index: unk/src/VBox/Main/src-client/VideoRecInternals.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/VideoRecInternals.cpp	(revision 75343)
+++ 	(revision )
@@ -1,93 +1,0 @@
-/* $Id$ */
-/** @file
- * Video recording internals code.
- */
-
-/*
- * Copyright (C) 2012-2018 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.
- */
-
-#include "VideoRecInternals.h"
-
-#include <iprt/assert.h>
-#include <iprt/mem.h>
-
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-/**
- * Frees a previously allocated video recording audio frame.
- *
- * @param   pFrame              Audio frame to free. The pointer will be invalid after return.
- */
-void VideoRecAudioFrameFree(PVIDEORECAUDIOFRAME pFrame)
-{
-    if (!pFrame)
-        return;
-
-    if (pFrame->pvBuf)
-    {
-        Assert(pFrame->cbBuf);
-        RTMemFree(pFrame->pvBuf);
-    }
-    RTMemFree(pFrame);
-    pFrame = NULL;
-}
-#endif
-
-/**
- * Frees a video recording video frame.
- *
- * @returns IPRT status code.
- * @param   pFrame              Pointer to video frame to free. The pointer will be invalid after return.
- */
-void VideoRecVideoFrameFree(PVIDEORECVIDEOFRAME pFrame)
-{
-    if (!pFrame)
-        return;
-
-    if (pFrame->pu8RGBBuf)
-    {
-        Assert(pFrame->cbRGBBuf);
-        RTMemFree(pFrame->pu8RGBBuf);
-    }
-    RTMemFree(pFrame);
-}
-
-/**
- * Frees a video recording (data) block.
- *
- * @returns IPRT status code.
- * @param   pBlock              Video recording (data) block to free. The pointer will be invalid after return.
- */
-void VideoRecBlockFree(PVIDEORECBLOCK pBlock)
-{
-    if (!pBlock)
-        return;
-
-    switch (pBlock->enmType)
-    {
-        case VIDEORECBLOCKTYPE_VIDEO:
-            VideoRecVideoFrameFree((PVIDEORECVIDEOFRAME)pBlock->pvData);
-            break;
-
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-        case VIDEORECBLOCKTYPE_AUDIO:
-            VideoRecAudioFrameFree((PVIDEORECAUDIOFRAME)pBlock->pvData);
-            break;
-#endif
-        default:
-            AssertFailed();
-            break;
-    }
-
-    RTMemFree(pBlock);
-    pBlock = NULL;
-}
-
Index: unk/src/VBox/Main/src-client/VideoRecStream.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/VideoRecStream.cpp	(revision 75343)
+++ 	(revision )
@@ -1,1119 +1,0 @@
-/* $Id$ */
-/** @file
- * Video recording stream code.
- */
-
-/*
- * Copyright (C) 2012-2018 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.
- */
-
-#ifdef LOG_GROUP
-# undef LOG_GROUP
-#endif
-#define LOG_GROUP LOG_GROUP_MAIN_DISPLAY
-#include "LoggingNew.h"
-
-#include <stdexcept>
-
-#include <iprt/asm.h>
-#include <iprt/assert.h>
-#include <iprt/critsect.h>
-#include <iprt/file.h>
-#include <iprt/path.h>
-#include <iprt/semaphore.h>
-#include <iprt/thread.h>
-#include <iprt/time.h>
-
-#include <VBox/err.h>
-#include <VBox/com/VirtualBox.h>
-
-#include "VideoRec.h"
-#include "VideoRecStream.h"
-#include "VideoRecUtils.h"
-#include "WebMWriter.h"
-
-
-CaptureStream::CaptureStream(CaptureContext *a_pCtx)
-    : pCtx(a_pCtx)
-    , enmState(RECORDINGSTREAMSTATE_UNINITIALIZED)
-    , tsStartMs(0)
-{
-    File.pWEBM = NULL;
-    File.hFile = NIL_RTFILE;
-}
-
-CaptureStream::CaptureStream(CaptureContext *a_pCtx, uint32_t uScreen, const settings::RecordScreenSettings &Settings)
-    : enmState(RECORDINGSTREAMSTATE_UNINITIALIZED)
-    , tsStartMs(0)
-{
-    File.pWEBM = NULL;
-    File.hFile = NIL_RTFILE;
-
-    int rc2 = initInternal(a_pCtx, uScreen, Settings);
-    if (RT_FAILURE(rc2))
-        throw rc2;
-}
-
-CaptureStream::~CaptureStream(void)
-{
-    int rc2 = uninitInternal();
-    AssertRC(rc2);
-}
-
-/**
- * Opens a recording stream.
- *
- * @returns IPRT status code.
- */
-int CaptureStream::open(const settings::RecordScreenSettings &Settings)
-{
-    /* Sanity. */
-    Assert(Settings.enmDest != RecordDestination_None);
-
-    int rc;
-
-    switch (Settings.enmDest)
-    {
-        case RecordDestination_File:
-        {
-            Assert(Settings.File.strName.isNotEmpty());
-
-            char *pszAbsPath = RTPathAbsDup(Settings.File.strName.c_str());
-            AssertPtrReturn(pszAbsPath, VERR_NO_MEMORY);
-
-            RTPathStripSuffix(pszAbsPath);
-
-            char *pszSuff = RTStrDup(".webm");
-            if (!pszSuff)
-            {
-                RTStrFree(pszAbsPath);
-                rc = VERR_NO_MEMORY;
-                break;
-            }
-
-            char *pszFile = NULL;
-
-            if (this->uScreenID > 0)
-                rc = RTStrAPrintf(&pszFile, "%s-%u%s", pszAbsPath, this->uScreenID + 1, pszSuff);
-            else
-                rc = RTStrAPrintf(&pszFile, "%s%s", pszAbsPath, pszSuff);
-
-            if (RT_SUCCESS(rc))
-            {
-                uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE;
-
-                /* Play safe: the file must not exist, overwriting is potentially
-                 * hazardous as nothing prevents the user from picking a file name of some
-                 * other important file, causing unintentional data loss. */
-                fOpen |= RTFILE_O_CREATE;
-
-                RTFILE hFile;
-                rc = RTFileOpen(&hFile, pszFile, fOpen);
-                if (rc == VERR_ALREADY_EXISTS)
-                {
-                    RTStrFree(pszFile);
-                    pszFile = NULL;
-
-                    RTTIMESPEC ts;
-                    RTTimeNow(&ts);
-                    RTTIME time;
-                    RTTimeExplode(&time, &ts);
-
-                    if (this->uScreenID > 0)
-                        rc = RTStrAPrintf(&pszFile, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ-%u%s",
-                                          pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay,
-                                          time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond,
-                                          this->uScreenID + 1, pszSuff);
-                    else
-                        rc = RTStrAPrintf(&pszFile, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ%s",
-                                          pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay,
-                                          time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond,
-                                          pszSuff);
-
-                    if (RT_SUCCESS(rc))
-                        rc = RTFileOpen(&hFile, pszFile, fOpen);
-                }
-
-                try
-                {
-                    Assert(File.pWEBM == NULL);
-                    File.pWEBM = new WebMWriter();
-                }
-                catch (std::bad_alloc &)
-               {
-                    rc = VERR_NO_MEMORY;
-                }
-
-                if (RT_SUCCESS(rc))
-                {
-                    this->File.hFile   = hFile;
-                    this->File.strName = pszFile;
-                }
-            }
-
-            RTStrFree(pszSuff);
-            RTStrFree(pszAbsPath);
-
-            if (RT_FAILURE(rc))
-            {
-                LogRel(("VideoRec: Failed to open file '%s' for screen %RU32, rc=%Rrc\n",
-                        pszFile ? pszFile : "<Unnamed>", this->uScreenID, rc));
-            }
-
-            RTStrFree(pszFile);
-            break;
-        }
-
-        default:
-            rc = VERR_NOT_IMPLEMENTED;
-            break;
-    }
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-int CaptureStream::parseOptionsString(const com::Utf8Str &strOptions)
-{
-    size_t pos = 0;
-    com::Utf8Str key, value;
-    while ((pos = strOptions.parseKeyValue(key, value, pos)) != com::Utf8Str::npos)
-    {
-        if (key.compare("vc_quality", Utf8Str::CaseInsensitive) == 0)
-        {
-#ifdef VBOX_WITH_LIBVPX
-            Assert(this->ScreenSettings.Video.ulFPS);
-            if (value.compare("realtime", Utf8Str::CaseInsensitive) == 0)
-                this->Video.Codec.VPX.uEncoderDeadline = VPX_DL_REALTIME;
-            else if (value.compare("good", Utf8Str::CaseInsensitive) == 0)
-                this->Video.Codec.VPX.uEncoderDeadline = 1000000 / this->ScreenSettings.Video.ulFPS;
-            else if (value.compare("best", Utf8Str::CaseInsensitive) == 0)
-                this->Video.Codec.VPX.uEncoderDeadline = VPX_DL_BEST_QUALITY;
-            else
-            {
-                LogRel(("VideoRec: Setting encoder deadline to '%s'\n", value.c_str()));
-                this->Video.Codec.VPX.uEncoderDeadline = value.toUInt32();
-#endif
-            }
-        }
-        else if (key.compare("vc_enabled", Utf8Str::CaseInsensitive) == 0)
-        {
-            if (value.compare("false", Utf8Str::CaseInsensitive) == 0)
-            {
-                this->ScreenSettings.featureMap[RecordFeature_Video] = false;
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-                LogRel(("VideoRec: Only audio will be recorded\n"));
-#endif
-            }
-        }
-        else if (key.compare("ac_enabled", Utf8Str::CaseInsensitive) == 0)
-        {
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-            if (value.compare("true", Utf8Str::CaseInsensitive) == 0)
-            {
-                this->ScreenSettings.featureMap[RecordFeature_Audio] = true;
-            }
-            else
-                LogRel(("VideoRec: Only video will be recorded\n"));
-#endif
-        }
-        else if (key.compare("ac_profile", Utf8Str::CaseInsensitive) == 0)
-        {
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-            if (value.compare("low", Utf8Str::CaseInsensitive) == 0)
-            {
-                this->ScreenSettings.Audio.uHz       = 8000;
-                this->ScreenSettings.Audio.cBits     = 16;
-                this->ScreenSettings.Audio.cChannels = 1;
-            }
-            else if (value.startsWith("med" /* "med[ium]" */, Utf8Str::CaseInsensitive) == 0)
-            {
-                /* Stay with the default set above. */
-            }
-            else if (value.compare("high", Utf8Str::CaseInsensitive) == 0)
-            {
-                this->ScreenSettings.Audio.uHz       = 48000;
-                this->ScreenSettings.Audio.cBits     = 16;
-                this->ScreenSettings.Audio.cChannels = 2;
-            }
-#endif
-        }
-        else
-            LogRel(("VideoRec: Unknown option '%s' (value '%s'), skipping\n", key.c_str(), value.c_str()));
-
-    } /* while */
-
-    return VINF_SUCCESS;
-}
-
-const settings::RecordScreenSettings &CaptureStream::GetConfig(void) const
-{
-    return this->ScreenSettings;
-}
-
-/**
- * Checks if a specified limit for recording has been reached.
- *
- * @returns true if any limit has been reached.
- * @param   tsNowMs             Current time stamp (in ms).
- */
-bool CaptureStream::IsLimitReached(uint64_t tsNowMs) const
-{
-    if (!IsReady())
-        return true;
-
-    if (   this->ScreenSettings.ulMaxTimeS
-        && tsNowMs >= this->tsStartMs + (this->ScreenSettings.ulMaxTimeS * RT_MS_1SEC))
-    {
-        return true;
-    }
-
-    if (this->ScreenSettings.enmDest == RecordDestination_File)
-    {
-
-        if (this->ScreenSettings.File.ulMaxSizeMB)
-        {
-            uint64_t sizeInMB = this->File.pWEBM->GetFileSize() / _1M;
-            if(sizeInMB >= this->ScreenSettings.File.ulMaxSizeMB)
-                return true;
-        }
-
-        /* Check for available free disk space */
-        if (   this->File.pWEBM
-            && this->File.pWEBM->GetAvailableSpace() < 0x100000) /** @todo r=andy WTF? Fix this. */
-        {
-            LogRel(("VideoRec: Not enough free storage space available, stopping video capture\n"));
-            return true;
-        }
-    }
-
-    return false;
-}
-
-bool CaptureStream::IsReady(void) const
-{
-    return this->fEnabled;
-}
-
-/**
- * Processes a recording stream.
- * This function takes care of the actual encoding and writing of a certain stream.
- * As this can be very CPU intensive, this function usually is called from a separate thread.
- *
- * @returns IPRT status code.
- * @param   mapBlocksCommon     Map of common block to process for this stream.
- */
-int CaptureStream::Process(VideoRecBlockMap &mapBlocksCommon)
-{
-    lock();
-
-    if (!this->ScreenSettings.fEnabled)
-    {
-        unlock();
-        return VINF_SUCCESS;
-    }
-
-    int rc = VINF_SUCCESS;
-
-    VideoRecBlockMap::iterator itStreamBlocks = Blocks.Map.begin();
-    while (itStreamBlocks != Blocks.Map.end())
-    {
-        const uint64_t        uTimeStampMs = itStreamBlocks->first;
-              CaptureBlocks *pBlocks       = itStreamBlocks->second;
-
-        AssertPtr(pBlocks);
-
-        while (!pBlocks->List.empty())
-        {
-            PVIDEORECBLOCK pBlock = pBlocks->List.front();
-            AssertPtr(pBlock);
-
-#ifdef VBOX_WITH_LIBVPX
-            if (pBlock->enmType == VIDEORECBLOCKTYPE_VIDEO)
-            {
-                PVIDEORECVIDEOFRAME pVideoFrame  = (PVIDEORECVIDEOFRAME)pBlock->pvData;
-
-                rc = videoRecRGBToYUV(pVideoFrame->uPixelFormat,
-                                      /* Destination */
-                                      this->Video.Codec.VPX.pu8YuvBuf, pVideoFrame->uWidth, pVideoFrame->uHeight,
-                                      /* Source */
-                                      pVideoFrame->pu8RGBBuf, this->ScreenSettings.Video.ulWidth, this->ScreenSettings.Video.ulHeight);
-                if (RT_SUCCESS(rc))
-                {
-                    rc = writeVideoVPX(uTimeStampMs, pVideoFrame);
-                }
-                else
-                    break;
-            }
-#endif
-            VideoRecBlockFree(pBlock);
-            pBlock = NULL;
-
-            pBlocks->List.pop_front();
-        }
-
-        ++itStreamBlocks;
-    }
-
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-    AssertPtr(pCtx);
-
-    /* As each (enabled) screen has to get the same audio data, look for common (audio) data which needs to be
-     * written to the screen's assigned recording stream. */
-    VideoRecBlockMap::iterator itCommonBlocks = mapBlocksCommon.begin();
-    while (itCommonBlocks != mapBlocksCommon.end())
-    {
-        VideoRecBlockList::iterator itBlock = itCommonBlocks->second->List.begin();
-        while (itBlock != itCommonBlocks->second->List.end())
-        {
-            PVIDEORECBLOCK pBlockCommon = (PVIDEORECBLOCK)(*itBlock);
-            switch (pBlockCommon->enmType)
-            {
-                case VIDEORECBLOCKTYPE_AUDIO:
-                {
-                    PVIDEORECAUDIOFRAME pAudioFrame = (PVIDEORECAUDIOFRAME)pBlockCommon->pvData;
-                    AssertPtr(pAudioFrame);
-                    AssertPtr(pAudioFrame->pvBuf);
-                    Assert(pAudioFrame->cbBuf);
-
-                    WebMWriter::BlockData_Opus blockData = { pAudioFrame->pvBuf, pAudioFrame->cbBuf,
-                                                             pBlockCommon->uTimeStampMs };
-                    AssertPtr(this->File.pWEBM);
-                    rc = this->File.pWEBM->WriteBlock(this->uTrackAudio, &blockData, sizeof(blockData));
-                    break;
-                }
-
-                default:
-                    AssertFailed();
-                    break;
-            }
-
-            if (RT_FAILURE(rc))
-                break;
-
-            Assert(pBlockCommon->cRefs);
-            pBlockCommon->cRefs--;
-            if (pBlockCommon->cRefs == 0)
-            {
-                VideoRecBlockFree(pBlockCommon);
-                itCommonBlocks->second->List.erase(itBlock);
-                itBlock = itCommonBlocks->second->List.begin();
-            }
-            else
-                ++itBlock;
-        }
-
-        /* If no entries are left over in the block map, remove it altogether. */
-        if (itCommonBlocks->second->List.empty())
-        {
-            delete itCommonBlocks->second;
-            mapBlocksCommon.erase(itCommonBlocks);
-            itCommonBlocks = mapBlocksCommon.begin();
-        }
-        else
-            ++itCommonBlocks;
-
-        LogFunc(("Common blocks: %zu\n", mapBlocksCommon.size()));
-
-        if (RT_FAILURE(rc))
-            break;
-    }
-#endif
-
-    unlock();
-
-    return rc;
-}
-
-int CaptureStream::SendVideoFrame(uint32_t x, uint32_t y, uint32_t uPixelFormat, uint32_t uBPP, uint32_t uBytesPerLine,
-                                  uint32_t uSrcWidth, uint32_t uSrcHeight, uint8_t *puSrcData, uint64_t uTimeStampMs)
-{
-    lock();
-
-    PVIDEORECVIDEOFRAME pFrame = NULL;
-
-    int rc = VINF_SUCCESS;
-
-    do
-    {
-        if (!this->fEnabled)
-        {
-            rc = VINF_TRY_AGAIN; /* Not (yet) enabled. */
-            break;
-        }
-
-        if (uTimeStampMs < this->Video.uLastTimeStampMs + this->Video.uDelayMs)
-        {
-            rc = VINF_TRY_AGAIN; /* Respect maximum frames per second. */
-            break;
-        }
-
-        this->Video.uLastTimeStampMs = uTimeStampMs;
-
-        int xDiff = ((int)this->ScreenSettings.Video.ulWidth - (int)uSrcWidth) / 2;
-        uint32_t w = uSrcWidth;
-        if ((int)w + xDiff + (int)x <= 0)  /* Nothing visible. */
-        {
-            rc = VERR_INVALID_PARAMETER;
-            break;
-        }
-
-        uint32_t destX;
-        if ((int)x < -xDiff)
-        {
-            w += xDiff + x;
-            x = -xDiff;
-            destX = 0;
-        }
-        else
-            destX = x + xDiff;
-
-        uint32_t h = uSrcHeight;
-        int yDiff = ((int)this->ScreenSettings.Video.ulHeight - (int)uSrcHeight) / 2;
-        if ((int)h + yDiff + (int)y <= 0)  /* Nothing visible. */
-        {
-            rc = VERR_INVALID_PARAMETER;
-            break;
-        }
-
-        uint32_t destY;
-        if ((int)y < -yDiff)
-        {
-            h += yDiff + (int)y;
-            y = -yDiff;
-            destY = 0;
-        }
-        else
-            destY = y + yDiff;
-
-        if (   destX > this->ScreenSettings.Video.ulWidth
-            || destY > this->ScreenSettings.Video.ulHeight)
-        {
-            rc = VERR_INVALID_PARAMETER;  /* Nothing visible. */
-            break;
-        }
-
-        if (destX + w > this->ScreenSettings.Video.ulWidth)
-            w = this->ScreenSettings.Video.ulWidth - destX;
-
-        if (destY + h > this->ScreenSettings.Video.ulHeight)
-            h = this->ScreenSettings.Video.ulHeight - destY;
-
-        pFrame = (PVIDEORECVIDEOFRAME)RTMemAllocZ(sizeof(VIDEORECVIDEOFRAME));
-        AssertBreakStmt(pFrame, rc = VERR_NO_MEMORY);
-
-        /* Calculate bytes per pixel and set pixel format. */
-        const unsigned uBytesPerPixel = uBPP / 8;
-        if (uPixelFormat == BitmapFormat_BGR)
-        {
-            switch (uBPP)
-            {
-                case 32:
-                    pFrame->uPixelFormat = VIDEORECPIXELFMT_RGB32;
-                    break;
-                case 24:
-                    pFrame->uPixelFormat = VIDEORECPIXELFMT_RGB24;
-                    break;
-                case 16:
-                    pFrame->uPixelFormat = VIDEORECPIXELFMT_RGB565;
-                    break;
-                default:
-                    AssertMsgFailedBreakStmt(("Unknown color depth (%RU32)\n", uBPP), rc = VERR_NOT_SUPPORTED);
-                    break;
-            }
-        }
-        else
-            AssertMsgFailedBreakStmt(("Unknown pixel format (%RU32)\n", uPixelFormat), rc = VERR_NOT_SUPPORTED);
-
-        const size_t cbRGBBuf =   this->ScreenSettings.Video.ulWidth
-                                * this->ScreenSettings.Video.ulHeight
-                                * uBytesPerPixel;
-        AssertBreakStmt(cbRGBBuf, rc = VERR_INVALID_PARAMETER);
-
-        pFrame->pu8RGBBuf = (uint8_t *)RTMemAlloc(cbRGBBuf);
-        AssertBreakStmt(pFrame->pu8RGBBuf, rc = VERR_NO_MEMORY);
-        pFrame->cbRGBBuf  = cbRGBBuf;
-        pFrame->uWidth    = uSrcWidth;
-        pFrame->uHeight   = uSrcHeight;
-
-        /* If the current video frame is smaller than video resolution we're going to encode,
-         * clear the frame beforehand to prevent artifacts. */
-        if (   uSrcWidth  < this->ScreenSettings.Video.ulWidth
-            || uSrcHeight < this->ScreenSettings.Video.ulHeight)
-        {
-            RT_BZERO(pFrame->pu8RGBBuf, pFrame->cbRGBBuf);
-        }
-
-        /* Calculate start offset in source and destination buffers. */
-        uint32_t offSrc = y * uBytesPerLine + x * uBytesPerPixel;
-        uint32_t offDst = (destY * this->ScreenSettings.Video.ulWidth + destX) * uBytesPerPixel;
-
-#ifdef VBOX_VIDEOREC_DUMP
-        VIDEORECBMPHDR bmpHdr;
-        RT_ZERO(bmpHdr);
-
-        VIDEORECBMPDIBHDR bmpDIBHdr;
-        RT_ZERO(bmpDIBHdr);
-
-        bmpHdr.u16Magic   = 0x4d42; /* Magic */
-        bmpHdr.u32Size    = (uint32_t)(sizeof(VIDEORECBMPHDR) + sizeof(VIDEORECBMPDIBHDR) + (w * h * uBytesPerPixel));
-        bmpHdr.u32OffBits = (uint32_t)(sizeof(VIDEORECBMPHDR) + sizeof(VIDEORECBMPDIBHDR));
-
-        bmpDIBHdr.u32Size          = sizeof(VIDEORECBMPDIBHDR);
-        bmpDIBHdr.u32Width         = w;
-        bmpDIBHdr.u32Height        = h;
-        bmpDIBHdr.u16Planes        = 1;
-        bmpDIBHdr.u16BitCount      = uBPP;
-        bmpDIBHdr.u32XPelsPerMeter = 5000;
-        bmpDIBHdr.u32YPelsPerMeter = 5000;
-
-        char szFileName[RTPATH_MAX];
-        RTStrPrintf2(szFileName, sizeof(szFileName), "/tmp/VideoRecFrame-%RU32.bmp", this->uScreenID);
-
-        RTFILE fh;
-        int rc2 = RTFileOpen(&fh, szFileName,
-                             RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
-        if (RT_SUCCESS(rc2))
-        {
-            RTFileWrite(fh, &bmpHdr,    sizeof(bmpHdr),    NULL);
-            RTFileWrite(fh, &bmpDIBHdr, sizeof(bmpDIBHdr), NULL);
-        }
-#endif
-        Assert(pFrame->cbRGBBuf >= w * h * uBytesPerPixel);
-
-        /* Do the copy. */
-        for (unsigned int i = 0; i < h; i++)
-        {
-            /* Overflow check. */
-            Assert(offSrc + w * uBytesPerPixel <= uSrcHeight * uBytesPerLine);
-            Assert(offDst + w * uBytesPerPixel <= this->ScreenSettings.Video.ulHeight * this->ScreenSettings.Video.ulWidth * uBytesPerPixel);
-
-            memcpy(pFrame->pu8RGBBuf + offDst, puSrcData + offSrc, w * uBytesPerPixel);
-
-#ifdef VBOX_VIDEOREC_DUMP
-            if (RT_SUCCESS(rc2))
-                RTFileWrite(fh, pFrame->pu8RGBBuf + offDst, w * uBytesPerPixel, NULL);
-#endif
-            offSrc += uBytesPerLine;
-            offDst += this->ScreenSettings.Video.ulWidth * uBytesPerPixel;
-        }
-
-#ifdef VBOX_VIDEOREC_DUMP
-        if (RT_SUCCESS(rc2))
-            RTFileClose(fh);
-#endif
-
-    } while (0);
-
-    if (rc == VINF_SUCCESS) /* Note: Also could be VINF_TRY_AGAIN. */
-    {
-        PVIDEORECBLOCK pBlock = (PVIDEORECBLOCK)RTMemAlloc(sizeof(VIDEORECBLOCK));
-        if (pBlock)
-        {
-            AssertPtr(pFrame);
-
-            pBlock->enmType = VIDEORECBLOCKTYPE_VIDEO;
-            pBlock->pvData  = pFrame;
-            pBlock->cbData  = sizeof(VIDEORECVIDEOFRAME) + pFrame->cbRGBBuf;
-
-            try
-            {
-                CaptureBlocks *pVideoRecBlocks = new CaptureBlocks();
-                pVideoRecBlocks->List.push_back(pBlock);
-
-                Assert(this->Blocks.Map.find(uTimeStampMs) == this->Blocks.Map.end());
-                this->Blocks.Map.insert(std::make_pair(uTimeStampMs, pVideoRecBlocks));
-            }
-            catch (const std::exception &ex)
-            {
-                RT_NOREF(ex);
-
-                RTMemFree(pBlock);
-                rc = VERR_NO_MEMORY;
-            }
-        }
-        else
-            rc = VERR_NO_MEMORY;
-    }
-
-    if (RT_FAILURE(rc))
-        VideoRecVideoFrameFree(pFrame);
-
-    unlock();
-
-    return rc;
-}
-
-/**
- * Initializes a recording stream.
- *
- * @returns IPRT status code.
- * @param   a_pCtx              Pointer to recording context.
- * @param   uScreen             Screen number to use for this recording stream.
- * @param   Settings            Capturing configuration to use for initialization.
- */
-int CaptureStream::Init(CaptureContext *a_pCtx, uint32_t uScreen, const settings::RecordScreenSettings &Settings)
-{
-    return initInternal(a_pCtx, uScreen, Settings);
-}
-
-/**
- * Initializes a recording stream, internal version.
- *
- * @returns IPRT status code.
- * @param   a_pCtx              Pointer to recording context.
- * @param   uScreen             Screen number to use for this recording stream.
- * @param   Settings            Capturing configuration to use for initialization.
- */
-int CaptureStream::initInternal(CaptureContext *a_pCtx, uint32_t uScreen, const settings::RecordScreenSettings &Settings)
-{
-    int rc = parseOptionsString(Settings.strOptions);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    rc = RTCritSectInit(&this->CritSect);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    rc = open(Settings);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    const bool fVideoEnabled = Settings.isFeatureEnabled(RecordFeature_Video);
-    const bool fAudioEnabled = Settings.isFeatureEnabled(RecordFeature_Audio);
-
-    if (fVideoEnabled)
-        rc = initVideo();
-
-    if (fAudioEnabled)
-        rc = initAudio();
-
-    switch (this->ScreenSettings.enmDest)
-    {
-        case RecordDestination_File:
-        {
-            const char *pszFile = this->ScreenSettings.File.strName.c_str();
-
-            AssertPtr(File.pWEBM);
-            rc = File.pWEBM->OpenEx(pszFile, &this->File.hFile,
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-                                      Settings.isFeatureEnabled(RecordFeature_Audio)
-                                    ? WebMWriter::AudioCodec_Opus : WebMWriter::AudioCodec_None,
-#else
-                                      WebMWriter::AudioCodec_None,
-#endif
-                                      Settings.isFeatureEnabled(RecordFeature_Video)
-                                    ? WebMWriter::VideoCodec_VP8 : WebMWriter::VideoCodec_None);
-            if (RT_FAILURE(rc))
-            {
-                LogRel(("VideoRec: Failed to create the capture output file '%s' (%Rrc)\n", pszFile, rc));
-                break;
-            }
-
-            if (fVideoEnabled)
-            {
-                rc = this->File.pWEBM->AddVideoTrack(Settings.Video.ulWidth, Settings.Video.ulHeight,
-                                                     Settings.Video.ulFPS, &this->uTrackVideo);
-                if (RT_FAILURE(rc))
-                {
-                    LogRel(("VideoRec: Failed to add video track to output file '%s' (%Rrc)\n", pszFile, rc));
-                    break;
-                }
-
-                LogRel(("VideoRec: Recording video of screen #%u with %RU32x%RU32 @ %RU32 kbps, %RU32 FPS (track #%RU8)\n",
-                        this->uScreenID, Settings.Video.ulWidth, Settings.Video.ulHeight, Settings.Video.ulRate,
-                        Settings.Video.ulFPS, this->uTrackVideo));
-            }
-
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-            if (fAudioEnabled)
-            {
-                rc = this->File.pWEBM->AddAudioTrack(Settings.Audio.uHz, Settings.Audio.cChannels, Settings.Audio.cBits,
-                                                     &this->uTrackAudio);
-                if (RT_FAILURE(rc))
-                {
-                    LogRel(("VideoRec: Failed to add audio track to output file '%s' (%Rrc)\n", pszFile, rc));
-                    break;
-                }
-
-                LogRel(("VideoRec: Recording audio in %RU16Hz, %RU8 bit, %RU8 %s (track #%RU8)\n",
-                        Settings.Audio.uHz, Settings.Audio.cBits, Settings.Audio.cChannels,
-                        Settings.Audio.cChannels ? "channels" : "channel", this->uTrackAudio));
-            }
-#endif
-
-            if (   fVideoEnabled
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-                || fAudioEnabled
-#endif
-               )
-            {
-                char szWhat[32] = { 0 };
-                if (fVideoEnabled)
-                    RTStrCat(szWhat, sizeof(szWhat), "video");
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-                if (fAudioEnabled)
-                {
-                    if (fVideoEnabled)
-                        RTStrCat(szWhat, sizeof(szWhat), " + ");
-                    RTStrCat(szWhat, sizeof(szWhat), "audio");
-                }
-#endif
-                LogRel(("VideoRec: Recording %s to '%s'\n", szWhat, pszFile));
-            }
-
-            break;
-        }
-
-        default:
-            AssertFailed(); /* Should never happen. */
-            rc = VERR_NOT_IMPLEMENTED;
-            break;
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        this->pCtx           = a_pCtx;
-        this->enmState       = RECORDINGSTREAMSTATE_INITIALIZED;
-        this->fEnabled       = true;
-        this->uScreenID      = uScreen;
-        this->tsStartMs      = RTTimeMilliTS();
-        this->ScreenSettings = Settings;
-    }
-    else
-    {
-        int rc2 = uninitInternal();
-        AssertRC(rc2);
-        return rc;
-    }
-
-    return VINF_SUCCESS;
-}
-
-/**
- * Closes a recording stream.
- * Depending on the stream's recording destination, this function closes all associated handles
- * and finalizes recording.
- *
- * @returns IPRT status code.
- */
-int CaptureStream::close(void)
-{
-    int rc = VINF_SUCCESS;
-
-    if (this->fEnabled)
-    {
-        switch (this->ScreenSettings.enmDest)
-        {
-            case RecordDestination_File:
-            {
-                if (this->File.pWEBM)
-                    rc = this->File.pWEBM->Close();
-                break;
-            }
-
-            default:
-                AssertFailed(); /* Should never happen. */
-                break;
-        }
-
-        this->Blocks.Clear();
-
-        LogRel(("VideoRec: Recording screen #%u stopped\n", this->uScreenID));
-    }
-
-    if (RT_FAILURE(rc))
-    {
-        LogRel(("VideoRec: Error stopping recording screen #%u, rc=%Rrc\n", this->uScreenID, rc));
-        return rc;
-    }
-
-    switch (this->ScreenSettings.enmDest)
-    {
-        case RecordDestination_File:
-        {
-            if (RTFileIsValid(this->File.hFile))
-            {
-                rc = RTFileClose(this->File.hFile);
-                if (RT_SUCCESS(rc))
-                {
-                    LogRel(("VideoRec: Closed file '%s'\n", this->ScreenSettings.File.strName.c_str()));
-                }
-                else
-                {
-                    LogRel(("VideoRec: Error closing file '%s', rc=%Rrc\n", this->ScreenSettings.File.strName.c_str(), rc));
-                    break;
-                }
-            }
-
-            if (this->File.pWEBM)
-            {
-                delete this->File.pWEBM;
-                this->File.pWEBM = NULL;
-            }
-            break;
-        }
-
-        default:
-            rc = VERR_NOT_IMPLEMENTED;
-            break;
-    }
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-/**
- * Uninitializes a recording stream.
- *
- * @returns IPRT status code.
- */
-int CaptureStream::Uninit(void)
-{
-    return uninitInternal();
-}
-
-int CaptureStream::uninitInternal(void)
-{
-    if (this->enmState != RECORDINGSTREAMSTATE_INITIALIZED)
-        return VINF_SUCCESS;
-
-    int rc = close();
-    if (RT_FAILURE(rc))
-        return rc;
-
-    if (this->ScreenSettings.isFeatureEnabled(RecordFeature_Video))
-    {
-        int rc2 = unitVideo();
-        if (RT_SUCCESS(rc))
-            rc = rc2;
-    }
-
-    RTCritSectDelete(&this->CritSect);
-
-    this->enmState = RECORDINGSTREAMSTATE_UNINITIALIZED;
-    this->fEnabled = false;
-
-    return rc;
-}
-
-/**
- * Uninitializes video recording for a certain recording stream.
- *
- * @returns IPRT status code.
- */
-int CaptureStream::unitVideo(void)
-{
-#ifdef VBOX_WITH_LIBVPX
-    /* At the moment we only have VPX. */
-    return uninitVideoVPX();
-#else
-    return VERR_NOT_SUPPORTED;
-#endif
-}
-
-#ifdef VBOX_WITH_LIBVPX
-/**
- * Uninitializes the VPX codec for a certain recording stream.
- *
- * @returns IPRT status code.
- */
-int CaptureStream::uninitVideoVPX(void)
-{
-    PVIDEORECVIDEOCODEC pCodec = &this->Video.Codec;
-    vpx_img_free(&pCodec->VPX.RawImage);
-    pCodec->VPX.pu8YuvBuf = NULL; /* Was pointing to VPX.RawImage. */
-
-    vpx_codec_err_t rcv = vpx_codec_destroy(&this->Video.Codec.VPX.Ctx);
-    Assert(rcv == VPX_CODEC_OK); RT_NOREF(rcv);
-
-    return VINF_SUCCESS;
-}
-#endif
-
-/**
- * Initializes the video recording for a certain recording stream.
- *
- * @returns IPRT status code.
- */
-int CaptureStream::initVideo(void)
-{
-    /* Sanity. */
-    AssertReturn(this->ScreenSettings.Video.ulRate,   VERR_INVALID_PARAMETER);
-    AssertReturn(this->ScreenSettings.Video.ulWidth,  VERR_INVALID_PARAMETER);
-    AssertReturn(this->ScreenSettings.Video.ulHeight, VERR_INVALID_PARAMETER);
-    AssertReturn(this->ScreenSettings.Video.ulFPS,    VERR_INVALID_PARAMETER);
-
-    this->Video.cFailedEncodingFrames = 0;
-    this->Video.uDelayMs = RT_MS_1SEC / this->ScreenSettings.Video.ulFPS;
-
-#ifdef VBOX_WITH_LIBVPX
-    /* At the moment we only have VPX. */
-    return initVideoVPX();
-#else
-    return VINF_SUCCESS;
-#endif
-}
-
-#ifdef VBOX_WITH_LIBVPX
-/**
- * Initializes the VPX codec for a certain recording stream.
- *
- * @returns IPRT status code.
- */
-int CaptureStream::initVideoVPX(void)
-{
-# ifdef VBOX_WITH_LIBVPX_VP9
-    vpx_codec_iface_t *pCodecIface = vpx_codec_vp9_cx();
-# else /* Default is using VP8. */
-    vpx_codec_iface_t *pCodecIface = vpx_codec_vp8_cx();
-# endif
-
-    PVIDEORECVIDEOCODEC pCodec = &this->Video.Codec;
-
-    vpx_codec_err_t rcv = vpx_codec_enc_config_default(pCodecIface, &pCodec->VPX.Cfg, 0 /* Reserved */);
-    if (rcv != VPX_CODEC_OK)
-    {
-        LogRel(("VideoRec: Failed to get default config for VPX encoder: %s\n", vpx_codec_err_to_string(rcv)));
-        return VERR_AVREC_CODEC_INIT_FAILED;
-    }
-
-    /* Target bitrate in kilobits per second. */
-    pCodec->VPX.Cfg.rc_target_bitrate = this->ScreenSettings.Video.ulRate;
-    /* Frame width. */
-    pCodec->VPX.Cfg.g_w = this->ScreenSettings.Video.ulWidth;
-    /* Frame height. */
-    pCodec->VPX.Cfg.g_h = this->ScreenSettings.Video.ulHeight;
-    /* 1ms per frame. */
-    pCodec->VPX.Cfg.g_timebase.num = 1;
-    pCodec->VPX.Cfg.g_timebase.den = 1000;
-    /* Disable multithreading. */
-    pCodec->VPX.Cfg.g_threads = 0;
-
-    /* Initialize codec. */
-    rcv = vpx_codec_enc_init(&pCodec->VPX.Ctx, pCodecIface, &pCodec->VPX.Cfg, 0 /* Flags */);
-    if (rcv != VPX_CODEC_OK)
-    {
-        LogRel(("VideoRec: Failed to initialize VPX encoder: %s\n", vpx_codec_err_to_string(rcv)));
-        return VERR_AVREC_CODEC_INIT_FAILED;
-    }
-
-    if (!vpx_img_alloc(&pCodec->VPX.RawImage, VPX_IMG_FMT_I420,
-                       this->ScreenSettings.Video.ulWidth, this->ScreenSettings.Video.ulHeight, 1))
-    {
-        LogRel(("VideoRec: Failed to allocate image %RU32x%RU32\n",
-                this->ScreenSettings.Video.ulWidth, this->ScreenSettings.Video.ulHeight));
-        return VERR_NO_MEMORY;
-    }
-
-    /* Save a pointer to the first raw YUV plane. */
-    pCodec->VPX.pu8YuvBuf = pCodec->VPX.RawImage.planes[0];
-
-    return VINF_SUCCESS;
-}
-#endif
-
-int CaptureStream::initAudio(void)
-{
-#ifdef VBOX_WITH_AUDIO_VIDEOREC
-    if (this->ScreenSettings.isFeatureEnabled(RecordFeature_Audio))
-    {
-        /* Sanity. */
-        AssertReturn(this->ScreenSettings.Audio.uHz,       VERR_INVALID_PARAMETER);
-        AssertReturn(this->ScreenSettings.Audio.cBits,     VERR_INVALID_PARAMETER);
-        AssertReturn(this->ScreenSettings.Audio.cChannels, VERR_INVALID_PARAMETER);
-    }
-#endif
-
-    return VINF_SUCCESS;
-}
-
-#ifdef VBOX_WITH_LIBVPX
-/**
- * Encodes the source image and write the encoded image to the stream's destination.
- *
- * @returns IPRT status code.
- * @param   uTimeStampMs        Absolute timestamp (PTS) of frame (in ms) to encode.
- * @param   pFrame              Frame to encode and submit.
- */
-int CaptureStream::writeVideoVPX(uint64_t uTimeStampMs, PVIDEORECVIDEOFRAME pFrame)
-{
-    AssertPtrReturn(pFrame, VERR_INVALID_POINTER);
-
-    int rc;
-
-    PVIDEORECVIDEOCODEC pCodec = &this->Video.Codec;
-
-    /* Presentation Time Stamp (PTS). */
-    vpx_codec_pts_t pts = uTimeStampMs;
-    vpx_codec_err_t rcv = vpx_codec_encode(&pCodec->VPX.Ctx,
-                                           &pCodec->VPX.RawImage,
-                                           pts                          /* Time stamp */,
-                                           this->Video.uDelayMs         /* How long to show this frame */,
-                                           0                            /* Flags */,
-                                           pCodec->VPX.uEncoderDeadline /* Quality setting */);
-    if (rcv != VPX_CODEC_OK)
-    {
-        if (this->Video.cFailedEncodingFrames++ < 64) /** @todo Make this configurable. */
-        {
-            LogRel(("VideoRec: Failed to encode video frame: %s\n", vpx_codec_err_to_string(rcv)));
-            return VERR_GENERAL_FAILURE;
-        }
-    }
-
-    this->Video.cFailedEncodingFrames = 0;
-
-    vpx_codec_iter_t iter = NULL;
-    rc = VERR_NO_DATA;
-    for (;;)
-    {
-        const vpx_codec_cx_pkt_t *pPacket = vpx_codec_get_cx_data(&pCodec->VPX.Ctx, &iter);
-        if (!pPacket)
-            break;
-
-        switch (pPacket->kind)
-        {
-            case VPX_CODEC_CX_FRAME_PKT:
-            {
-                WebMWriter::BlockData_VP8 blockData = { &pCodec->VPX.Cfg, pPacket };
-                rc = this->File.pWEBM->WriteBlock(this->uTrackVideo, &blockData, sizeof(blockData));
-                break;
-            }
-
-            default:
-                AssertFailed();
-                LogFunc(("Unexpected video packet type %ld\n", pPacket->kind));
-                break;
-        }
-    }
-
-    return rc;
-}
-#endif /* VBOX_WITH_LIBVPX */
-
-/**
- * Locks a recording stream.
- */
-void CaptureStream::lock(void)
-{
-    int rc = RTCritSectEnter(&CritSect);
-    AssertRC(rc);
-}
-
-/**
- * Unlocks a locked recording stream.
- */
-void CaptureStream::unlock(void)
-{
-    int rc = RTCritSectLeave(&CritSect);
-    AssertRC(rc);
-}
-
Index: unk/src/VBox/Main/src-client/VideoRecUtils.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/VideoRecUtils.cpp	(revision 75343)
+++ 	(revision )
@@ -1,176 +1,0 @@
-/* $Id$ */
-/** @file
- * Video recording utility code.
- */
-
-/*
- * Copyright (C) 2012-2018 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.
- */
-
-#include "VideoRec.h"
-#include "VideoRecUtils.h"
-
-#include <iprt/asm.h>
-#include <iprt/assert.h>
-#include <iprt/critsect.h>
-#include <iprt/path.h>
-#include <iprt/semaphore.h>
-#include <iprt/thread.h>
-#include <iprt/time.h>
-
-
-/**
- * Convert an image to YUV420p format.
- *
- * @return true on success, false on failure.
- * @param  aDstBuf              The destination image buffer.
- * @param  aDstWidth            Width (in pixel) of destination buffer.
- * @param  aDstHeight           Height (in pixel) of destination buffer.
- * @param  aSrcBuf              The source image buffer.
- * @param  aSrcWidth            Width (in pixel) of source buffer.
- * @param  aSrcHeight           Height (in pixel) of source buffer.
- */
-template <class T>
-inline bool videoRecColorConvWriteYUV420p(uint8_t *aDstBuf, unsigned aDstWidth, unsigned aDstHeight,
-                                          uint8_t *aSrcBuf, unsigned aSrcWidth, unsigned aSrcHeight)
-{
-    RT_NOREF(aDstWidth, aDstHeight);
-
-    AssertReturn(!(aSrcWidth & 1),  false);
-    AssertReturn(!(aSrcHeight & 1), false);
-
-    bool fRc = true;
-    T iter1(aSrcWidth, aSrcHeight, aSrcBuf);
-    T iter2 = iter1;
-    iter2.skip(aSrcWidth);
-    unsigned cPixels = aSrcWidth * aSrcHeight;
-    unsigned offY = 0;
-    unsigned offU = cPixels;
-    unsigned offV = cPixels + cPixels / 4;
-    unsigned const cyHalf = aSrcHeight / 2;
-    unsigned const cxHalf = aSrcWidth  / 2;
-    for (unsigned i = 0; i < cyHalf && fRc; ++i)
-    {
-        for (unsigned j = 0; j < cxHalf; ++j)
-        {
-            unsigned red, green, blue;
-            fRc = iter1.getRGB(&red, &green, &blue);
-            AssertReturn(fRc, false);
-            aDstBuf[offY] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;
-            unsigned u = (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4;
-            unsigned v = (((112 * red - 94 * green -  18 * blue + 128) >> 8) + 128) / 4;
-
-            fRc = iter1.getRGB(&red, &green, &blue);
-            AssertReturn(fRc, false);
-            aDstBuf[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;
-
-            fRc = iter2.getRGB(&red, &green, &blue);
-            AssertReturn(fRc, false);
-            aDstBuf[offY + aSrcWidth] = ((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;
-
-            fRc = iter2.getRGB(&red, &green, &blue);
-            AssertReturn(fRc, false);
-            aDstBuf[offY + aSrcWidth + 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;
-
-            aDstBuf[offU] = u;
-            aDstBuf[offV] = v;
-            offY += 2;
-            ++offU;
-            ++offV;
-        }
-
-        iter1.skip(aSrcWidth);
-        iter2.skip(aSrcWidth);
-        offY += aSrcWidth;
-    }
-
-    return true;
-}
-
-/**
- * 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 videoRecColorConvWriteRGB24(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;
-}
-
-/**
- * Converts a RGB to YUV buffer.
- *
- * @returns IPRT status code.
- * @param   uPixelFormat        Pixel format to use for conversion.
- * @param   paDst               Pointer to destination buffer.
- * @param   uDstWidth           Width (X, in pixels) of destination buffer.
- * @param   uDstHeight          Height (Y, in pixels) of destination buffer.
- * @param   paSrc               Pointer to source buffer.
- * @param   uSrcWidth           Width (X, in pixels) of source buffer.
- * @param   uSrcHeight          Height (Y, in pixels) of source buffer.
- */
-int videoRecRGBToYUV(uint32_t uPixelFormat,
-                     uint8_t *paDst, uint32_t uDstWidth, uint32_t uDstHeight,
-                     uint8_t *paSrc, uint32_t uSrcWidth, uint32_t uSrcHeight)
-{
-    switch (uPixelFormat)
-    {
-        case VIDEORECPIXELFMT_RGB32:
-            if (!videoRecColorConvWriteYUV420p<ColorConvBGRA32Iter>(paDst, uDstWidth, uDstHeight,
-                                                            paSrc, uSrcWidth, uSrcHeight))
-                return VERR_INVALID_PARAMETER;
-            break;
-        case VIDEORECPIXELFMT_RGB24:
-            if (!videoRecColorConvWriteYUV420p<ColorConvBGR24Iter>(paDst, uDstWidth, uDstHeight,
-                                                           paSrc, uSrcWidth, uSrcHeight))
-                return VERR_INVALID_PARAMETER;
-            break;
-        case VIDEORECPIXELFMT_RGB565:
-            if (!videoRecColorConvWriteYUV420p<ColorConvBGR565Iter>(paDst, uDstWidth, uDstHeight,
-                                                            paSrc, uSrcWidth, uSrcHeight))
-                return VERR_INVALID_PARAMETER;
-            break;
-        default:
-            AssertFailed();
-            return VERR_NOT_SUPPORTED;
-    }
-    return VINF_SUCCESS;
-}
-
