Index: /trunk/src/VBox/Main/src-client/EbmlWriter.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/EbmlWriter.cpp	(revision 45913)
+++ /trunk/src/VBox/Main/src-client/EbmlWriter.cpp	(revision 45913)
@@ -0,0 +1,503 @@
+/* $Id$ */
+/** @file
+ * EbmlWriter.cpp - EBML writer + WebM container
+ */
+
+/*
+ * Copyright (C) 2013 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 is based on:
+ *
+ * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS.  All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "EbmlWriter.h"
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <VBox/log.h>
+
+
+int Ebml_Write(EbmlGlobal *glob, const void *buffer_in, uint64_t len)
+{
+    return RTFileWrite(glob->file, buffer_in, len, NULL);
+}
+
+int Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, uint64_t len)
+{
+    const unsigned char *q = (const unsigned char *)buffer_in + len - 1;
+
+    for (; len; len--)
+    {
+        int rc = Ebml_Write(glob, q--, 1);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+    return VINF_SUCCESS;
+}
+
+int Ebml_SerializeUnsigned32(EbmlGlobal *glob, uint32_t class_id, uint64_t ui)
+{
+    unsigned char sizeSerialized = 4 | 0x80;
+    int rc = Ebml_WriteID(glob, class_id);
+    rc = Ebml_Serialize(glob, &sizeSerialized, 1);
+    if (RT_SUCCESS(rc))
+        rc = Ebml_Serialize(glob, &ui, 4);
+    return rc;
+}
+
+int Ebml_StartSubElement(EbmlGlobal *glob, uint64_t *ebmlLoc, uint32_t class_id)
+{
+    // todo this is always taking 8 bytes, this may need later optimization
+    // this is a key that says lenght unknown
+    uint64_t unknownLen =  UINT64_C(0x01FFFFFFFFFFFFFF);
+
+    Ebml_WriteID(glob, class_id);
+    *ebmlLoc = RTFileTell(glob->file);
+    return Ebml_Serialize(glob, &unknownLen, 8);
+}
+
+int Ebml_EndSubElement(EbmlGlobal *glob, uint64_t *ebmlLoc)
+{
+    /* Save the current file pointer */
+    uint64_t pos = RTFileTell(glob->file);
+
+    /* Calculate the size of this element */
+    uint64_t size  = pos - *ebmlLoc - 8;
+    size |= UINT64_C(0x0100000000000000);
+
+    /* Seek back to the beginning of the element and write the new size */
+    RTFileSeek(glob->file, *ebmlLoc, RTFILE_SEEK_BEGIN, NULL);
+    int rc = Ebml_Serialize(glob, &size, 8);
+
+    /* Reset the file pointer */
+    RTFileSeek(glob->file, pos, RTFILE_SEEK_BEGIN, NULL);
+
+    return rc;
+}
+
+int Ebml_WriteLen(EbmlGlobal *glob, uint64_t val)
+{
+    //TODO check and make sure we are not > than 0x0100000000000000LLU
+    unsigned char size = 8; //size in bytes to output
+    uint64_t minVal = UINT64_C(0x00000000000000ff); //mask to compare for byte size
+
+    for (size = 1; size < 8; size ++)
+    {
+        if (val < minVal)
+            break;
+
+        minVal = (minVal << 7);
+    }
+
+    val |= (UINT64_C(0x000000000000080) << ((size - 1) * 7));
+
+    return Ebml_Serialize(glob, (void *) &val, size);
+}
+
+int Ebml_WriteString(EbmlGlobal *glob, const char *str)
+{
+    const size_t size_ = strlen(str);
+    const uint64_t size = size_;
+    int rc = Ebml_WriteLen(glob, size);
+    //TODO: it's not clear from the spec whether the nul terminator
+    //should be serialized too.  For now we omit the null terminator.
+    if (RT_SUCCESS(rc))
+        rc = Ebml_Write(glob, str, size);
+    return rc;
+}
+
+int Ebml_WriteID(EbmlGlobal *glob, uint32_t class_id)
+{
+    int rc;
+    if (class_id >= 0x01000000)
+        rc = Ebml_Serialize(glob, (void *)&class_id, 4);
+    else if (class_id >= 0x00010000)
+        rc = Ebml_Serialize(glob, (void *)&class_id, 3);
+    else if (class_id >= 0x00000100)
+        rc = Ebml_Serialize(glob, (void *)&class_id, 2);
+    else
+        rc = Ebml_Serialize(glob, (void *)&class_id, 1);
+    return rc;
+}
+int Ebml_SerializeUnsigned64(EbmlGlobal *glob, uint32_t class_id, uint64_t ui)
+{
+    unsigned char sizeSerialized = 8 | 0x80;
+    int rc = Ebml_WriteID(glob, class_id);
+    if (RT_SUCCESS(rc))
+        rc = Ebml_Serialize(glob, &sizeSerialized, 1);
+    if (RT_SUCCESS(rc))
+        rc = Ebml_Serialize(glob, &ui, 8);
+    return rc;
+}
+
+int Ebml_SerializeUnsigned(EbmlGlobal *glob, uint32_t class_id, uint32_t ui)
+{
+    unsigned char size = 8; //size in bytes to output
+    unsigned char sizeSerialized = 0;
+    uint32_t minVal;
+
+    int rc = Ebml_WriteID(glob, class_id);
+    if (RT_FAILURE(rc))
+        return rc;
+    minVal = 0x7fLU; //mask to compare for byte size
+
+    for (size = 1; size < 4; size ++)
+    {
+        if (ui < minVal)
+            break;
+
+        minVal <<= 7;
+    }
+
+    sizeSerialized = 0x80 | size;
+    rc = Ebml_Serialize(glob, &sizeSerialized, 1);
+    if (RT_SUCCESS(rc))
+        rc = Ebml_Serialize(glob, &ui, size);
+    return rc;
+}
+
+//TODO: perhaps this is a poor name for this id serializer helper function
+int Ebml_SerializeBinary(EbmlGlobal *glob, uint32_t class_id, uint32_t bin)
+{
+    int size;
+    for (size = 4; size > 1; size--)
+    {
+        if (bin & 0x000000ff << ((size-1) * 8))
+            break;
+    }
+    int rc = Ebml_WriteID(glob, class_id);
+    if (RT_SUCCESS(rc))
+        rc = Ebml_WriteLen(glob, size);
+    if (RT_SUCCESS(rc))
+        rc = Ebml_WriteID(glob, bin);
+    return rc;
+}
+
+int Ebml_SerializeFloat(EbmlGlobal *glob, uint32_t class_id, double d)
+{
+    unsigned char len = 0x88;
+
+    int rc = Ebml_WriteID(glob, class_id);
+    if (RT_SUCCESS(rc))
+        rc = Ebml_Serialize(glob, &len, 1);
+    if (RT_SUCCESS(rc))
+        rc = Ebml_Serialize(glob,  &d, 8);
+    return rc;
+}
+
+int Ebml_SerializeString(EbmlGlobal *glob, uint32_t class_id, const char *s)
+{
+    int rc = Ebml_WriteID(glob, class_id);
+    if (RT_SUCCESS(rc))
+        rc = Ebml_WriteString(glob, s);
+    return rc;
+}
+
+int Ebml_WriteWebMSeekElement(EbmlGlobal *ebml, uint32_t id, uint64_t pos)
+{
+    uint64_t offset = pos - ebml->position_reference;
+    uint64_t start;
+    int rc = Ebml_StartSubElement(ebml, &start, Seek);
+    if (RT_SUCCESS(rc))
+        rc = Ebml_SerializeBinary(ebml, SeekID, id);
+    if (RT_SUCCESS(rc))
+        rc = Ebml_SerializeUnsigned64(ebml, SeekPosition, offset);
+    if (RT_SUCCESS(rc))
+        rc = Ebml_EndSubElement(ebml, &start);
+    return rc;
+}
+
+int Ebml_WriteWebMSeekInfo(EbmlGlobal *ebml)
+{
+    uint64_t pos;
+    int rc = VINF_SUCCESS;
+
+    /* Save the current file pointer */
+    pos = RTFileTell(ebml->file);
+
+    if (ebml->seek_info_pos)
+        rc = RTFileSeek(ebml->file, ebml->seek_info_pos, RTFILE_SEEK_BEGIN, NULL);
+    else
+        ebml->seek_info_pos = pos;
+
+    {
+        uint64_t start;
+
+        if (RT_SUCCESS(rc))
+            rc = Ebml_StartSubElement(ebml, &start, SeekHead);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_WriteWebMSeekElement(ebml, Tracks, ebml->track_pos);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_WriteWebMSeekElement(ebml, Cues,   ebml->cue_pos);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_WriteWebMSeekElement(ebml, Info,   ebml->segment_info_pos);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_EndSubElement(ebml, &start);
+    }
+    {
+        //segment info
+        uint64_t startInfo;
+        uint64_t frame_time;
+
+        frame_time = (uint64_t)1000 * ebml->framerate.den
+                     / ebml->framerate.num;
+        ebml->segment_info_pos = RTFileTell(ebml->file);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_StartSubElement(ebml, &startInfo, Info);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_SerializeFloat(ebml, Segment_Duration,
+                                     (double)(ebml->last_pts_ms + frame_time));
+        char szVersion[64];
+        RTStrPrintf(szVersion, sizeof(szVersion), "vpxenc%",
+                    ebml->debug ? vpx_codec_version_str() : "");
+        if (RT_SUCCESS(rc))
+            rc = Ebml_SerializeString(ebml, 0x4D80, szVersion);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_SerializeString(ebml, 0x5741, szVersion);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_EndSubElement(ebml, &startInfo);
+    }
+    return rc;
+}
+
+int Ebml_WriteWebMFileHeader(EbmlGlobal                *glob,
+                             const vpx_codec_enc_cfg_t *cfg,
+                             const struct vpx_rational *fps)
+{
+    int rc = VINF_SUCCESS;
+    {
+        uint64_t start;
+        rc = Ebml_StartSubElement(glob, &start, EBML);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_SerializeUnsigned(glob, EBMLVersion, 1);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); //EBML Read Version
+        if (RT_SUCCESS(rc))
+            rc = Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); //EBML Max ID Length
+        if (RT_SUCCESS(rc))
+            rc = Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); //EBML Max Size Length
+        if (RT_SUCCESS(rc))
+            rc = Ebml_SerializeString(glob, DocType, "webm"); //Doc Type
+        if (RT_SUCCESS(rc))
+            rc = Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); //Doc Type Version
+        if (RT_SUCCESS(rc))
+            rc = Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); //Doc Type Read Version
+        if (RT_SUCCESS(rc))
+            rc = Ebml_EndSubElement(glob, &start);
+    }
+    {
+        if (RT_SUCCESS(rc))
+            rc = Ebml_StartSubElement(glob, &glob->startSegment, Segment); //segment
+        glob->position_reference = RTFileTell(glob->file);
+        glob->framerate = *fps;
+        if (RT_SUCCESS(rc))
+            rc = Ebml_WriteWebMSeekInfo(glob);
+        {
+            uint64_t trackStart;
+            glob->track_pos = RTFileTell(glob->file);
+            if (RT_SUCCESS(rc))
+                rc = Ebml_StartSubElement(glob, &trackStart, Tracks);
+            {
+                unsigned int trackNumber = 1;
+                uint64_t     trackID = 0;
+
+                uint64_t start;
+                if (RT_SUCCESS(rc))
+                    rc = Ebml_StartSubElement(glob, &start, TrackEntry);
+                if (RT_SUCCESS(rc))
+                    rc = Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
+                glob->track_id_pos = RTFileTell(glob->file);
+                Ebml_SerializeUnsigned32(glob, TrackUID, trackID);
+                Ebml_SerializeUnsigned(glob, TrackType, 1); //video is always 1
+                Ebml_SerializeString(glob, CodecID, "V_VP8");
+                {
+                    unsigned int pixelWidth = cfg->g_w;
+                    unsigned int pixelHeight = cfg->g_h;
+                    double       frameRate   = (double)fps->num/(double)fps->den;
+
+                    uint64_t videoStart;
+                    if (RT_SUCCESS(rc))
+                        rc = Ebml_StartSubElement(glob, &videoStart, Video);
+                    if (RT_SUCCESS(rc))
+                        rc = Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
+                    if (RT_SUCCESS(rc))
+                        rc = Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
+                    if (RT_SUCCESS(rc))
+                        rc = Ebml_SerializeFloat(glob, FrameRate, frameRate);
+                    if (RT_SUCCESS(rc))
+                        rc = Ebml_EndSubElement(glob, &videoStart); //Video
+                }
+                if (RT_SUCCESS(rc))
+                    rc = Ebml_EndSubElement(glob, &start); //Track Entry
+            }
+            if (RT_SUCCESS(rc))
+                rc = Ebml_EndSubElement(glob, &trackStart);
+        }
+        // segment element is open
+    }
+    return rc;
+}
+
+int Ebml_WriteWebMBlock(EbmlGlobal                *glob,
+                        const vpx_codec_enc_cfg_t *cfg,
+                        const vpx_codec_cx_pkt_t  *pkt)
+{
+    uint64_t       block_length;
+    unsigned char  track_number;
+    unsigned short block_timecode = 0;
+    unsigned char  flags;
+    int64_t        pts_ms;
+    int            start_cluster = 0, is_keyframe;
+    int            rc = VINF_SUCCESS;
+
+    /* Calculate the PTS of this frame in milliseconds */
+    pts_ms = pkt->data.frame.pts * 1000
+             * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den;
+    if (pts_ms <= glob->last_pts_ms)
+        pts_ms = glob->last_pts_ms + 1;
+    glob->last_pts_ms = pts_ms;
+
+    /* Calculate the relative time of this block */
+    if (pts_ms - glob->cluster_timecode > 65536)
+        start_cluster = 1;
+    else
+        block_timecode = (unsigned short)(pts_ms - glob->cluster_timecode);
+
+    is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY);
+    if (start_cluster || is_keyframe)
+    {
+        if (glob->cluster_open)
+            rc = Ebml_EndSubElement(glob, &glob->startCluster);
+
+        /* Open the new cluster */
+        block_timecode = 0;
+        glob->cluster_open = 1;
+        glob->cluster_timecode = pts_ms;
+        glob->cluster_pos = RTFileTell(glob->file);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_StartSubElement(glob, &glob->startCluster, Cluster); //cluster
+        if (RT_SUCCESS(rc))
+            rc = Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode);
+
+        /* Save a cue point if this is a keyframe. */
+        if (is_keyframe)
+        {
+            struct cue_entry *cue;
+
+            glob->cue_list = (cue_entry*)RTMemRealloc(glob->cue_list, (glob->cues+1) * sizeof(cue_entry));
+            cue = &glob->cue_list[glob->cues];
+            cue->time = glob->cluster_timecode;
+            cue->loc = glob->cluster_pos;
+            glob->cues++;
+        }
+    }
+
+    /* Write the Simple Block */
+    if (RT_SUCCESS(rc))
+        rc = Ebml_WriteID(glob, SimpleBlock);
+
+    block_length = pkt->data.frame.sz + 4;
+    block_length |= 0x10000000;
+    if (RT_SUCCESS(rc))
+        rc = Ebml_Serialize(glob, &block_length, 4);
+
+    track_number = 1;
+    track_number |= 0x80;
+    if (RT_SUCCESS(rc))
+        rc = Ebml_Write(glob, &track_number, 1);
+
+    if (RT_SUCCESS(rc))
+        rc = Ebml_Serialize(glob, &block_timecode, 2);
+
+    flags = 0;
+    if (is_keyframe)
+        flags |= 0x80;
+    if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE)
+        flags |= 0x08;
+    if (RT_SUCCESS(rc))
+        rc = Ebml_Write(glob, &flags, 1);
+
+    if (RT_SUCCESS(rc))
+        rc = Ebml_Write(glob, pkt->data.frame.buf, pkt->data.frame.sz);
+
+    return rc;
+}
+
+
+int Ebml_WriteWebMFileFooter(EbmlGlobal *glob, long hash)
+{
+    int rc = VINF_SUCCESS;
+    if (glob->cluster_open)
+        rc = Ebml_EndSubElement(glob, &glob->startCluster);
+
+    {
+        uint64_t start;
+        unsigned int i;
+
+        glob->cue_pos = RTFileTell(glob->file);
+        if (RT_SUCCESS(rc))
+            rc = Ebml_StartSubElement(glob, &start, Cues);
+        for (i=0; i<glob->cues; i++)
+        {
+            struct cue_entry *cue = &glob->cue_list[i];
+            uint64_t startSub;
+
+            if (RT_SUCCESS(rc))
+                rc = Ebml_StartSubElement(glob, &startSub, CuePoint);
+            {
+                uint64_t startSubsub;
+
+                if (RT_SUCCESS(rc))
+                    rc = Ebml_SerializeUnsigned(glob, CueTime, cue->time);
+                if (RT_SUCCESS(rc))
+                    rc = Ebml_StartSubElement(glob, &startSubsub, CueTrackPositions);
+                if (RT_SUCCESS(rc))
+                    rc = Ebml_SerializeUnsigned(glob, CueTrack, 1);
+                if (RT_SUCCESS(rc))
+                    rc = Ebml_SerializeUnsigned64(glob, CueClusterPosition,
+                                                  cue->loc - glob->position_reference);
+                //Ebml_SerializeUnsigned(glob, CueBlockNumber, cue->blockNumber);
+                if (RT_SUCCESS(rc))
+                    rc = Ebml_EndSubElement(glob, &startSubsub);
+            }
+            if (RT_SUCCESS(rc))
+                rc = Ebml_EndSubElement(glob, &startSub);
+        }
+        if (RT_SUCCESS(rc))
+            rc = Ebml_EndSubElement(glob, &start);
+    }
+
+    if (RT_SUCCESS(rc))
+        rc = Ebml_EndSubElement(glob, &glob->startSegment);
+
+    /* Patch up the seek info block */
+    if (RT_SUCCESS(rc))
+        rc = Ebml_WriteWebMSeekInfo(glob);
+
+    /* Patch up the track id */
+    if (RT_SUCCESS(rc))
+        rc = RTFileSeek(glob->file, glob->track_id_pos, RTFILE_SEEK_BEGIN, NULL);
+    if (RT_SUCCESS(rc))
+        rc  = Ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash);
+
+    if (RT_SUCCESS(rc))
+        rc = RTFileSeek(glob->file, 0, RTFILE_SEEK_END, NULL);
+    return rc;
+}
Index: /trunk/src/VBox/Main/src-client/EbmlWriter.h
===================================================================
--- /trunk/src/VBox/Main/src-client/EbmlWriter.h	(revision 45913)
+++ /trunk/src/VBox/Main/src-client/EbmlWriter.h	(revision 45913)
@@ -0,0 +1,307 @@
+/* $Id$ */
+/** @file
+ * EbmlWriter.h - EBML writer + WebM container.
+ */
+
+/*
+ * Copyright (C) 2013 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 is based on:
+ *
+ * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS.  All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef ____EBMLWRITER
+#define ____EBMLWRITER
+
+#include <iprt/file.h>
+#include <vpx/vpx_encoder.h>
+
+enum mkv
+{
+    EBML = 0x1A45DFA3,
+    EBMLVersion = 0x4286,
+    EBMLReadVersion = 0x42F7,
+    EBMLMaxIDLength = 0x42F2,
+    EBMLMaxSizeLength = 0x42F3,
+    DocType = 0x4282,
+    DocTypeVersion = 0x4287,
+    DocTypeReadVersion = 0x4285,
+//  CRC_32 = 0xBF,
+    Void = 0xEC,
+    SignatureSlot = 0x1B538667,
+    SignatureAlgo = 0x7E8A,
+    SignatureHash = 0x7E9A,
+    SignaturePublicKey = 0x7EA5,
+    Signature = 0x7EB5,
+    SignatureElements = 0x7E5B,
+    SignatureElementList = 0x7E7B,
+    SignedElement = 0x6532,
+    //segment
+    Segment = 0x18538067,
+    //Meta Seek Information
+    SeekHead = 0x114D9B74,
+    Seek = 0x4DBB,
+    SeekID = 0x53AB,
+    SeekPosition = 0x53AC,
+    //Segment Information
+    Info = 0x1549A966,
+//  SegmentUID = 0x73A4,
+//  SegmentFilename = 0x7384,
+//  PrevUID = 0x3CB923,
+//  PrevFilename = 0x3C83AB,
+//  NextUID = 0x3EB923,
+//  NextFilename = 0x3E83BB,
+//  SegmentFamily = 0x4444,
+//  ChapterTranslate = 0x6924,
+//  ChapterTranslateEditionUID = 0x69FC,
+//  ChapterTranslateCodec = 0x69BF,
+//  ChapterTranslateID = 0x69A5,
+    TimecodeScale = 0x2AD7B1,
+    Segment_Duration = 0x4489,
+    DateUTC = 0x4461,
+//  Title = 0x7BA9,
+    MuxingApp = 0x4D80,
+    WritingApp = 0x5741,
+    //Cluster
+    Cluster = 0x1F43B675,
+    Timecode = 0xE7,
+//  SilentTracks = 0x5854,
+//  SilentTrackNumber = 0x58D7,
+//  Position = 0xA7,
+    PrevSize = 0xAB,
+    BlockGroup = 0xA0,
+    Block = 0xA1,
+//  BlockVirtual = 0xA2,
+//  BlockAdditions = 0x75A1,
+//  BlockMore = 0xA6,
+//  BlockAddID = 0xEE,
+//  BlockAdditional = 0xA5,
+    BlockDuration = 0x9B,
+//  ReferencePriority = 0xFA,
+    ReferenceBlock = 0xFB,
+//  ReferenceVirtual = 0xFD,
+//  CodecState = 0xA4,
+//  Slices = 0x8E,
+//  TimeSlice = 0xE8,
+    LaceNumber = 0xCC,
+//  FrameNumber = 0xCD,
+//  BlockAdditionID = 0xCB,
+//  MkvDelay = 0xCE,
+//  Cluster_Duration = 0xCF,
+    SimpleBlock = 0xA3,
+//  EncryptedBlock = 0xAF,
+    //Track
+    Tracks = 0x1654AE6B,
+    TrackEntry = 0xAE,
+    TrackNumber = 0xD7,
+    TrackUID = 0x73C5,
+    TrackType = 0x83,
+    FlagEnabled = 0xB9,
+    FlagDefault = 0x88,
+    FlagForced = 0x55AA,
+    FlagLacing = 0x9C,
+//  MinCache = 0x6DE7,
+//  MaxCache = 0x6DF8,
+    DefaultDuration = 0x23E383,
+//  TrackTimecodeScale = 0x23314F,
+//  TrackOffset = 0x537F,
+//  MaxBlockAdditionID = 0x55EE,
+    Name = 0x536E,
+    Language = 0x22B59C,
+    CodecID = 0x86,
+    CodecPrivate = 0x63A2,
+    CodecName = 0x258688,
+//  AttachmentLink = 0x7446,
+//  CodecSettings = 0x3A9697,
+//  CodecInfoURL = 0x3B4040,
+//  CodecDownloadURL = 0x26B240,
+//  CodecDecodeAll = 0xAA,
+//  TrackOverlay = 0x6FAB,
+//  TrackTranslate = 0x6624,
+//  TrackTranslateEditionUID = 0x66FC,
+//  TrackTranslateCodec = 0x66BF,
+//  TrackTranslateTrackID = 0x66A5,
+    //video
+    Video = 0xE0,
+    FlagInterlaced = 0x9A,
+//  StereoMode = 0x53B8,
+    PixelWidth = 0xB0,
+    PixelHeight = 0xBA,
+    PixelCropBottom = 0x54AA,
+    PixelCropTop = 0x54BB,
+    PixelCropLeft = 0x54CC,
+    PixelCropRight = 0x54DD,
+    DisplayWidth = 0x54B0,
+    DisplayHeight = 0x54BA,
+    DisplayUnit = 0x54B2,
+    AspectRatioType = 0x54B3,
+//  ColourSpace = 0x2EB524,
+//  GammaValue = 0x2FB523,
+    FrameRate = 0x2383E3,
+    //end video
+    //audio
+    Audio = 0xE1,
+    SamplingFrequency = 0xB5,
+    OutputSamplingFrequency = 0x78B5,
+    Channels = 0x9F,
+//  ChannelPositions = 0x7D7B,
+    BitDepth = 0x6264,
+    //end audio
+    //content encoding
+//  ContentEncodings = 0x6d80,
+//  ContentEncoding = 0x6240,
+//  ContentEncodingOrder = 0x5031,
+//  ContentEncodingScope = 0x5032,
+//  ContentEncodingType = 0x5033,
+//  ContentCompression = 0x5034,
+//  ContentCompAlgo = 0x4254,
+//  ContentCompSettings = 0x4255,
+//  ContentEncryption = 0x5035,
+//  ContentEncAlgo = 0x47e1,
+//  ContentEncKeyID = 0x47e2,
+//  ContentSignature = 0x47e3,
+//  ContentSigKeyID = 0x47e4,
+//  ContentSigAlgo = 0x47e5,
+//  ContentSigHashAlgo = 0x47e6,
+    //end content encoding
+    //Cueing Data
+    Cues = 0x1C53BB6B,
+    CuePoint = 0xBB,
+    CueTime = 0xB3,
+    CueTrackPositions = 0xB7,
+    CueTrack = 0xF7,
+    CueClusterPosition = 0xF1,
+    CueBlockNumber = 0x5378
+//  CueCodecState = 0xEA,
+//  CueReference = 0xDB,
+//  CueRefTime = 0x96,
+//  CueRefCluster = 0x97,
+//  CueRefNumber = 0x535F,
+//  CueRefCodecState = 0xEB,
+    //Attachment
+//  Attachments = 0x1941A469,
+//  AttachedFile = 0x61A7,
+//  FileDescription = 0x467E,
+//  FileName = 0x466E,
+//  FileMimeType = 0x4660,
+//  FileData = 0x465C,
+//  FileUID = 0x46AE,
+//  FileReferral = 0x4675,
+    //Chapters
+//  Chapters = 0x1043A770,
+//  EditionEntry = 0x45B9,
+//  EditionUID = 0x45BC,
+//  EditionFlagHidden = 0x45BD,
+//  EditionFlagDefault = 0x45DB,
+//  EditionFlagOrdered = 0x45DD,
+//  ChapterAtom = 0xB6,
+//  ChapterUID = 0x73C4,
+//  ChapterTimeStart = 0x91,
+//  ChapterTimeEnd = 0x92,
+//  ChapterFlagHidden = 0x98,
+//  ChapterFlagEnabled = 0x4598,
+//  ChapterSegmentUID = 0x6E67,
+//  ChapterSegmentEditionUID = 0x6EBC,
+//  ChapterPhysicalEquiv = 0x63C3,
+//  ChapterTrack = 0x8F,
+//  ChapterTrackNumber = 0x89,
+//  ChapterDisplay = 0x80,
+//  ChapString = 0x85,
+//  ChapLanguage = 0x437C,
+//  ChapCountry = 0x437E,
+//  ChapProcess = 0x6944,
+//  ChapProcessCodecID = 0x6955,
+//  ChapProcessPrivate = 0x450D,
+//  ChapProcessCommand = 0x6911,
+//  ChapProcessTime = 0x6922,
+//  ChapProcessData = 0x6933,
+    //Tagging
+//  Tags = 0x1254C367,
+//  Tag = 0x7373,
+//  Targets = 0x63C0,
+//  TargetTypeValue = 0x68CA,
+//  TargetType = 0x63CA,
+//  Tagging_TrackUID = 0x63C5,
+//  Tagging_EditionUID = 0x63C9,
+//  Tagging_ChapterUID = 0x63C4,
+//  AttachmentUID = 0x63C6,
+//  SimpleTag = 0x67C8,
+//  TagName = 0x45A3,
+//  TagLanguage = 0x447A,
+//  TagDefault = 0x4484,
+//  TagString = 0x4487,
+//  TagBinary = 0x4485,
+};
+
+struct cue_entry
+{
+    uint64_t    time;
+    uint64_t    loc;
+};
+
+struct EbmlGlobal
+{
+    int        debug;
+    RTFILE     file;
+    int64_t    last_pts_ms;
+    vpx_rational_t framerate;
+
+    uint64_t    position_reference;
+    uint64_t    seek_info_pos;
+    uint64_t    segment_info_pos;
+    uint64_t    track_pos;
+    uint64_t    cue_pos;
+    uint64_t    cluster_pos;
+
+    uint64_t    track_id_pos;
+
+    uint64_t    startSegment;
+    uint64_t    startCluster;
+
+    uint64_t    cluster_timecode;
+    int         cluster_open;
+
+    struct cue_entry *cue_list;
+    unsigned int cues;
+};
+
+int Ebml_Serialize(EbmlGlobal *glob, const void *, uint64_t);
+int Ebml_SerializeUnsigned32(EbmlGlobal *glob, uint32_t class_id, uint64_t ui);
+int Ebml_Write(EbmlGlobal *glob, const void *, uint64_t);
+int Ebml_StartSubElement(EbmlGlobal *glob, uint64_t *ebmlLoc, uint32_t class_id);
+int Ebml_EndSubElement(EbmlGlobal *glob, uint64_t *ebmlLoc);
+
+int Ebml_WriteLen(EbmlGlobal *glob, uint64_t val);
+int Ebml_WriteString(EbmlGlobal *glob, const char *str);
+int Ebml_WriteID(EbmlGlobal *glob, uint32_t class_id);
+int Ebml_SerializeUnsigned64(EbmlGlobal *glob, uint32_t class_id, uint64_t ui);
+int Ebml_SerializeUnsigned(EbmlGlobal *glob, uint32_t class_id, uint32_t ui);
+int Ebml_SerializeBinary(EbmlGlobal *glob, uint32_t class_id, uint32_t ui);
+int Ebml_SerializeFloat(EbmlGlobal *glob, uint32_t class_id, double d);
+
+int Ebml_SerializeString(EbmlGlobal *glob, uint32_t class_id, const char *s);
+
+int Ebml_WriteWebMSeekElement(EbmlGlobal *ebml, uint32_t id, uint64_t pos);
+int Ebml_WriteWebMSeekInfo(EbmlGlobal *ebml);
+int Ebml_WriteWebMFileHeader(EbmlGlobal *glob, const vpx_codec_enc_cfg_t *cfg, const struct vpx_rational *fps);
+int Ebml_WriteWebMBlock(EbmlGlobal *glob, const vpx_codec_enc_cfg_t *cfg, const vpx_codec_cx_pkt_t *pkt);
+int Ebml_WriteWebMFileFooter(EbmlGlobal *glob, long hash);
+
+#endif
