VirtualBox

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

Last change on this file since 93931 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • 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
Line 
1/* $Id: EBMLWriter.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * EBMLWriter.cpp - EBML writer implementation.
4 */
5
6/*
7 * Copyright (C) 2013-2022 Oracle Corporation
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
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
24#ifdef LOG_GROUP
25# undef LOG_GROUP
26#endif
27#define LOG_GROUP LOG_GROUP_MAIN_DISPLAY
28#include "LoggingNew.h"
29
30#include <list>
31#include <map>
32#include <queue>
33#include <stack>
34
35#include <math.h> /* For lround.h. */
36
37#include <iprt/asm.h>
38#include <iprt/buildconfig.h>
39#include <iprt/cdefs.h>
40#include <iprt/critsect.h>
41#include <iprt/errcore.h>
42#include <iprt/file.h>
43#include <iprt/rand.h>
44#include <iprt/string.h>
45
46#include <VBox/log.h>
47#include <VBox/version.h>
48
49#include "EBMLWriter.h"
50#include "EBML_MKV.h"
51
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)
56
57/** Creates an EBML output file using an existing, open file handle. */
58int EBMLWriter::createEx(const char *a_pszFile, PRTFILE phFile)
59{
60 AssertPtrReturn(phFile, VERR_INVALID_POINTER);
61
62 m_hFile = *phFile;
63 m_fFlags |= VBOX_EBMLWRITER_FLAG_HANDLE_INHERITED;
64 m_strFile = a_pszFile;
65
66 return VINF_SUCCESS;
67}
68
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))
74 m_strFile = a_pszFile;
75
76 return rc;
77}
78
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}
86
87/** Closes the file. */
88void EBMLWriter::close(void)
89{
90 if (!isOpen())
91 return;
92
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));
96
97 if (!(m_fFlags & VBOX_EBMLWRITER_FLAG_HANDLE_INHERITED))
98 {
99 RTFileClose(m_hFile);
100 m_hFile = NIL_RTFILE;
101 }
102
103 m_fFlags = VBOX_EBMLWRITER_FLAG_NONE;
104 m_strFile = "";
105}
106
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).
115 */
116 writeUnsignedInteger(UINT64_C(0x01FFFFFFFFFFFFFF));
117 return *this;
118}
119
120/** Ends an EBML sub-element. */
121EBMLWriter& EBMLWriter::subEnd(EbmlClassId classId)
122{
123#ifdef VBOX_STRICT
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.
126 */
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));
130#else
131 RT_NOREF(classId);
132#endif
133
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);
137
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}
144
145/** Serializes a null-terminated string. */
146EBMLWriter& EBMLWriter::serializeString(EbmlClassId classId, const char *str)
147{
148 writeClassId(classId);
149 uint64_t size = strlen(str);
150 writeSize(size);
151 write(str, size);
152 return *this;
153}
154
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 */)
158{
159 writeClassId(classId);
160 if (!size) size = getSizeOfUInt(parm);
161 writeSize(size);
162 writeUnsignedInteger(parm, size);
163 return *this;
164}
165
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)
172{
173 writeClassId(classId);
174 Assert(sizeof(uint32_t) == sizeof(float));
175 writeSize(sizeof(float));
176
177 union
178 {
179 float f;
180 uint8_t u8[4];
181 } u;
182
183 u.f = value;
184
185 for (int i = 3; i >= 0; i--) /* Converts values to big endian. */
186 write(&u.u8[i], 1);
187
188 return *this;
189}
190
191/** Serializes binary data. */
192EBMLWriter& EBMLWriter::serializeData(EbmlClassId classId, const void *pvData, size_t cbData)
193{
194 writeClassId(classId);
195 writeSize(cbData);
196 write(pvData, cbData);
197 return *this;
198}
199
200/** Writes raw data to file. */
201int EBMLWriter::write(const void *data, size_t size)
202{
203 return RTFileWrite(m_hFile, data, size, NULL);
204}
205
206/** Writes an unsigned integer of variable of fixed size. */
207void EBMLWriter::writeUnsignedInteger(uint64_t value, size_t size /* = sizeof(uint64_t) */)
208{
209 /* convert to big-endian */
210 value = RT_H2BE_U64(value);
211 write(reinterpret_cast<uint8_t*>(&value) + sizeof(value) - size, size);
212}
213
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)
221{
222 writeUnsignedInteger(parm, getSizeOfUInt(parm));
223}
224
225/** Writes data size value. */
226void EBMLWriter::writeSize(uint64_t parm)
227{
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);
246}
247
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)
259{
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));
264}
265
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette