VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/WebMWriter.h@ 70030

Last change on this file since 70030 was 69689, checked in by vboxsync, 7 years ago

Main/WebMWriter: SVN props.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.8 KB
Line 
1/* $Id: WebMWriter.h 69689 2017-11-14 14:50:37Z vboxsync $ */
2/** @file
3 * WebMWriter.h - WebM container handling.
4 */
5
6/*
7 * Copyright (C) 2013-2017 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#ifndef ____WEBMWRITER
19#define ____WEBMWRITER
20
21#include "EBMLWriter.h"
22
23#ifdef VBOX_WITH_LIBVPX
24# ifdef _MSC_VER
25# pragma warning(push)
26# pragma warning(disable: 4668) /* vpx_codec.h(64) : warning C4668: '__GNUC__' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */
27# include <vpx/vpx_encoder.h>
28# pragma warning(pop)
29# else
30# include <vpx/vpx_encoder.h>
31# endif
32#endif /* VBOX_WITH_LIBVPX */
33
34/** No flags specified. */
35#define VBOX_WEBM_BLOCK_FLAG_NONE 0
36/** Invisible block which can be skipped. */
37#define VBOX_WEBM_BLOCK_FLAG_INVISIBLE 0x08
38/** The block marks a key frame. */
39#define VBOX_WEBM_BLOCK_FLAG_KEY_FRAME 0x80
40
41/** The default timecode scale factor for WebM -- all timecodes in the segments are expressed in ms.
42 * This allows every cluster to have blocks with positive values up to 32.767 seconds. */
43#define VBOX_WEBM_TIMECODESCALE_FACTOR_MS 1000000
44
45/** Maximum time (in ms) a cluster can store. */
46#define VBOX_WEBM_CLUSTER_MAX_LEN_MS INT16_MAX
47
48/** Maximum time a block can store.
49 * With signed 16-bit timecodes and a default timecode scale of 1ms per unit this makes 65536ms. */
50#define VBOX_WEBM_BLOCK_MAX_LEN_MS UINT16_MAX
51
52#ifdef VBOX_WITH_LIBOPUS
53# pragma pack(push)
54# pragma pack(1)
55 /** Opus codec private data within the MKV (WEBM) container.
56 * Taken from: https://wiki.xiph.org/MatroskaOpus */
57 typedef struct WEBMOPUSPRIVDATA
58 {
59 WEBMOPUSPRIVDATA(uint32_t a_u32SampleRate, uint8_t a_u8Channels)
60 {
61 au64Head = RT_MAKE_U64_FROM_U8('O', 'p', 'u', 's', 'H', 'e', 'a', 'd');
62 u8Version = 1;
63 u8Channels = a_u8Channels;
64 u16PreSkip = 0;
65 u32SampleRate = a_u32SampleRate;
66 u16Gain = 0;
67 u8MappingFamily = 0;
68 }
69
70 uint64_t au64Head; /**< Defaults to "OpusHead". */
71 uint8_t u8Version; /**< Must be set to 1. */
72 uint8_t u8Channels;
73 uint16_t u16PreSkip;
74 /** Sample rate *before* encoding to Opus.
75 * Note: This rate has nothing to do with the playback rate later! */
76 uint32_t u32SampleRate;
77 uint16_t u16Gain;
78 /** Must stay 0 -- otherwise a mapping table must be appended
79 * right after this header. */
80 uint8_t u8MappingFamily;
81 } WEBMOPUSPRIVDATA, *PWEBMOPUSPRIVDATA;
82 AssertCompileSize(WEBMOPUSPRIVDATA, 19);
83# pragma pack(pop)
84#endif /* VBOX_WITH_LIBOPUS */
85
86using namespace com;
87
88class WebMWriter : public EBMLWriter
89{
90
91public:
92
93 /** Defines a WebM timecode. */
94 typedef uint16_t WebMTimecode;
95
96 /** Defines the WebM block flags data type. */
97 typedef uint8_t WebMBlockFlags;
98
99 /**
100 * Supported audio codecs.
101 */
102 enum AudioCodec
103 {
104 /** No audio codec specified. */
105 AudioCodec_None = 0,
106 /** Opus. */
107 AudioCodec_Opus = 1
108 };
109
110 /**
111 * Supported video codecs.
112 */
113 enum VideoCodec
114 {
115 /** No video codec specified. */
116 VideoCodec_None = 0,
117 /** VP8. */
118 VideoCodec_VP8 = 1
119 };
120
121 /**
122 * Track type enumeration.
123 */
124 enum WebMTrackType
125 {
126 /** Unknown / invalid type. */
127 WebMTrackType_Invalid = 0,
128 /** Only writes audio. */
129 WebMTrackType_Audio = 1,
130 /** Only writes video. */
131 WebMTrackType_Video = 2
132 };
133
134 struct WebMTrack;
135
136 /**
137 * Structure for defining a WebM simple block.
138 */
139 struct WebMSimpleBlock
140 {
141 WebMSimpleBlock(WebMTrack *a_pTrack,
142 WebMTimecode a_tcPTSMs, const void *a_pvData, size_t a_cbData, WebMBlockFlags a_fFlags)
143 : pTrack(a_pTrack)
144 {
145 Data.tcPTSMs = a_tcPTSMs;
146 Data.cb = a_cbData;
147 Data.fFlags = a_fFlags;
148
149 if (Data.cb)
150 {
151 Data.pv = RTMemDup(a_pvData, a_cbData);
152 if (!Data.pv)
153 throw;
154 }
155 }
156
157 virtual ~WebMSimpleBlock()
158 {
159 if (Data.pv)
160 {
161 Assert(Data.cb);
162 RTMemFree(Data.pv);
163 }
164 }
165
166 WebMTrack *pTrack;
167
168 /** Actual simple block data. */
169 struct
170 {
171 WebMTimecode tcPTSMs;
172 WebMTimecode tcRelToClusterMs;
173 void *pv;
174 size_t cb;
175 WebMBlockFlags fFlags;
176 } Data;
177 };
178
179 /** A simple block queue.*/
180 typedef std::queue<WebMSimpleBlock *> WebMSimpleBlockQueue;
181
182 /** Structure for queuing all simple blocks bound to a single timecode.
183 * This can happen if multiple tracks are being involved. */
184 struct WebMTimecodeBlocks
185 {
186 WebMTimecodeBlocks(void)
187 : fClusterNeeded(false)
188 , fClusterStarted(false) { }
189
190 /** The actual block queue for this timecode. */
191 WebMSimpleBlockQueue Queue;
192 /** Whether a new cluster is needed for this timecode or not. */
193 bool fClusterNeeded;
194 /** Whether a new cluster already has been started for this timecode or not. */
195 bool fClusterStarted;
196
197 /**
198 * Enqueues a simple block into the internal queue.
199 *
200 * @param a_pBlock Block to enqueue and take ownership of.
201 */
202 void Enqueue(WebMSimpleBlock *a_pBlock)
203 {
204 Queue.push(a_pBlock);
205
206 if (a_pBlock->Data.fFlags & VBOX_WEBM_BLOCK_FLAG_KEY_FRAME)
207 fClusterNeeded = true;
208 }
209 };
210
211 /** A block map containing all currently queued blocks.
212 * The key specifies a unique timecode, whereas the value
213 * is a queue of blocks which all correlate to the key (timecode). */
214 typedef std::map<WebMTimecode, WebMTimecodeBlocks> WebMBlockMap;
215
216 /**
217 * Structure for defining a WebM (encoding) queue.
218 */
219 struct WebMQueue
220 {
221 WebMQueue(void)
222 : tcLastBlockWrittenMs(0)
223 , tslastProcessedMs(0) { }
224
225 /** Blocks as FIFO (queue). */
226 WebMBlockMap Map;
227 /** Timecode (in ms) of last written block to queue. */
228 WebMTimecode tcLastBlockWrittenMs;
229 /** Time stamp (in ms) of when the queue was processed last. */
230 uint64_t tslastProcessedMs;
231 };
232
233 /**
234 * Structure for keeping a WebM track entry.
235 */
236 struct WebMTrack
237 {
238 WebMTrack(WebMTrackType a_enmType, uint8_t a_uTrack, uint64_t a_offID)
239 : enmType(a_enmType)
240 , uTrack(a_uTrack)
241 , offUUID(a_offID)
242 , cTotalBlocks(0)
243 , tcLastWrittenMs(0)
244 {
245 uUUID = RTRandU32();
246 }
247
248 /** The type of this track. */
249 WebMTrackType enmType;
250 /** Track parameters. */
251 union
252 {
253 struct
254 {
255 /** Sample rate of input data. */
256 uint32_t uHz;
257 /** Duration of the frame in samples (per channel).
258 * Valid frame size are:
259 *
260 * ms Frame size
261 * 2.5 120
262 * 5 240
263 * 10 480
264 * 20 (Default) 960
265 * 40 1920
266 * 60 2880
267 */
268 uint16_t framesPerBlock;
269 /** How many milliseconds (ms) one written (simple) block represents. */
270 uint16_t msPerBlock;
271 } Audio;
272 };
273 /** This track's track number. Also used as key in track map. */
274 uint8_t uTrack;
275 /** The track's "UUID".
276 * Needed in case this track gets mux'ed with tracks from other files. Not really unique though. */
277 uint32_t uUUID;
278 /** Absolute offset in file of track UUID.
279 * Needed to write the hash sum within the footer. */
280 uint64_t offUUID;
281 /** Total number of blocks. */
282 uint64_t cTotalBlocks;
283 /** Timecode (in ms) of last write. */
284 WebMTimecode tcLastWrittenMs;
285 };
286
287 /**
288 * Structure for keeping a cue point.
289 */
290 struct WebMCuePoint
291 {
292 WebMCuePoint(WebMTrack *a_pTrack, uint64_t a_offCluster, WebMTimecode a_tcAbs)
293 : pTrack(a_pTrack)
294 , offCluster(a_offCluster), tcAbs(a_tcAbs) { }
295
296 /** Associated track. */
297 WebMTrack *pTrack;
298 /** Offset (in bytes) of the related cluster containing the given position. */
299 uint64_t offCluster;
300 /** Time code (absolute) of this cue point. */
301 WebMTimecode tcAbs;
302 };
303
304 /**
305 * Structure for keeping a WebM cluster entry.
306 */
307 struct WebMCluster
308 {
309 WebMCluster(void)
310 : uID(0)
311 , offStart(0)
312 , fOpen(false)
313 , tcStartMs(0)
314 , cBlocks(0) { }
315
316 /** This cluster's ID. */
317 uint64_t uID;
318 /** Absolute offset (in bytes) of this cluster.
319 * Needed for seeking info table. */
320 uint64_t offStart;
321 /** Whether this cluster element is opened currently. */
322 bool fOpen;
323 /** Timecode (in ms) when this cluster starts. */
324 WebMTimecode tcStartMs;
325 /** Number of (simple) blocks in this cluster. */
326 uint64_t cBlocks;
327 };
328
329 /**
330 * Structure for keeping a WebM segment entry.
331 *
332 * Current we're only using one segment.
333 */
334 struct WebMSegment
335 {
336 WebMSegment(void)
337 : tcStartMs(0)
338 , tcLastWrittenMs(0)
339 , offStart(0)
340 , offInfo(0)
341 , offSeekInfo(0)
342 , offTracks(0)
343 , offCues(0)
344 {
345 uTimecodeScaleFactor = VBOX_WEBM_TIMECODESCALE_FACTOR_MS;
346
347 LogFunc(("Default timecode scale is: %RU64ns\n", uTimecodeScaleFactor));
348 }
349
350 int init(void)
351 {
352 return RTCritSectInit(&CritSect);
353 }
354
355 void destroy(void)
356 {
357 RTCritSectDelete(&CritSect);
358 }
359
360 /** Critical section for serializing access to this segment. */
361 RTCRITSECT CritSect;
362
363 /** The timecode scale factor of this segment. */
364 uint64_t uTimecodeScaleFactor;
365
366 /** Timecode (in ms) when starting this segment. */
367 WebMTimecode tcStartMs;
368 /** Timecode (in ms) of last write. */
369 WebMTimecode tcLastWrittenMs;
370
371 /** Absolute offset (in bytes) of CurSeg. */
372 uint64_t offStart;
373 /** Absolute offset (in bytes) of general info. */
374 uint64_t offInfo;
375 /** Absolute offset (in bytes) of seeking info. */
376 uint64_t offSeekInfo;
377 /** Absolute offset (in bytes) of tracks. */
378 uint64_t offTracks;
379 /** Absolute offset (in bytes) of cues table. */
380 uint64_t offCues;
381 /** List of cue points. Needed for seeking table. */
382 std::list<WebMCuePoint> lstCues;
383
384 /** Total number of clusters. */
385 uint64_t cClusters;
386
387 /** Map of tracks.
388 * The key marks the track number (*not* the UUID!). */
389 std::map <uint8_t, WebMTrack *> mapTracks;
390
391 /** Current cluster which is being handled.
392 *
393 * Note that we don't need (and shouldn't need, as this can be a *lot* of data!) a
394 * list of all clusters. */
395 WebMCluster CurCluster;
396
397 WebMQueue queueBlocks;
398
399 } CurSeg;
400
401 /** Audio codec to use. */
402 WebMWriter::AudioCodec m_enmAudioCodec;
403 /** Video codec to use. */
404 WebMWriter::VideoCodec m_enmVideoCodec;
405
406 /** Whether we're currently in the tracks section. */
407 bool m_fInTracksSection;
408
409 /** Size of timecodes in bytes. */
410 size_t m_cbTimecode;
411 /** Maximum value a timecode can have. */
412 uint32_t m_uTimecodeMax;
413
414#ifdef VBOX_WITH_LIBVPX
415 /**
416 * Block data for VP8-encoded video data.
417 */
418 struct BlockData_VP8
419 {
420 const vpx_codec_enc_cfg_t *pCfg;
421 const vpx_codec_cx_pkt_t *pPkt;
422 };
423#endif /* VBOX_WITH_LIBVPX */
424
425#ifdef VBOX_WITH_LIBOPUS
426 /**
427 * Block data for Opus-encoded audio data.
428 */
429 struct BlockData_Opus
430 {
431 /** Pointer to encoded Opus audio data. */
432 const void *pvData;
433 /** Size (in bytes) of encoded Opus audio data. */
434 size_t cbData;
435 /** PTS (in ms) of encoded Opus audio data. */
436 uint64_t uPTSMs;
437 };
438#endif /* VBOX_WITH_LIBOPUS */
439
440public:
441
442 WebMWriter();
443
444 virtual ~WebMWriter();
445
446public:
447
448 int OpenEx(const char *a_pszFilename, PRTFILE a_phFile,
449 WebMWriter::AudioCodec a_enmAudioCodec, WebMWriter::VideoCodec a_enmVideoCodec);
450
451 int Open(const char *a_pszFilename, uint64_t a_fOpen,
452 WebMWriter::AudioCodec a_enmAudioCodec, WebMWriter::VideoCodec a_enmVideoCodec);
453
454 int Close(void);
455
456 int AddAudioTrack(uint16_t uHz, uint8_t cChannels, uint8_t cBits, uint8_t *puTrack);
457
458 int AddVideoTrack(uint16_t uWidth, uint16_t uHeight, double dbFPS, uint8_t *puTrack);
459
460 int WriteBlock(uint8_t uTrack, const void *pvData, size_t cbData);
461
462 const Utf8Str& GetFileName(void);
463
464 uint64_t GetFileSize(void);
465
466 uint64_t GetAvailableSpace(void);
467
468protected:
469
470 int init(void);
471
472 void destroy(void);
473
474 int writeHeader(void);
475
476 void writeSegSeekInfo(void);
477
478 int writeFooter(void);
479
480 int writeSimpleBlockEBML(WebMTrack *a_pTrack, WebMSimpleBlock *a_pBlock);
481
482 int writeSimpleBlockQueued(WebMTrack *a_pTrack, WebMSimpleBlock *a_pBlock);
483
484#ifdef VBOX_WITH_LIBVPX
485 int writeSimpleBlockVP8(WebMTrack *a_pTrack, const vpx_codec_enc_cfg_t *a_pCfg, const vpx_codec_cx_pkt_t *a_pPkt);
486#endif
487
488#ifdef VBOX_WITH_LIBOPUS
489 int writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecode uPTSMs);
490#endif
491
492 int processQueues(WebMQueue *pQueue, bool fForce);
493
494protected:
495
496 typedef std::map <uint8_t, WebMTrack *> WebMTracks;
497};
498
499#endif /* !____WEBMWRITER */
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