VirtualBox

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

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

6219: EbmlWriter code cleanup. Default video capture quality tuning.

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

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