VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/EbmlWriter.cpp@ 52325

Last change on this file since 52325 was 52325, checked in by vboxsync, 11 years ago

6219: Available storage free space check has been added. The capture will stop once free space has become less than 1 MB

  • 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.9 KB
Line 
1/* $Id: EbmlWriter.cpp 52325 2014-08-08 12:56:29Z vboxsync $ */
2/** @file
3 * EbmlWriter.cpp - EBML writer + WebM container
4 */
5
6/*
7 * Copyright (C) 2013 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 * This code is based on:
20 *
21 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
22 * Use of this source code is governed by a BSD-style license
23 * that can be found in the LICENSE file in the root of the source
24 * tree. An additional intellectual property rights grant can be found
25 * in the file PATENTS. All contributing project authors may
26 * be found in the AUTHORS file in the root of the source tree.
27 */
28
29#include "EbmlWriter.h"
30#include <iprt/asm.h>
31#include <iprt/mem.h>
32#include <iprt/string.h>
33#include <VBox/log.h>
34
35Ebml::Ebml() {}
36
37void Ebml::init(const RTFILE &a_File)
38{
39 m_File = a_File;
40}
41
42void Ebml::write(const void *data, size_t size)
43{
44 int rc = RTFileWrite(m_File, data, size, NULL);
45 if (!RT_SUCCESS(rc)) throw rc;
46}
47
48uint64_t WebMWriter::getFileSize()
49{
50 return RTFileTell(m_File);
51}
52
53uint64_t WebMWriter::getAvailableSpace()
54{
55 RTFOFF pcbFree;
56 int rc = RTFileQueryFsSizes(m_File, NULL, &pcbFree, 0, 0);
57 return (RT_SUCCESS(rc)? (uint64_t)pcbFree : UINT64_MAX);
58}
59
60WebMWriter::WebMWriter() :
61 m_bDebug(false),
62 m_iLastPtsMs(-1),
63 m_Framerate(),
64 m_uPositionReference(0),
65 m_uSeekInfoPos(0),
66 m_uSegmentInfoPos(0),
67 m_uTrackPos(0),
68 m_uCuePos(0),
69 m_uClusterPos(0),
70 m_uTrackIdPos(0),
71 m_uStartSegment(0),
72 m_uClusterTimecode(0),
73 m_bClusterOpen(false) {}
74
75int WebMWriter::create(const char *a_pszFilename)
76{
77 int rc = RTFileOpen(&m_File, a_pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
78 if (RT_SUCCESS(rc))
79 {
80 m_Ebml.init(m_File);
81 }
82 return rc;
83}
84
85void WebMWriter::close()
86{
87 RTFileClose(m_File);
88}
89
90Ebml &operator<<(Ebml &a_Ebml, const WebMWriter::SimpleBlockData &a_Data)
91{
92 a_Ebml.serializeConst<WebMWriter::SimpleBlock>();
93 a_Ebml.write<uint32_t>(0x10000000u | (Ebml::getSizeOfUInt(a_Data.trackNumber) + 2 + 1 + a_Data.dataSize));
94 a_Ebml.serializeInteger(a_Data.trackNumber);
95 a_Ebml.write(a_Data.timeCode);
96 a_Ebml.write(a_Data.flags);
97 a_Ebml.write(a_Data.data, a_Data.dataSize);
98 return a_Ebml;
99}
100
101void WebMWriter::writeSeekInfo()
102{
103 // Save the current file pointer
104 uint64_t uPos = RTFileTell(m_File);
105 if (m_uSeekInfoPos)
106 RTFileSeek(m_File, m_uSeekInfoPos, RTFILE_SEEK_BEGIN, NULL);
107 else
108 m_uSeekInfoPos = uPos;
109
110 m_Ebml << Ebml::SubStart<SeekHead>()
111
112 << Ebml::SubStart<Seek>()
113 << Ebml::Const<SeekID, Tracks>()
114 << Ebml::Var<SeekPosition, uint64_t>(m_uTrackPos - m_uPositionReference)
115 << Ebml::SubEnd<Seek>()
116
117 << Ebml::SubStart<Seek>()
118 << Ebml::Const<SeekID, Cues>()
119 << Ebml::Var<SeekPosition, uint64_t>(m_uCuePos - m_uPositionReference)
120 << Ebml::SubEnd<Seek>()
121
122 << Ebml::SubStart<Seek>()
123 << Ebml::Const<SeekID, Info>()
124 << Ebml::Var<SeekPosition, uint64_t>(m_uSegmentInfoPos - m_uPositionReference)
125 << Ebml::SubEnd<Seek>()
126
127 << Ebml::SubEnd<SeekHead>();
128
129 int64_t iFrameTime = (int64_t)1000 * m_Framerate.den / m_Framerate.num;
130 m_uSegmentInfoPos = RTFileTell(m_File);
131
132 char szVersion[64];
133 RTStrPrintf(szVersion, sizeof(szVersion), "vpxenc%",
134 m_bDebug ? vpx_codec_version_str() : "");
135
136 m_Ebml << Ebml::SubStart<Info>()
137 << Ebml::UnsignedInteger<TimecodeScale>(1000000)
138 << Ebml::Float<Segment_Duration>(m_iLastPtsMs + iFrameTime)
139 << Ebml::String<MuxingApp>(szVersion)
140 << Ebml::String<WritingApp>(szVersion)
141 << Ebml::SubEnd<Info>();
142}
143
144int WebMWriter::writeHeader(const vpx_codec_enc_cfg_t *a_pCfg,
145 const struct vpx_rational *a_pFps)
146{
147 try
148 {
149 m_Ebml << Ebml::SubStart<EBML>()
150 << Ebml::UnsignedInteger<EBMLVersion>(1)
151 << Ebml::UnsignedInteger<EBMLReadVersion>(1)
152 << Ebml::UnsignedInteger<EBMLMaxIDLength>(4)
153 << Ebml::UnsignedInteger<EBMLMaxSizeLength>(8)
154 << Ebml::String<DocType>("webm")
155 << Ebml::UnsignedInteger<DocTypeVersion>(2)
156 << Ebml::UnsignedInteger<DocTypeReadVersion>(2)
157 << Ebml::SubEnd<EBML>();
158
159 m_Ebml << Ebml::SubStart<Segment>();
160
161 m_uPositionReference = RTFileTell(m_File);
162 m_Framerate = *a_pFps;
163
164 writeSeekInfo();
165
166 m_uTrackPos = RTFileTell(m_File);
167
168 m_Ebml << Ebml::SubStart<Tracks>()
169 << Ebml::SubStart<TrackEntry>()
170 << Ebml::UnsignedInteger<TrackNumber>(1);
171
172 m_uTrackIdPos = RTFileTell(m_File);
173
174 m_Ebml << Ebml::Var<TrackUID, uint32_t>(0)
175 << Ebml::UnsignedInteger<TrackType>(1)
176 << Ebml::String<CodecID>("V_VP8")
177 << Ebml::SubStart<Video>()
178 << Ebml::UnsignedInteger<PixelWidth>(a_pCfg->g_w)
179 << Ebml::UnsignedInteger<PixelHeight>(a_pCfg->g_h)
180 << Ebml::Float<FrameRate>((double)a_pFps->num / a_pFps->den)
181 << Ebml::SubEnd<Video>()
182 << Ebml::SubEnd<TrackEntry>()
183 << Ebml::SubEnd<Tracks>();
184 }
185 catch(int rc)
186 {
187 LogFlow(("WebMWriter::writeHeader catched"));
188 return rc;
189 }
190 return VINF_SUCCESS;
191}
192
193int WebMWriter::writeBlock(const vpx_codec_enc_cfg_t *a_pCfg,
194 const vpx_codec_cx_pkt_t *a_pPkt)
195{
196 try {
197 uint16_t uBlockTimecode = 0;
198 int64_t iPtsMs;
199 bool bStartCluster = false;
200
201 /* Calculate the PTS of this frame in milliseconds */
202 iPtsMs = a_pPkt->data.frame.pts * 1000
203 * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den;
204 if (iPtsMs <= m_iLastPtsMs)
205 iPtsMs = m_iLastPtsMs + 1;
206 m_iLastPtsMs = iPtsMs;
207
208 /* Calculate the relative time of this block */
209 if (iPtsMs - m_uClusterTimecode > 65536)
210 bStartCluster = 1;
211 else
212 uBlockTimecode = static_cast<uint16_t>(iPtsMs - m_uClusterTimecode);
213
214 int fKeyframe = (a_pPkt->data.frame.flags & VPX_FRAME_IS_KEY);
215 if (bStartCluster || fKeyframe)
216 {
217 if (m_bClusterOpen)
218 m_Ebml << Ebml::SubEnd<Cluster>();
219
220 /* Open a new cluster */
221 uBlockTimecode = 0;
222 m_bClusterOpen = true;
223 m_uClusterTimecode = (uint32_t)iPtsMs;
224 m_uClusterPos = RTFileTell(m_File);
225 m_Ebml << Ebml::SubStart<Cluster>()
226 << Ebml::UnsignedInteger<Timecode>(m_uClusterTimecode);
227
228 /* Save a cue point if this is a keyframe. */
229 if (fKeyframe)
230 {
231 CueEntry cue(m_uClusterTimecode, m_uClusterPos);
232 m_CueList.push_back(cue);
233 }
234 }
235
236 // Write a Simple Block
237 SimpleBlockData block(1, uBlockTimecode,
238 (fKeyframe ? 0x80 : 0) | (a_pPkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE ? 0x08 : 0),
239 a_pPkt->data.frame.buf, a_pPkt->data.frame.sz);
240
241 m_Ebml << block;
242 }
243 catch(int rc)
244 {
245 LogFlow(("WebMWriter::writeBlock catched"));
246 return rc;
247 }
248 return VINF_SUCCESS;
249}
250
251int WebMWriter::writeFooter(uint32_t a_u64Hash)
252{
253 try {
254 if (m_bClusterOpen)
255 m_Ebml << Ebml::SubEnd<Cluster>();
256
257 m_uCuePos = RTFileTell(m_File);
258 m_Ebml << Ebml::SubStart<Cues>();
259 for (std::list<CueEntry>::iterator it = m_CueList.begin(); it != m_CueList.end(); ++it)
260 {
261 m_Ebml << Ebml::SubStart<CuePoint>()
262 << Ebml::UnsignedInteger<CueTime>(it->time)
263 << Ebml::SubStart<CueTrackPositions>()
264 << Ebml::Const<CueTrack, 1>()
265 << Ebml::Var<CueClusterPosition, uint64_t>(it->loc - m_uPositionReference)
266 << Ebml::SubEnd<CueTrackPositions>()
267 << Ebml::SubEnd<CuePoint>();
268 }
269 m_Ebml << Ebml::SubEnd<Cues>()
270 << Ebml::SubEnd<Segment>();
271
272 writeSeekInfo();
273
274 int rc = RTFileSeek(m_File, m_uTrackIdPos, RTFILE_SEEK_BEGIN, NULL);
275 if (!RT_SUCCESS(rc)) throw rc;
276
277 m_Ebml << Ebml::Var<TrackUID, uint32_t>(m_bDebug ? 0xDEADBEEF : a_u64Hash);
278
279 rc = RTFileSeek(m_File, 0, RTFILE_SEEK_END, NULL);
280 if (!RT_SUCCESS(rc)) throw rc;
281 }
282 catch(int rc)
283 {
284 LogFlow(("WebMWriter::writeFooterException catched"));
285 return rc;
286 }
287 return VINF_SUCCESS;
288}
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