VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/EBMLWriter.cpp@ 73768

Last change on this file since 73768 was 69683, checked in by vboxsync, 7 years ago

VideoRec/Main: Factored out the WebMWriter class from the EBMLWriter one and got rid of the extra Impl class and instead derive WebMWriter from EBMLWriter. Saves quite a bit of code and should make the stuff a lot easier to read and maintain. No functional code changes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
  • Property svn:mergeinfo set to (toggle deleted branches)
    /branches/VBox-3.0/src/VBox/Frontends/VBoxHeadless/VideoCapture/EbmlWriter.cpp58652,​70973
    /branches/VBox-3.2/src/VBox/Frontends/VBoxHeadless/VideoCapture/EbmlWriter.cpp66309,​66318
    /branches/VBox-4.0/src/VBox/Frontends/VBoxHeadless/VideoCapture/EbmlWriter.cpp70873
    /branches/VBox-4.1/src/VBox/Frontends/VBoxHeadless/VideoCapture/EbmlWriter.cpp74233
    /branches/VBox-4.2/src/VBox/Main/src-client/EbmlWriter.cpp91503-91504,​91506-91508,​91510,​91514-91515,​91521
    /branches/VBox-4.3/src/VBox/Main/src-client/EbmlWriter.cpp91223
    /branches/VBox-4.3/trunk/src/VBox/Main/src-client/EbmlWriter.cpp91223
    /branches/dsen/gui/src/VBox/Frontends/VBoxHeadless/VideoCapture/EbmlWriter.cpp79076-79078,​79089,​79109-79110,​79112-79113,​79127-79130,​79134,​79141,​79151,​79155,​79157-79159,​79193,​79197
    /branches/dsen/gui2/src/VBox/Frontends/VBoxHeadless/VideoCapture/EbmlWriter.cpp79224,​79228,​79233,​79235,​79258,​79262-79263,​79273,​79341,​79345,​79354,​79357,​79387-79388,​79559-79569,​79572-79573,​79578,​79581-79582,​79590-79591,​79598-79599,​79602-79603,​79605-79606,​79632,​79635,​79637,​79644
    /branches/dsen/gui3/src/VBox/Frontends/VBoxHeadless/VideoCapture/EbmlWriter.cpp79645-79692
File size: 8.3 KB
RevLine 
[45913]1/* $Id: EBMLWriter.cpp 69683 2017-11-14 11:09:16Z vboxsync $ */
2/** @file
[69683]3 * EBMLWriter.cpp - EBML writer implementation.
[45913]4 */
5
6/*
[65197]7 * Copyright (C) 2013-2017 Oracle Corporation
[45913]8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
[68451]18/**
19 * For more information, see:
20 * - https://w3c.github.io/media-source/webm-byte-stream-format.html
21 * - https://www.webmproject.org/docs/container/#muxer-guidelines
22 */
23
[69683]24#ifdef LOG_GROUP
25# undef LOG_GROUP
26#endif
[67914]27#define LOG_GROUP LOG_GROUP_MAIN_DISPLAY
28#include "LoggingNew.h"
[45913]29
[52791]30#include <list>
[65330]31#include <map>
[69189]32#include <queue>
[52791]33#include <stack>
[65389]34
35#include <math.h> /* For lround.h. */
36
[52791]37#include <iprt/asm.h>
[65307]38#include <iprt/buildconfig.h>
[52791]39#include <iprt/cdefs.h>
[69189]40#include <iprt/critsect.h>
[52791]41#include <iprt/err.h>
[65256]42#include <iprt/file.h>
43#include <iprt/rand.h>
44#include <iprt/string.h>
45
[52791]46#include <VBox/log.h>
[65307]47#include <VBox/version.h>
[65256]48
[69194]49#include "EBMLWriter.h"
[69195]50#include "EBML_MKV.h"
[45913]51
[68796]52/** No flags set. */
53#define VBOX_EBMLWRITER_FLAG_NONE 0
54/** The file handle was inherited. */
55#define VBOX_EBMLWRITER_FLAG_HANDLE_INHERITED RT_BIT(0)
[52316]56
[69683]57/** Creates an EBML output file using an existing, open file handle. */
58int EBMLWriter::createEx(const char *a_pszFile, PRTFILE phFile)
[52325]59{
[69683]60 AssertPtrReturn(phFile, VERR_INVALID_POINTER);
[52325]61
[69683]62 m_hFile = *phFile;
63 m_fFlags |= VBOX_EBMLWRITER_FLAG_HANDLE_INHERITED;
64 m_strFile = a_pszFile;
[45922]65
[69683]66 return VINF_SUCCESS;
67}
[52791]68
[69683]69/** Creates an EBML output file using a file name. */
70int EBMLWriter::create(const char *a_pszFile, uint64_t fOpen)
71{
72 int rc = RTFileOpen(&m_hFile, a_pszFile, fOpen);
73 if (RT_SUCCESS(rc))
[68796]74 m_strFile = a_pszFile;
75
[69683]76 return rc;
77}
[68796]78
[69683]79/** Returns available space on storage. */
80uint64_t EBMLWriter::getAvailableSpace(void)
81{
82 RTFOFF pcbFree;
83 int rc = RTFileQueryFsSizes(m_hFile, NULL, &pcbFree, 0, 0);
84 return (RT_SUCCESS(rc)? (uint64_t)pcbFree : UINT64_MAX);
85}
[68332]86
[69683]87/** Closes the file. */
88void EBMLWriter::close(void)
89{
90 if (!isOpen())
91 return;
[45913]92
[69683]93 AssertMsg(m_Elements.size() == 0,
94 ("%zu elements are not closed yet (next element to close is 0x%x)\n",
95 m_Elements.size(), m_Elements.top().classId));
[68332]96
[69683]97 if (!(m_fFlags & VBOX_EBMLWRITER_FLAG_HANDLE_INHERITED))
[52791]98 {
[69683]99 RTFileClose(m_hFile);
100 m_hFile = NIL_RTFILE;
[52791]101 }
[45922]102
[69683]103 m_fFlags = VBOX_EBMLWRITER_FLAG_NONE;
104 m_strFile = "";
105}
[45913]106
[69683]107/** Starts an EBML sub-element. */
108EBMLWriter& EBMLWriter::subStart(EbmlClassId classId)
109{
110 writeClassId(classId);
111 /* store the current file offset. */
112 m_Elements.push(EbmlSubElement(RTFileTell(m_hFile), classId));
113 /* Indicates that size of the element
114 * is unkown (as according to EBML specs).
[65256]115 */
[69683]116 writeUnsignedInteger(UINT64_C(0x01FFFFFFFFFFFFFF));
117 return *this;
118}
[65256]119
[69683]120/** Ends an EBML sub-element. */
121EBMLWriter& EBMLWriter::subEnd(EbmlClassId classId)
122{
[65261]123#ifdef VBOX_STRICT
[69683]124 /* Class ID on the top of the stack should match the class ID passed
125 * to the function. Otherwise it may mean that we have a bug in the code.
[52791]126 */
[69683]127 AssertMsg(!m_Elements.empty(), ("No elements to close anymore\n"));
128 AssertMsg(m_Elements.top().classId == classId,
129 ("Ending sub element 0x%x is in wrong order (next to close is 0x%x)\n", classId, m_Elements.top().classId));
[65259]130#else
[69683]131 RT_NOREF(classId);
[65259]132#endif
[65256]133
[69683]134 uint64_t uPos = RTFileTell(m_hFile);
135 uint64_t uSize = uPos - m_Elements.top().offset - 8;
136 RTFileSeek(m_hFile, m_Elements.top().offset, RTFILE_SEEK_BEGIN, NULL);
[68451]137
[69683]138 /* Make sure that size will be serialized as uint64_t. */
139 writeUnsignedInteger(uSize | UINT64_C(0x0100000000000000));
140 RTFileSeek(m_hFile, uPos, RTFILE_SEEK_BEGIN, NULL);
141 m_Elements.pop();
142 return *this;
143}
[68451]144
[69683]145/** Serializes a null-terminated string. */
146EBMLWriter& EBMLWriter::serializeString(EbmlClassId classId, const char *str)
[52791]147{
[69683]148 writeClassId(classId);
149 uint64_t size = strlen(str);
150 writeSize(size);
151 write(str, size);
152 return *this;
[52791]153}
154
[69683]155/** Serializes an UNSIGNED integer.
156 * If size is zero then it will be detected automatically. */
157EBMLWriter& EBMLWriter::serializeUnsignedInteger(EbmlClassId classId, uint64_t parm, size_t size /* = 0 */)
[68796]158{
[69683]159 writeClassId(classId);
160 if (!size) size = getSizeOfUInt(parm);
161 writeSize(size);
162 writeUnsignedInteger(parm, size);
163 return *this;
[68796]164}
165
[69683]166/** Serializes a floating point value.
167 *
168 * Only 8-bytes double precision values are supported
169 * by this function.
170 */
171EBMLWriter& EBMLWriter::serializeFloat(EbmlClassId classId, float value)
[52791]172{
[69683]173 writeClassId(classId);
174 Assert(sizeof(uint32_t) == sizeof(float));
175 writeSize(sizeof(float));
176
177 union
[65256]178 {
[69683]179 float f;
180 uint8_t u8[4];
181 } u;
[65197]182
[69683]183 u.f = value;
[52791]184
[69683]185 for (int i = 3; i >= 0; i--) /* Converts values to big endian. */
186 write(&u.u8[i], 1);
[52791]187
[69683]188 return *this;
[52791]189}
190
[69683]191/** Serializes binary data. */
192EBMLWriter& EBMLWriter::serializeData(EbmlClassId classId, const void *pvData, size_t cbData)
[52791]193{
[69683]194 writeClassId(classId);
195 writeSize(cbData);
196 write(pvData, cbData);
197 return *this;
[65256]198}
199
[69683]200/** Writes raw data to file. */
201int EBMLWriter::write(const void *data, size_t size)
[65256]202{
[69683]203 return RTFileWrite(m_hFile, data, size, NULL);
[65256]204}
205
[69683]206/** Writes an unsigned integer of variable of fixed size. */
207void EBMLWriter::writeUnsignedInteger(uint64_t value, size_t size /* = sizeof(uint64_t) */)
[65256]208{
[69683]209 /* convert to big-endian */
210 value = RT_H2BE_U64(value);
211 write(reinterpret_cast<uint8_t*>(&value) + sizeof(value) - size, size);
[52791]212}
213
[69683]214/** Writes EBML class ID to file.
215 *
216 * EBML ID already has a UTF8-like represenation
217 * so getSizeOfUInt is used to determine
218 * the number of its bytes.
219 */
220void EBMLWriter::writeClassId(EbmlClassId parm)
[68332]221{
[69683]222 writeUnsignedInteger(parm, getSizeOfUInt(parm));
[68332]223}
224
[69683]225/** Writes data size value. */
226void EBMLWriter::writeSize(uint64_t parm)
[52791]227{
[69683]228 /* The following expression defines the size of the value that will be serialized
229 * as an EBML UTF-8 like integer (with trailing bits represeting its size):
230 1xxx xxxx - value 0 to 2^7-2
231 01xx xxxx xxxx xxxx - value 0 to 2^14-2
232 001x xxxx xxxx xxxx xxxx xxxx - value 0 to 2^21-2
233 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^28-2
234 0000 1xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^35-2
235 0000 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^42-2
236 0000 001x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^49-2
237 0000 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^56-2
238 */
239 size_t size = 8 - ! (parm & (UINT64_MAX << 49)) - ! (parm & (UINT64_MAX << 42)) -
240 ! (parm & (UINT64_MAX << 35)) - ! (parm & (UINT64_MAX << 28)) -
241 ! (parm & (UINT64_MAX << 21)) - ! (parm & (UINT64_MAX << 14)) -
242 ! (parm & (UINT64_MAX << 7));
243 /* One is subtracted in order to avoid loosing significant bit when size = 8. */
244 uint64_t mask = RT_BIT_64(size * 8 - 1);
245 writeUnsignedInteger((parm & (((mask << 1) - 1) >> size)) | (mask >> (size - 1)), size);
[52791]246}
247
[69683]248/** Size calculation for variable size UNSIGNED integer.
249 *
250 * The function defines the size of the number by trimming
251 * consequent trailing zero bytes starting from the most significant.
252 * The following statement is always true:
253 * 1 <= getSizeOfUInt(arg) <= 8.
254 *
255 * Every !(arg & (UINT64_MAX << X)) expression gives one
256 * if an only if all the bits from X to 63 are set to zero.
257 */
258size_t EBMLWriter::getSizeOfUInt(uint64_t arg)
[52791]259{
[69683]260 return 8 - ! (arg & (UINT64_MAX << 56)) - ! (arg & (UINT64_MAX << 48)) -
261 ! (arg & (UINT64_MAX << 40)) - ! (arg & (UINT64_MAX << 32)) -
262 ! (arg & (UINT64_MAX << 24)) - ! (arg & (UINT64_MAX << 16)) -
263 ! (arg & (UINT64_MAX << 8));
[52791]264}
[63160]265
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use