Index: /trunk/src/VBox/Main/src-client/DrvAudioVideoRec.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/DrvAudioVideoRec.cpp	(revision 65211)
+++ /trunk/src/VBox/Main/src-client/DrvAudioVideoRec.cpp	(revision 65212)
@@ -194,5 +194,5 @@
     PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
 
-    pThis->enmMode = AVRECMODE_AUDIO;
+    pThis->enmMode = AVRECMODE_AUDIO; /** @todo Fix mode! */
 
     int rc;
@@ -205,5 +205,7 @@
             {
                 pThis->pEBML = new WebMWriter();
-                pThis->pEBML->create("/tmp/test.webm", WebMWriter::Mode_Audio); /** @todo FIX! */
+                rc = pThis->pEBML->create("/tmp/test.webm", RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE,
+                                          WebMWriter::Mode_Audio, /** @todo Fix path! */
+                                          WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_None);
                 break;
             }
@@ -211,4 +213,5 @@
             case AVRECMODE_AUDIO_VIDEO:
             {
+                rc = VERR_NOT_SUPPORTED;
                 break;
             }
Index: /trunk/src/VBox/Main/src-client/EbmlWriter.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/EbmlWriter.cpp	(revision 65211)
+++ /trunk/src/VBox/Main/src-client/EbmlWriter.cpp	(revision 65212)
@@ -49,7 +49,7 @@
 
     /** Creates EBML output file. */
-    inline int create(const char *a_pszFilename)
-    {
-        return RTFileOpen(&m_File, a_pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
+    inline int create(const char *a_pszFilename, uint64_t fOpen)
+    {
+        return RTFileOpen(&m_File, a_pszFilename, fOpen);
     }
 
@@ -143,4 +143,13 @@
         writeSize(sizeof(double));
         writeUnsignedInteger(*reinterpret_cast<uint64_t*>(&value));
+        return *this;
+    }
+
+    /** Serializes binary data. */
+    inline Ebml &serializeData(EbmlClassId classId, const void *pvData, size_t cbData)
+    {
+        writeClassId(classId);
+        writeSize(cbData);
+        write(pvData, cbData);
         return *this;
     }
@@ -227,48 +236,83 @@
     };
 
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+# pragma pack(push)
+# pragma pack(1)
+    /** Opus codec private data.
+     *  Taken from: https://wiki.xiph.org/MatroskaOpus */
+    struct OpusPrivData
+    {
+        uint8_t  au8Head[8]       = { 0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64 };
+        uint8_t  u8Version        = 1;
+        uint8_t  c8Channels;
+        uint16_t u16PreSkip       = 0;
+        uint32_t u32SampleRate;
+        uint16_t u16Gain          = 0;
+        uint8_t  u8Mapping_family = 0;
+    };
+# pragma pack(pop)
+#endif /* VBOX_WITH_AUDIO_VIDEOREC */
+
     /** Operation mode. */
-    WebMWriter::Mode m_enmMode;
-
-    bool            m_fDebug;
-    int64_t         m_iLastPtsMs;
-    int64_t         m_iInitialPtsMs;
-    vpx_rational_t  m_Framerate;
-
-    uint64_t        m_uPositionReference;
-    uint64_t        m_uSeekInfoPos;
-    uint64_t        m_uSegmentInfoPos;
-    uint64_t        m_uTrackPos;
-    uint64_t        m_uCuePos;
-    uint64_t        m_uClusterPos;
-
-    uint64_t        m_uTrackIdPos;
-
-    uint64_t        m_uStartSegment;
-
-    uint32_t        m_uClusterTimecode;
-    bool            m_bClusterOpen;
-
-    std::list<CueEntry> m_CueList;
-
-    Ebml                m_Ebml;
+    WebMWriter::Mode       m_enmMode;
+    /** Audio codec to use. */
+    WebMWriter::AudioCodec m_enmAudioCodec;
+    /** Video codec to use. */
+    WebMWriter::VideoCodec m_enmVideoCodec;
+
+    bool                   m_fDebug;
+
+    /** Timestamp of initial PTS (Presentation Time Stamp). */
+    int64_t                m_tsInitialPtsMs;
+    /** Timestamp of last written PTS (Presentation Time Stamp). */
+    int64_t                m_tsLastPtsMs;
+
+    vpx_rational_t         m_Framerate;
+
+    /** Start offset (in bytes) of current segment. */
+    uint64_t               m_offSegCurStart;
+
+    /** Start offset (in bytes) of seeking info segment. */
+    uint64_t               m_offSegSeekInfoStart;
+    /** Offset (in bytes) for current seek info element. */
+    uint64_t               m_offSeekInfo;
+
+    /** Start offset (in bytes) of tracks segment. */
+    uint64_t               m_offSegTracksStart;
+
+    /** Absolute position of cue segment. */
+    uint64_t               m_uCuePos;
+    /** List of cue points. Needed for seeking table. */
+    std::list<CueEntry>    m_lstCue;
+
+    uint64_t               m_uTrackIdPos;
+
+    /** Timestamp (in ms) when the current cluster has been opened. */
+    uint32_t               m_tsClusterOpenMs;
+    /** Whether we're currently in an opened cluster segment. */
+    bool                   m_fClusterOpen;
+    /** Absolute position (in bytes) of current cluster within file.
+     *  Needed for seeking info table. */
+    uint64_t               m_offSegClusterStart;
+
+    Ebml                   m_Ebml;
 
 public:
 
     WebMWriter_Impl() :
-        m_enmMode(WebMWriter::Mode_Unknown),
-        m_fDebug(false),
-        m_iLastPtsMs(-1),
-        m_iInitialPtsMs(-1),
-        m_Framerate(),
-        m_uPositionReference(0),
-        m_uSeekInfoPos(0),
-        m_uSegmentInfoPos(0),
-        m_uTrackPos(0),
-        m_uCuePos(0),
-        m_uClusterPos(0),
-        m_uTrackIdPos(0),
-        m_uStartSegment(0),
-        m_uClusterTimecode(0),
-        m_bClusterOpen(false) {}
+          m_enmMode(WebMWriter::Mode_Unknown)
+        , m_fDebug(false)
+        , m_tsInitialPtsMs(-1)
+        , m_tsLastPtsMs(-1)
+        , m_Framerate()
+        , m_offSegCurStart(0)
+        , m_offSegSeekInfoStart(0)
+        , m_offSeekInfo(0)
+        , m_offSegTracksStart(0)
+        , m_uCuePos(0)
+        , m_uTrackIdPos(0)
+        , m_tsClusterOpenMs(0)
+        , m_fClusterOpen(false)
+        , m_offSegClusterStart(0) {}
 
     void writeHeader(const vpx_codec_enc_cfg_t *a_pCfg, const struct vpx_rational *a_pFps)
@@ -286,10 +330,13 @@
         m_Ebml.subStart(Segment);
 
-        m_uPositionReference = RTFileTell(m_Ebml.getFile());
         m_Framerate = *a_pFps;
 
+        /* Save offset of current segment. */
+        m_offSegCurStart = RTFileTell(m_Ebml.getFile());
+
         writeSeekInfo();
 
-        m_uTrackPos = RTFileTell(m_Ebml.getFile());
+        /* Save offset of upcoming tracks segment. */
+        m_offSegTracksStart = RTFileTell(m_Ebml.getFile());
 
         m_Ebml.subStart(Tracks);
@@ -329,7 +376,10 @@
             /** @todo Implement track's "Language" property? Currently this defaults to English ("eng"). */
 
+            OpusPrivData opusPrivData;
+
             m_Ebml.serializeUnsignedInteger(TrackUID, 1 /* UID */, 4)
                   .serializeUnsignedInteger(TrackType, 2 /* Audio */)
                   .serializeString(CodecID, "A_OPUS")
+                  .serializeData(CodecPrivate, &opusPrivData, sizeof(opusPrivData))
                   .subStart(Audio)
                   .serializeFloat(SamplingFrequency, 44100.0)
@@ -347,43 +397,46 @@
     void writeBlock(const vpx_codec_enc_cfg_t *a_pCfg, const vpx_codec_cx_pkt_t *a_pPkt)
     {
+        /* Calculate the PTS of this frame in milliseconds. */
+        int64_t iPtsMs = a_pPkt->data.frame.pts * 1000
+                       * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den;
+
+        if (iPtsMs <= m_tsLastPtsMs)
+            iPtsMs = m_tsLastPtsMs + 1;
+
+        m_tsLastPtsMs = iPtsMs;
+
+        if (m_tsInitialPtsMs < 0)
+          m_tsInitialPtsMs = m_tsLastPtsMs;
+
+        /* Calculate the relative time of this block. */
         uint16_t uBlockTimecode = 0;
-        int64_t  iPtsMs;
-        bool     bStartCluster = false;
-
-        /* Calculate the PTS of this frame in milliseconds. */
-        iPtsMs = a_pPkt->data.frame.pts * 1000
-                 * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den;
-        if (iPtsMs <= m_iLastPtsMs)
-            iPtsMs = m_iLastPtsMs + 1;
-        m_iLastPtsMs = iPtsMs;
-
-        if (m_iInitialPtsMs < 0)
-          m_iInitialPtsMs = m_iLastPtsMs;
-
-        /* Calculate the relative time of this block. */
-        if (iPtsMs - m_uClusterTimecode > 65536)
-            bStartCluster = 1;
+        bool     fClusterStart  = false;
+
+        if (iPtsMs - m_tsClusterOpenMs > 65536)
+            fClusterStart = true;
         else
-            uBlockTimecode = static_cast<uint16_t>(iPtsMs - m_uClusterTimecode);
-
-        int fKeyframe = (a_pPkt->data.frame.flags & VPX_FRAME_IS_KEY);
-        if (bStartCluster || fKeyframe)
+            uBlockTimecode = static_cast<uint16_t>(iPtsMs - m_tsClusterOpenMs);
+
+        bool fKeyframe = RT_BOOL(a_pPkt->data.frame.flags & VPX_FRAME_IS_KEY);
+
+        if (   fClusterStart
+            || fKeyframe)
         {
-            if (m_bClusterOpen)
+            if (m_fClusterOpen)
                 m_Ebml.subEnd(Cluster);
 
             /* Open a new cluster. */
             uBlockTimecode = 0;
-            m_bClusterOpen = true;
-            m_uClusterTimecode = (uint32_t)iPtsMs;
-            m_uClusterPos = RTFileTell(m_Ebml.getFile());
+            m_fClusterOpen = true;
+            m_tsClusterOpenMs = (uint32_t)iPtsMs;
+            m_offSegClusterStart = RTFileTell(m_Ebml.getFile());
             m_Ebml.subStart(Cluster)
-                  .serializeUnsignedInteger(Timecode, m_uClusterTimecode);
+                  .serializeUnsignedInteger(Timecode, m_tsClusterOpenMs);
 
             /* Save a cue point if this is a keyframe. */
             if (fKeyframe)
             {
-                CueEntry cue(m_uClusterTimecode, m_uClusterPos);
-                m_CueList.push_back(cue);
+                CueEntry cue(m_tsClusterOpenMs, m_offSegClusterStart);
+                m_lstCue.push_back(cue);
             }
         }
@@ -400,10 +453,10 @@
     void writeFooter(uint32_t a_u64Hash)
     {
-        if (m_bClusterOpen)
+        if (m_fClusterOpen)
             m_Ebml.subEnd(Cluster);
 
         m_uCuePos = RTFileTell(m_Ebml.getFile());
         m_Ebml.subStart(Cues);
-        for (std::list<CueEntry>::iterator it = m_CueList.begin(); it != m_CueList.end(); ++it)
+        for (std::list<CueEntry>::iterator it = m_lstCue.begin(); it != m_lstCue.end(); ++it)
         {
           m_Ebml.subStart(CuePoint)
@@ -411,5 +464,5 @@
                 .subStart(CueTrackPositions)
                 .serializeUnsignedInteger(CueTrack, 1)
-                .serializeUnsignedInteger(CueClusterPosition, it->loc - m_uPositionReference, 8)
+                .serializeUnsignedInteger(CueClusterPosition, it->loc - m_offSegCurStart, 8)
                 .subEnd(CueTrackPositions)
                 .subEnd(CuePoint);
@@ -434,11 +487,11 @@
 private:
 
-    void writeSeekInfo()
+    void writeSeekInfo(void)
     {
         uint64_t uPos = RTFileTell(m_Ebml.getFile());
-        if (m_uSeekInfoPos)
-            RTFileSeek(m_Ebml.getFile(), m_uSeekInfoPos, RTFILE_SEEK_BEGIN, NULL);
+        if (m_offSegSeekInfoStart)
+            RTFileSeek(m_Ebml.getFile(), m_offSegSeekInfoStart, RTFILE_SEEK_BEGIN, NULL);
         else
-            m_uSeekInfoPos = uPos;
+            m_offSegSeekInfoStart = uPos;
 
         m_Ebml.subStart(SeekHead)
@@ -446,21 +499,21 @@
               .subStart(Seek)
               .serializeUnsignedInteger(SeekID, Tracks)
-              .serializeUnsignedInteger(SeekPosition, m_uTrackPos - m_uPositionReference, 8)
+              .serializeUnsignedInteger(SeekPosition, m_offSegTracksStart - m_offSegCurStart, 8)
               .subEnd(Seek)
 
               .subStart(Seek)
               .serializeUnsignedInteger(SeekID, Cues)
-              .serializeUnsignedInteger(SeekPosition, m_uCuePos - m_uPositionReference, 8)
+              .serializeUnsignedInteger(SeekPosition, m_uCuePos - m_offSegCurStart, 8)
               .subEnd(Seek)
 
               .subStart(Seek)
               .serializeUnsignedInteger(SeekID, Info)
-              .serializeUnsignedInteger(SeekPosition, m_uSegmentInfoPos - m_uPositionReference, 8)
+              .serializeUnsignedInteger(SeekPosition, m_offSeekInfo - m_offSegCurStart, 8)
               .subEnd(Seek)
 
-              .subEnd(SeekHead);
+        .subEnd(SeekHead);
 
         int64_t iFrameTime = (int64_t)1000 * m_Framerate.den / m_Framerate.num;
-        m_uSegmentInfoPos = RTFileTell(m_Ebml.getFile());
+        m_offSeekInfo = RTFileTell(m_Ebml.getFile());
 
         char szVersion[64];
@@ -470,5 +523,5 @@
         m_Ebml.subStart(Info)
               .serializeUnsignedInteger(TimecodeScale, 1000000)
-              .serializeFloat(Segment_Duration, m_iLastPtsMs + iFrameTime - m_iInitialPtsMs)
+              .serializeFloat(Segment_Duration, m_tsLastPtsMs + iFrameTime - m_tsInitialPtsMs)
               .serializeString(MuxingApp, szVersion)
               .serializeString(WritingApp, szVersion)
@@ -477,21 +530,25 @@
 };
 
-WebMWriter::WebMWriter() : m_Impl(new WebMWriter_Impl()) {}
-
-WebMWriter::~WebMWriter()
-{
-    delete m_Impl;
-}
-
-int WebMWriter::create(const char *a_pszFilename, WebMWriter::Mode a_enmMode)
-{
-    m_Impl->m_enmMode = a_enmMode;
-
-    return m_Impl->m_Ebml.create(a_pszFilename);
-}
-
-void WebMWriter::close()
-{
-    m_Impl->m_Ebml.close();
+WebMWriter::WebMWriter(void) : m_pImpl(new WebMWriter_Impl()) {}
+
+WebMWriter::~WebMWriter(void)
+{
+    if (m_pImpl)
+        delete m_pImpl;
+}
+
+int WebMWriter::create(const char *a_pszFilename, uint64_t a_fOpen, WebMWriter::Mode a_enmMode,
+                       WebMWriter::AudioCodec a_enmAudioCodec, WebMWriter::VideoCodec a_enmVideoCodec)
+{
+    m_pImpl->m_enmMode       = a_enmMode;
+    m_pImpl->m_enmAudioCodec = a_enmAudioCodec;
+    m_pImpl->m_enmVideoCodec = a_enmVideoCodec;
+
+    return m_pImpl->m_Ebml.create(a_pszFilename, a_fOpen);
+}
+
+void WebMWriter::close(void)
+{
+    m_pImpl->m_Ebml.close();
 }
 
@@ -500,5 +557,5 @@
     try
     {
-        m_Impl->writeHeader(a_pCfg, a_pFps);
+        m_pImpl->writeHeader(a_pCfg, a_pFps);
     }
     catch(int rc)
@@ -513,5 +570,5 @@
     try
     {
-        m_Impl->writeBlock(a_pCfg, a_pPkt);
+        m_pImpl->writeBlock(a_pCfg, a_pPkt);
     }
     catch(int rc)
@@ -526,5 +583,5 @@
     try
     {
-        m_Impl->writeFooter(a_u64Hash);
+        m_pImpl->writeFooter(a_u64Hash);
     }
     catch(int rc)
@@ -537,10 +594,10 @@
 uint64_t WebMWriter::getFileSize()
 {
-    return m_Impl->m_Ebml.getFileSize();
+    return m_pImpl->m_Ebml.getFileSize();
 }
 
 uint64_t WebMWriter::getAvailableSpace()
 {
-    return m_Impl->m_Ebml.getAvailableSpace();
-}
-
+    return m_pImpl->m_Ebml.getAvailableSpace();
+}
+
Index: /trunk/src/VBox/Main/src-client/EbmlWriter.h
===================================================================
--- /trunk/src/VBox/Main/src-client/EbmlWriter.h	(revision 65211)
+++ /trunk/src/VBox/Main/src-client/EbmlWriter.h	(revision 65212)
@@ -28,4 +28,6 @@
 #endif
 
+#include <iprt/file.h>
+
 class WebMWriter_Impl;
 
@@ -34,4 +36,32 @@
 
 public:
+
+    /**
+     * Supported audio codecs.
+     */
+    enum AudioCodec
+    {
+        /** No audio codec specified. */
+        AudioCodec_Unknown = 0,
+        /** Opus. */
+        AudioCodec_Opus    = 1
+    };
+
+    /**
+     * Supported video codecs.
+     */
+    enum VideoCodec
+    {
+        /** No video codec specified. */
+        VideoCodec_None = 0,
+        /** VP8. */
+        VideoCodec_VP8  = 1
+    };
+
+    struct BlockData
+    {
+        void  *pvData;
+        size_t cbData;
+    };
 
     /**
@@ -44,5 +74,5 @@
         /** Only writes audio. */
         Mode_Audio       = 1,
-        /** Only Writes video. */
+        /** Only writes video. */
         Mode_Video       = 2,
         /** Writes audio and video. */
@@ -59,10 +89,14 @@
      *
      * @param   a_pszFilename   Name of the file to create.
+     * @param   a_fOpen         File open mode of type RTFILE_O_.
      * @param   a_enmMode       Operation mode.
+     * @param   a_enmAudioCodec Audio codec to use.
+     * @param   a_enmVideoCodec Video codec to use.
      *
      * @returns VBox status code. */
-    int create(const char *a_pszFilename, WebMWriter::Mode a_enmMode);
+    int create(const char *a_pszFilename, uint64_t a_fOpen, WebMWriter::Mode a_enmMode,
+               WebMWriter::AudioCodec a_enmAudioCodec, WebMWriter::VideoCodec a_enmVideoCodec);
 
-    /* Closes output file. */
+    /** Closes output file. */
     void close();
 
@@ -116,5 +150,5 @@
     /** WebMWriter implementation.
      *  To isolate some include files. */
-    WebMWriter_Impl *m_Impl;
+    WebMWriter_Impl *m_pImpl;
 
     DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(WebMWriter);
Index: /trunk/src/VBox/Main/src-client/VideoRec.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/VideoRec.cpp	(revision 65211)
+++ /trunk/src/VBox/Main/src-client/VideoRec.cpp	(revision 65212)
@@ -647,5 +647,13 @@
      * other important file, causing unintentional data loss. */
 
-    int rc = pStream->pEBML->create(pszFile, WebMWriter::Mode_AudioVideo); /** @todo Make mode configurable. */
+    /** @todo Make mode configurable. */
+#ifdef VBOX_WITH_AUDIO_VIDEOREC
+    WebMWriter::Mode enmMode = WebMWriter::Mode_AudioVideo;
+#else
+    WebMWriter::Mode enmMode = WebMWriter::Mode_Video;
+#endif
+
+    int rc = pStream->pEBML->create(pszFile, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE, enmMode,
+                                    WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_VP8);
     if (RT_FAILURE(rc))
     {
