VirtualBox

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

Last change on this file since 52769 was 52432, checked in by vboxsync, 10 years ago

Main/EbmlWriter: fixed version string

  • 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.0 KB
Line 
1/* $Id: EbmlWriter.cpp 52432 2014-08-20 16:34:15Z 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 <VBox/log.h>
31
32uint64_t WebMWriter::getFileSize()
33{
34 return RTFileTell(m_File);
35}
36
37uint64_t WebMWriter::getAvailableSpace()
38{
39 RTFOFF pcbFree;
40 int rc = RTFileQueryFsSizes(m_File, NULL, &pcbFree, 0, 0);
41 return (RT_SUCCESS(rc)? (uint64_t)pcbFree : UINT64_MAX);
42}
43
44WebMWriter::WebMWriter() :
45 m_bDebug(false),
46 m_iLastPtsMs(-1),
47 m_iInitialPtsMs(-1),
48 m_Framerate(),
49 m_uPositionReference(0),
50 m_uSeekInfoPos(0),
51 m_uSegmentInfoPos(0),
52 m_uTrackPos(0),
53 m_uCuePos(0),
54 m_uClusterPos(0),
55 m_uTrackIdPos(0),
56 m_uStartSegment(0),
57 m_uClusterTimecode(0),
58 m_bClusterOpen(false) {}
59
60int WebMWriter::create(const char *a_pszFilename)
61{
62 int rc = RTFileOpen(&m_File, a_pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
63 if (RT_SUCCESS(rc))
64 {
65 m_Ebml.init(m_File);
66 }
67 return rc;
68}
69
70void WebMWriter::close()
71{
72 RTFileClose(m_File);
73}
74
75void WebMWriter::writeSeekInfo()
76{
77 uint64_t uPos = RTFileTell(m_File);
78 if (m_uSeekInfoPos)
79 RTFileSeek(m_File, m_uSeekInfoPos, RTFILE_SEEK_BEGIN, NULL);
80 else
81 m_uSeekInfoPos = uPos;
82
83 m_Ebml.subStart(SeekHead)
84
85 .subStart(Seek)
86 .serializeUnsignedInteger(SeekID, Tracks)
87 .serializeUnsignedInteger(SeekPosition, m_uTrackPos - m_uPositionReference, 8)
88 .subEnd(Seek)
89
90 .subStart(Seek)
91 .serializeUnsignedInteger(SeekID, Cues)
92 .serializeUnsignedInteger(SeekPosition, m_uCuePos - m_uPositionReference, 8)
93 .subEnd(Seek)
94
95 .subStart(Seek)
96 .serializeUnsignedInteger(SeekID, Info)
97 .serializeUnsignedInteger(SeekPosition, m_uSegmentInfoPos - m_uPositionReference, 8)
98 .subEnd(Seek)
99
100 .subEnd(SeekHead);
101
102 int64_t iFrameTime = (int64_t)1000 * m_Framerate.den / m_Framerate.num;
103 m_uSegmentInfoPos = RTFileTell(m_File);
104
105 char szVersion[64];
106 RTStrPrintf(szVersion, sizeof(szVersion), "vpxenc%s",
107 m_bDebug ? "" : vpx_codec_version_str());
108
109 m_Ebml.subStart(Info)
110 .serializeUnsignedInteger(TimecodeScale, 1000000)
111 .serializeFloat(Segment_Duration, m_iLastPtsMs + iFrameTime - m_iInitialPtsMs)
112 .serializeString(MuxingApp, szVersion)
113 .serializeString(WritingApp, szVersion)
114 .subEnd(Info);
115}
116
117int WebMWriter::writeHeader(const vpx_codec_enc_cfg_t *a_pCfg,
118 const struct vpx_rational *a_pFps)
119{
120 try
121 {
122
123 m_Ebml.subStart(EBML)
124 .serializeUnsignedInteger(EBMLVersion, 1)
125 .serializeUnsignedInteger(EBMLReadVersion, 1)
126 .serializeUnsignedInteger(EBMLMaxIDLength, 4)
127 .serializeUnsignedInteger(EBMLMaxSizeLength, 8)
128 .serializeString(DocType, "webm")
129 .serializeUnsignedInteger(DocTypeVersion, 2)
130 .serializeUnsignedInteger(DocTypeReadVersion, 2)
131 .subEnd(EBML);
132
133 m_Ebml.subStart(Segment);
134
135 m_uPositionReference = RTFileTell(m_File);
136 m_Framerate = *a_pFps;
137
138 writeSeekInfo();
139
140 m_uTrackPos = RTFileTell(m_File);
141
142 m_Ebml.subStart(Tracks)
143 .subStart(TrackEntry)
144 .serializeUnsignedInteger(TrackNumber, 1);
145
146 m_uTrackIdPos = RTFileTell(m_File);
147
148 m_Ebml.serializeUnsignedInteger(TrackUID, 0, 4)
149 .serializeUnsignedInteger(TrackType, 1)
150 .serializeString(CodecID, "V_VP8")
151 .subStart(Video)
152 .serializeUnsignedInteger(PixelWidth, a_pCfg->g_w)
153 .serializeUnsignedInteger(PixelHeight, a_pCfg->g_h)
154 .serializeFloat(FrameRate, (double) a_pFps->num / a_pFps->den)
155 .subEnd(Video)
156 .subEnd(TrackEntry)
157 .subEnd(Tracks);
158
159 }
160 catch(int rc)
161 {
162 return rc;
163 }
164 return VINF_SUCCESS;
165}
166
167int WebMWriter::writeBlock(const vpx_codec_enc_cfg_t *a_pCfg,
168 const vpx_codec_cx_pkt_t *a_pPkt)
169{
170 try
171 {
172 uint16_t uBlockTimecode = 0;
173 int64_t iPtsMs;
174 bool bStartCluster = false;
175
176 /* Calculate the PTS of this frame in milliseconds */
177 iPtsMs = a_pPkt->data.frame.pts * 1000
178 * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den;
179 if (iPtsMs <= m_iLastPtsMs)
180 iPtsMs = m_iLastPtsMs + 1;
181 m_iLastPtsMs = iPtsMs;
182
183 if (m_iInitialPtsMs < 0)
184 m_iInitialPtsMs = m_iLastPtsMs;
185
186 /* Calculate the relative time of this block */
187 if (iPtsMs - m_uClusterTimecode > 65536)
188 bStartCluster = 1;
189 else
190 uBlockTimecode = static_cast<uint16_t>(iPtsMs - m_uClusterTimecode);
191
192 int fKeyframe = (a_pPkt->data.frame.flags & VPX_FRAME_IS_KEY);
193 if (bStartCluster || fKeyframe)
194 {
195 if (m_bClusterOpen)
196 m_Ebml.subEnd(Cluster);
197
198 /* Open a new cluster */
199 uBlockTimecode = 0;
200 m_bClusterOpen = true;
201 m_uClusterTimecode = (uint32_t)iPtsMs;
202 m_uClusterPos = RTFileTell(m_File);
203 m_Ebml.subStart(Cluster)
204 .serializeUnsignedInteger(Timecode, m_uClusterTimecode);
205
206 /* Save a cue point if this is a keyframe. */
207 if (fKeyframe)
208 {
209 CueEntry cue(m_uClusterTimecode, m_uClusterPos);
210 m_CueList.push_back(cue);
211 }
212 }
213
214 /* Write a Simple Block */
215 m_Ebml.writeClassId(SimpleBlock);
216 m_Ebml.writeUnsignedInteger(0x10000000u | (4 + a_pPkt->data.frame.sz), 4);
217 m_Ebml.writeSize(1);
218 m_Ebml.writeUnsignedInteger(uBlockTimecode, 2);
219 m_Ebml.writeUnsignedInteger((fKeyframe ? 0x80 : 0) | (a_pPkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE ? 0x08 : 0), 1);
220 m_Ebml.write(a_pPkt->data.frame.buf, a_pPkt->data.frame.sz);
221 }
222 catch(int rc)
223 {
224 return rc;
225 }
226 return VINF_SUCCESS;
227}
228
229int WebMWriter::writeFooter(uint32_t a_u64Hash)
230{
231 try
232 {
233 if (m_bClusterOpen)
234 m_Ebml.subEnd(Cluster);
235
236 m_uCuePos = RTFileTell(m_File);
237 m_Ebml.subStart(Cues);
238 for (std::list<CueEntry>::iterator it = m_CueList.begin(); it != m_CueList.end(); ++it)
239 {
240 m_Ebml.subStart(CuePoint)
241 .serializeUnsignedInteger(CueTime, it->time)
242 .subStart(CueTrackPositions)
243 .serializeUnsignedInteger(CueTrack, 1)
244 .serializeUnsignedInteger(CueClusterPosition, it->loc - m_uPositionReference, 8)
245 .subEnd(CueTrackPositions)
246 .subEnd(CuePoint);
247 }
248
249 m_Ebml.subEnd(Cues)
250 .subEnd(Segment);
251
252 writeSeekInfo();
253
254 int rc = RTFileSeek(m_File, m_uTrackIdPos, RTFILE_SEEK_BEGIN, NULL);
255 if (!RT_SUCCESS(rc)) throw rc;
256
257 m_Ebml.serializeUnsignedInteger(TrackUID, (m_bDebug ? 0xDEADBEEF : a_u64Hash), 4);
258
259 rc = RTFileSeek(m_File, 0, RTFILE_SEEK_END, NULL);
260 if (!RT_SUCCESS(rc)) throw rc;
261 }
262 catch(int rc)
263 {
264 return rc;
265 }
266 return VINF_SUCCESS;
267}
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