VirtualBox

source: vbox/trunk/src/VBox/Main/include/WebMWriter.h@ 76454

Last change on this file since 76454 was 75047, checked in by vboxsync, 6 years ago

VideoRec/WebMWriter: Renaming, docs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1/* $Id: WebMWriter.h 75047 2018-10-24 15:27:20Z vboxsync $ */
2/** @file
3 * WebMWriter.h - WebM container handling.
4 */
5
6/*
7 * Copyright (C) 2013-2018 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 an absolute WebM timecode (Block + Cluster). */
94 typedef uint64_t WebMTimecodeAbs;
95
96 /** Defines a relative WebM timecode (Block). */
97 typedef uint16_t WebMTimecodeRel;
98
99 /** Defines the WebM block flags data type. */
100 typedef uint8_t WebMBlockFlags;
101
102 /**
103 * Supported audio codecs.
104 */
105 enum AudioCodec
106 {
107 /** No audio codec specified. */
108 AudioCodec_None = 0,
109 /** Opus. */
110 AudioCodec_Opus = 1
111 };
112
113 /**
114 * Supported video codecs.
115 */
116 enum VideoCodec
117 {
118 /** No video codec specified. */
119 VideoCodec_None = 0,
120 /** VP8. */
121 VideoCodec_VP8 = 1
122 };
123
124 /**
125 * Track type enumeration.
126 */
127 enum WebMTrackType
128 {
129 /** Unknown / invalid type. */
130 WebMTrackType_Invalid = 0,
131 /** Only writes audio. */
132 WebMTrackType_Audio = 1,
133 /** Only writes video. */
134 WebMTrackType_Video = 2
135 };
136
137 struct WebMTrack;
138
139 /**
140 * Structure for defining a WebM simple block.
141 */
142 struct WebMSimpleBlock
143 {
144 WebMSimpleBlock(WebMTrack *a_pTrack,
145 WebMTimecodeAbs a_tcAbsPTSMs, const void *a_pvData, size_t a_cbData, WebMBlockFlags a_fFlags)
146 : pTrack(a_pTrack)
147 {
148 Data.tcAbsPTSMs = a_tcAbsPTSMs;
149 Data.cb = a_cbData;
150 Data.fFlags = a_fFlags;
151
152 if (Data.cb)
153 {
154 Data.pv = RTMemDup(a_pvData, a_cbData);
155 if (!Data.pv)
156 throw;
157 }
158 }
159
160 virtual ~WebMSimpleBlock()
161 {
162 if (Data.pv)
163 {
164 Assert(Data.cb);
165 RTMemFree(Data.pv);
166 }
167 }
168
169 WebMTrack *pTrack;
170
171 /** Actual simple block data. */
172 struct
173 {
174 WebMTimecodeAbs tcAbsPTSMs;
175 WebMTimecodeRel tcRelToClusterMs;
176 void *pv;
177 size_t cb;
178 WebMBlockFlags fFlags;
179 } Data;
180 };
181
182 /** A simple block queue.*/
183 typedef std::queue<WebMSimpleBlock *> WebMSimpleBlockQueue;
184
185 /** Structure for queuing all simple blocks bound to a single timecode.
186 * This can happen if multiple tracks are being involved. */
187 struct WebMTimecodeBlocks
188 {
189 WebMTimecodeBlocks(void)
190 : fClusterNeeded(false)
191 , fClusterStarted(false) { }
192
193 /** The actual block queue for this timecode. */
194 WebMSimpleBlockQueue Queue;
195 /** Whether a new cluster is needed for this timecode or not. */
196 bool fClusterNeeded;
197 /** Whether a new cluster already has been started for this timecode or not. */
198 bool fClusterStarted;
199
200 /**
201 * Enqueues a simple block into the internal queue.
202 *
203 * @param a_pBlock Block to enqueue and take ownership of.
204 */
205 void Enqueue(WebMSimpleBlock *a_pBlock)
206 {
207 Queue.push(a_pBlock);
208
209 if (a_pBlock->Data.fFlags & VBOX_WEBM_BLOCK_FLAG_KEY_FRAME)
210 fClusterNeeded = true;
211 }
212 };
213
214 /** A block map containing all currently queued blocks.
215 * The key specifies a unique timecode, whereas the value
216 * is a queue of blocks which all correlate to the key (timecode). */
217 typedef std::map<WebMTimecodeAbs, WebMTimecodeBlocks> WebMBlockMap;
218
219 /**
220 * Structure for defining a WebM (encoding) queue.
221 */
222 struct WebMQueue
223 {
224 WebMQueue(void)
225 : tcAbsLastBlockWrittenMs(0)
226 , tsLastProcessedMs(0) { }
227
228 /** Blocks as FIFO (queue). */
229 WebMBlockMap Map;
230 /** Absolute timecode (in ms) of last written block to queue. */
231 WebMTimecodeAbs tcAbsLastBlockWrittenMs;
232 /** Time stamp (in ms) of when the queue was processed last. */
233 uint64_t tsLastProcessedMs;
234 };
235
236 /**
237 * Structure for keeping a WebM track entry.
238 */
239 struct WebMTrack
240 {
241 WebMTrack(WebMTrackType a_enmType, uint8_t a_uTrack, uint64_t a_offID)
242 : enmType(a_enmType)
243 , uTrack(a_uTrack)
244 , offUUID(a_offID)
245 , cTotalBlocks(0)
246 , tcAbsLastWrittenMs(0)
247 {
248 uUUID = RTRandU32();
249 }
250
251 /** The type of this track. */
252 WebMTrackType enmType;
253 /** Track parameters. */
254 union
255 {
256 struct
257 {
258 /** Sample rate of input data. */
259 uint32_t uHz;
260 /** Duration of the frame in samples (per channel).
261 * Valid frame size are:
262 *
263 * ms Frame size
264 * 2.5 120
265 * 5 240
266 * 10 480
267 * 20 (Default) 960
268 * 40 1920
269 * 60 2880
270 */
271 uint16_t framesPerBlock;
272 /** How many milliseconds (ms) one written (simple) block represents. */
273 uint16_t msPerBlock;
274 } Audio;
275 };
276 /** This track's track number. Also used as key in track map. */
277 uint8_t uTrack;
278 /** The track's "UUID".
279 * Needed in case this track gets mux'ed with tracks from other files. Not really unique though. */
280 uint32_t uUUID;
281 /** Absolute offset in file of track UUID.
282 * Needed to write the hash sum within the footer. */
283 uint64_t offUUID;
284 /** Total number of blocks. */
285 uint64_t cTotalBlocks;
286 /** Absoute timecode (in ms) of last write. */
287 WebMTimecodeAbs tcAbsLastWrittenMs;
288 };
289
290 /**
291 * Structure for a single cue point track position entry.
292 */
293 struct WebMCueTrackPosEntry
294 {
295 WebMCueTrackPosEntry(uint64_t a_offCluster)
296 : offCluster(a_offCluster) { }
297
298 /** Offset (in bytes) of the related cluster containing the given position. */
299 uint64_t offCluster;
300 };
301
302 /** Map for keeping track position entries for a single cue point.
303 * The key is the track number (*not* UUID!). */
304 typedef std::map<uint8_t, WebMCueTrackPosEntry *> WebMCueTrackPosMap;
305
306 /**
307 * Structure for keeping a cue point.
308 */
309 struct WebMCuePoint
310 {
311 WebMCuePoint(WebMTimecodeAbs a_tcAbs)
312 : tcAbs(a_tcAbs) { }
313
314 virtual ~WebMCuePoint()
315 {
316 Clear();
317 }
318
319 void Clear(void)
320 {
321 WebMCueTrackPosMap::iterator itTrackPos = Pos.begin();
322 while (itTrackPos != Pos.end())
323 {
324 WebMCueTrackPosEntry *pTrackPos = itTrackPos->second;
325 AssertPtr(pTrackPos);
326 delete pTrackPos;
327
328 Pos.erase(itTrackPos);
329 itTrackPos = Pos.begin();
330 }
331
332 Assert(Pos.empty());
333 }
334
335 /** Map containing all track positions for this specific cue point. */
336 WebMCueTrackPosMap Pos;
337 /** Absolute time code according to the segment time base. */
338 WebMTimecodeAbs tcAbs;
339 };
340
341 /** List of cue points. */
342 typedef std::list<WebMCuePoint *> WebMCuePointList;
343
344 /**
345 * Structure for keeping a WebM cluster entry.
346 */
347 struct WebMCluster
348 {
349 WebMCluster(void)
350 : uID(0)
351 , offStart(0)
352 , fOpen(false)
353 , tcAbsStartMs(0)
354 , cBlocks(0) { }
355
356 /** This cluster's ID. */
357 uint64_t uID;
358 /** Absolute offset (in bytes) of this cluster.
359 * Needed for seeking info table. */
360 uint64_t offStart;
361 /** Whether this cluster element is opened currently. */
362 bool fOpen;
363 /** Absolute timecode (in ms) when this cluster starts. */
364 WebMTimecodeAbs tcAbsStartMs;
365 /** Absolute timecode (in ms) of when last written to this cluster. */
366 WebMTimecodeAbs tcAbsLastWrittenMs;
367 /** Number of (simple) blocks in this cluster. */
368 uint64_t cBlocks;
369 };
370
371 /**
372 * Structure for keeping a WebM segment entry.
373 *
374 * Current we're only using one segment.
375 */
376 struct WebMSegment
377 {
378 WebMSegment(void)
379 : tcAbsStartMs(0)
380 , tcAbsLastWrittenMs(0)
381 , offStart(0)
382 , offInfo(0)
383 , offSeekInfo(0)
384 , offTracks(0)
385 , offCues(0)
386 , cClusters(0)
387 {
388 uTimecodeScaleFactor = VBOX_WEBM_TIMECODESCALE_FACTOR_MS;
389
390 LogFunc(("Default timecode scale is: %RU64ns\n", uTimecodeScaleFactor));
391 }
392
393 virtual ~WebMSegment()
394 {
395 uninit();
396 }
397
398 /**
399 * Initializes a segment.
400 *
401 * @returns IPRT status code.
402 */
403 int init(void)
404 {
405 return RTCritSectInit(&CritSect);
406 }
407
408 /**
409 * Uninitializes a segment.
410 */
411 void uninit(void)
412 {
413 clear();
414
415 RTCritSectDelete(&CritSect);
416 }
417
418 /**
419 * Clear the segment's data by removing (and freeing) all data.
420 */
421 void clear(void)
422 {
423 WebMCuePointList::iterator itCuePoint = lstCuePoints.begin();
424 while (itCuePoint != lstCuePoints.end())
425 {
426 WebMCuePoint *pCuePoint = (*itCuePoint);
427 AssertPtr(pCuePoint);
428 delete pCuePoint;
429
430 lstCuePoints.erase(itCuePoint);
431 itCuePoint = lstCuePoints.begin();
432 }
433
434 Assert(lstCuePoints.empty());
435 }
436
437 /** Critical section for serializing access to this segment. */
438 RTCRITSECT CritSect;
439
440 /** The timecode scale factor of this segment. */
441 uint64_t uTimecodeScaleFactor;
442
443 /** Absolute timecode (in ms) when starting this segment. */
444 WebMTimecodeAbs tcAbsStartMs;
445 /** Absolute timecode (in ms) of last write. */
446 WebMTimecodeAbs tcAbsLastWrittenMs;
447
448 /** Absolute offset (in bytes) of CurSeg. */
449 uint64_t offStart;
450 /** Absolute offset (in bytes) of general info. */
451 uint64_t offInfo;
452 /** Absolute offset (in bytes) of seeking info. */
453 uint64_t offSeekInfo;
454 /** Absolute offset (in bytes) of tracks. */
455 uint64_t offTracks;
456 /** Absolute offset (in bytes) of cues table. */
457 uint64_t offCues;
458 /** List of cue points. Needed for seeking table. */
459 WebMCuePointList lstCuePoints;
460
461 /** Total number of clusters. */
462 uint64_t cClusters;
463
464 /** Map of tracks.
465 * The key marks the track number (*not* the UUID!). */
466 std::map <uint8_t, WebMTrack *> mapTracks;
467
468 /** Current cluster which is being handled.
469 *
470 * Note that we don't need (and shouldn't need, as this can be a *lot* of data!) a
471 * list of all clusters. */
472 WebMCluster CurCluster;
473
474 WebMQueue queueBlocks;
475
476 } CurSeg;
477
478 /** Audio codec to use. */
479 WebMWriter::AudioCodec m_enmAudioCodec;
480 /** Video codec to use. */
481 WebMWriter::VideoCodec m_enmVideoCodec;
482
483 /** Whether we're currently in the tracks section. */
484 bool m_fInTracksSection;
485
486 /** Size of timecodes (in bytes). */
487 size_t m_cbTimecode;
488 /** Maximum value a timecode can have. */
489 uint32_t m_uTimecodeMax;
490
491#ifdef VBOX_WITH_LIBVPX
492 /**
493 * Block data for VP8-encoded video data.
494 */
495 struct BlockData_VP8
496 {
497 const vpx_codec_enc_cfg_t *pCfg;
498 const vpx_codec_cx_pkt_t *pPkt;
499 };
500#endif /* VBOX_WITH_LIBVPX */
501
502#ifdef VBOX_WITH_LIBOPUS
503 /**
504 * Block data for Opus-encoded audio data.
505 */
506 struct BlockData_Opus
507 {
508 /** Pointer to encoded Opus audio data. */
509 const void *pvData;
510 /** Size (in bytes) of encoded Opus audio data. */
511 size_t cbData;
512 /** PTS (in ms) of encoded Opus audio data. */
513 uint64_t uPTSMs;
514 };
515#endif /* VBOX_WITH_LIBOPUS */
516
517public:
518
519 WebMWriter();
520
521 virtual ~WebMWriter();
522
523public:
524
525 int OpenEx(const char *a_pszFilename, PRTFILE a_phFile,
526 WebMWriter::AudioCodec a_enmAudioCodec, WebMWriter::VideoCodec a_enmVideoCodec);
527
528 int Open(const char *a_pszFilename, uint64_t a_fOpen,
529 WebMWriter::AudioCodec a_enmAudioCodec, WebMWriter::VideoCodec a_enmVideoCodec);
530
531 int Close(void);
532
533 int AddAudioTrack(uint16_t uHz, uint8_t cChannels, uint8_t cBits, uint8_t *puTrack);
534
535 int AddVideoTrack(uint16_t uWidth, uint16_t uHeight, uint32_t uFPS, uint8_t *puTrack);
536
537 int WriteBlock(uint8_t uTrack, const void *pvData, size_t cbData);
538
539 const Utf8Str& GetFileName(void);
540
541 uint64_t GetFileSize(void);
542
543 uint64_t GetAvailableSpace(void);
544
545protected:
546
547 int init(void);
548
549 void destroy(void);
550
551 int writeHeader(void);
552
553 void writeSeekHeader(void);
554
555 int writeFooter(void);
556
557 int writeSimpleBlockEBML(WebMTrack *a_pTrack, WebMSimpleBlock *a_pBlock);
558
559 int writeSimpleBlockQueued(WebMTrack *a_pTrack, WebMSimpleBlock *a_pBlock);
560
561#ifdef VBOX_WITH_LIBVPX
562 int writeSimpleBlockVP8(WebMTrack *a_pTrack, const vpx_codec_enc_cfg_t *a_pCfg, const vpx_codec_cx_pkt_t *a_pPkt);
563#endif
564
565#ifdef VBOX_WITH_LIBOPUS
566 int writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecodeAbs tcAbsPTSMs);
567#endif
568
569 int processQueue(WebMQueue *pQueue, bool fForce);
570
571protected:
572
573 typedef std::map <uint8_t, WebMTrack *> WebMTracks;
574};
575
576#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