Changeset 52791 in vbox for trunk/src/VBox/Main/src-client/EbmlWriter.h
- Timestamp:
- Sep 18, 2014 4:11:50 PM (11 years ago)
- svn:sync-xref-src-repo-rev:
- 96177
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-client/EbmlWriter.h
r52427 r52791 5 5 6 6 /* 7 * Copyright (C) 2013 Oracle Corporation7 * Copyright (C) 2013-2014 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 31 31 #define ____EBMLWRITER 32 32 33 #include <iprt/file.h>34 #include <iprt/cdefs.h>35 #include <iprt/asm.h>36 #include <iprt/string.h>37 33 #include <vpx/vpx_encoder.h> 38 34 39 #include <stack> 40 #include <list> 41 42 class Ebml 43 { 44 public: 45 typedef uint32_t EbmlClassId; 46 47 private: 48 49 struct EbmlSubElement 50 { 51 uint64_t offset; 52 EbmlClassId classId; 53 EbmlSubElement(uint64_t offs, EbmlClassId cid) : offset(offs), classId(cid) {} 54 }; 55 56 std::stack<EbmlSubElement> m_Elements; 57 RTFILE m_File; 58 59 public: 60 61 /* Initialize EBML object */ 62 inline void init(const RTFILE &a_File) { m_File = a_File; } 63 64 /* Starts an EBML sub-element */ 65 inline Ebml &subStart(EbmlClassId classId) 66 { 67 writeClassId(classId); 68 /* store the current file offset */ 69 m_Elements.push(EbmlSubElement(RTFileTell(m_File), classId)); 70 /* Indicates that size of the element 71 * is unkown (as according to EBML specs) 72 */ 73 writeUnsignedInteger(UINT64_C(0x01FFFFFFFFFFFFFF)); 74 return *this; 75 } 76 77 /* Ends an EBML sub-element */ 78 inline Ebml &subEnd(EbmlClassId classId) 79 { 80 /* Class ID on the top of the stack should match the class ID passed 81 * to the function. Otherwise it may mean that we have a bug in the code 82 */ 83 if(m_Elements.empty() || m_Elements.top().classId != classId) throw VERR_INTERNAL_ERROR; 84 85 uint64_t uPos = RTFileTell(m_File); 86 uint64_t uSize = uPos - m_Elements.top().offset - 8; 87 RTFileSeek(m_File, m_Elements.top().offset, RTFILE_SEEK_BEGIN, NULL); 88 89 /* make sure that size will be serialized as uint64 */ 90 writeUnsignedInteger(uSize | UINT64_C(0x0100000000000000)); 91 RTFileSeek(m_File, uPos, RTFILE_SEEK_BEGIN, NULL); 92 m_Elements.pop(); 93 return *this; 94 } 95 96 /* Serializes a null-terminated string */ 97 inline Ebml &serializeString(EbmlClassId classId, const char *str) 98 { 99 writeClassId(classId); 100 uint64_t size = strlen(str); 101 writeSize(size); 102 write(str, size); 103 return *this; 104 } 105 106 /* Serializes an UNSIGNED integer 107 * If size is zero then it will be detected automatically */ 108 inline Ebml &serializeUnsignedInteger(EbmlClassId classId, uint64_t parm, size_t size = 0) 109 { 110 writeClassId(classId); 111 if (!size) size = getSizeOfUInt(parm); 112 writeSize(size); 113 writeUnsignedInteger(parm, size); 114 return *this; 115 } 116 117 /* Serializes a floating point value 118 * Only 8-bytes double precision values are supported 119 * by this function 120 */ 121 inline Ebml &serializeFloat(EbmlClassId classId, double value) 122 { 123 writeClassId(classId); 124 writeSize(sizeof(double)); 125 writeUnsignedInteger(*reinterpret_cast<uint64_t*>(&value)); 126 return *this; 127 } 128 129 /* Writes raw data to file */ 130 inline void write(const void *data, size_t size) 131 { 132 int rc = RTFileWrite(m_File, data, size, NULL); 133 if (!RT_SUCCESS(rc)) throw rc; 134 } 135 136 /* Writes an unsigned integer of variable of fixed size */ 137 inline void writeUnsignedInteger(uint64_t value, size_t size = sizeof(uint64_t)) 138 { 139 /* Convert to big-endian */ 140 value = RT_H2BE_U64(value); 141 write(reinterpret_cast<uint8_t*>(&value) + sizeof(value) - size, size); 142 } 143 144 /* Writes EBML class ID to file 145 * EBML ID already has a UTF8-like represenation 146 * so getSizeOfUInt is used to determine 147 * the number of its bytes 148 */ 149 inline void writeClassId(EbmlClassId parm) 150 { 151 writeUnsignedInteger(parm, getSizeOfUInt(parm)); 152 } 153 154 /* Writes data size value */ 155 inline void writeSize(uint64_t parm) 156 { 157 /* The following expression defines the size of the value that will be serialized 158 * as an EBML UTF-8 like integer (with trailing bits represeting its size) 159 1xxx xxxx - value 0 to 2^7-2 160 01xx xxxx xxxx xxxx - value 0 to 2^14-2 161 001x xxxx xxxx xxxx xxxx xxxx - value 0 to 2^21-2 162 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^28-2 163 0000 1xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^35-2 164 0000 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^42-2 165 0000 001x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^49-2 166 0000 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^56-2 167 */ 168 size_t size = 8 - ! (parm & (UINT64_MAX << 49)) - ! (parm & (UINT64_MAX << 42)) - 169 ! (parm & (UINT64_MAX << 35)) - ! (parm & (UINT64_MAX << 28)) - 170 ! (parm & (UINT64_MAX << 21)) - ! (parm & (UINT64_MAX << 14)) - 171 ! (parm & (UINT64_MAX << 7)); 172 /* One is subtracted in order to avoid loosing significant bit when size = 8 */ 173 uint64_t mask = RT_BIT_64(size * 8 - 1); 174 writeUnsignedInteger((parm & (((mask << 1) - 1) >> size)) | (mask >> (size - 1)), size); 175 } 176 /* Size calculation for variable size UNSIGNED integer. 177 * The function defines the size of the number by trimming 178 * consequent trailing zero bytes starting from the most significant. 179 * The following statement is always true: 180 * 1 <= getSizeOfUInt(arg) <= 8 181 * 182 * Every !(arg & (UINT64_MAX << X)) expression gives one 183 * if an only if all the bits from X to 63 are set to zero. 184 */ 185 static inline size_t getSizeOfUInt(uint64_t arg) 186 { 187 return 8 - ! (arg & (UINT64_MAX << 56)) - ! (arg & (UINT64_MAX << 48)) - 188 ! (arg & (UINT64_MAX << 40)) - ! (arg & (UINT64_MAX << 32)) - 189 ! (arg & (UINT64_MAX << 24)) - ! (arg & (UINT64_MAX << 16)) - 190 ! (arg & (UINT64_MAX << 8)); 191 } 192 193 private: 194 void operator=(const Ebml &); 195 196 }; 35 class WebMWriter_Impl; 197 36 198 37 class WebMWriter 199 38 { 200 /* Matroska EBML Class IDs supported by WebM */201 enum Mkv202 {203 EBML = 0x1A45DFA3,204 EBMLVersion = 0x4286,205 EBMLReadVersion = 0x42F7,206 EBMLMaxIDLength = 0x42F2,207 EBMLMaxSizeLength = 0x42F3,208 DocType = 0x4282,209 DocTypeVersion = 0x4287,210 DocTypeReadVersion = 0x4285,211 // CRC_32 = 0xBF,212 Void = 0xEC,213 SignatureSlot = 0x1B538667,214 SignatureAlgo = 0x7E8A,215 SignatureHash = 0x7E9A,216 SignaturePublicKey = 0x7EA5,217 Signature = 0x7EB5,218 SignatureElements = 0x7E5B,219 SignatureElementList = 0x7E7B,220 SignedElement = 0x6532,221 //segment222 Segment = 0x18538067,223 //Meta Seek Information224 SeekHead = 0x114D9B74,225 Seek = 0x4DBB,226 SeekID = 0x53AB,227 SeekPosition = 0x53AC,228 //Segment Information229 Info = 0x1549A966,230 // SegmentUID = 0x73A4,231 // SegmentFilename = 0x7384,232 // PrevUID = 0x3CB923,233 // PrevFilename = 0x3C83AB,234 // NextUID = 0x3EB923,235 // NextFilename = 0x3E83BB,236 // SegmentFamily = 0x4444,237 // ChapterTranslate = 0x6924,238 // ChapterTranslateEditionUID = 0x69FC,239 // ChapterTranslateCodec = 0x69BF,240 // ChapterTranslateID = 0x69A5,241 TimecodeScale = 0x2AD7B1,242 Segment_Duration = 0x4489,243 DateUTC = 0x4461,244 // Title = 0x7BA9,245 MuxingApp = 0x4D80,246 WritingApp = 0x5741,247 //Cluster248 Cluster = 0x1F43B675,249 Timecode = 0xE7,250 // SilentTracks = 0x5854,251 // SilentTrackNumber = 0x58D7,252 // Position = 0xA7,253 PrevSize = 0xAB,254 BlockGroup = 0xA0,255 Block = 0xA1,256 // BlockVirtual = 0xA2,257 // BlockAdditions = 0x75A1,258 // BlockMore = 0xA6,259 // BlockAddID = 0xEE,260 // BlockAdditional = 0xA5,261 BlockDuration = 0x9B,262 // ReferencePriority = 0xFA,263 ReferenceBlock = 0xFB,264 // ReferenceVirtual = 0xFD,265 // CodecState = 0xA4,266 // Slices = 0x8E,267 // TimeSlice = 0xE8,268 LaceNumber = 0xCC,269 // FrameNumber = 0xCD,270 // BlockAdditionID = 0xCB,271 // MkvDelay = 0xCE,272 // Cluster_Duration = 0xCF,273 SimpleBlock = 0xA3,274 // EncryptedBlock = 0xAF,275 //Track276 Tracks = 0x1654AE6B,277 TrackEntry = 0xAE,278 TrackNumber = 0xD7,279 TrackUID = 0x73C5,280 TrackType = 0x83,281 FlagEnabled = 0xB9,282 FlagDefault = 0x88,283 FlagForced = 0x55AA,284 FlagLacing = 0x9C,285 // MinCache = 0x6DE7,286 // MaxCache = 0x6DF8,287 DefaultDuration = 0x23E383,288 // TrackTimecodeScale = 0x23314F,289 // TrackOffset = 0x537F,290 // MaxBlockAdditionID = 0x55EE,291 Name = 0x536E,292 Language = 0x22B59C,293 CodecID = 0x86,294 CodecPrivate = 0x63A2,295 CodecName = 0x258688,296 // AttachmentLink = 0x7446,297 // CodecSettings = 0x3A9697,298 // CodecInfoURL = 0x3B4040,299 // CodecDownloadURL = 0x26B240,300 // CodecDecodeAll = 0xAA,301 // TrackOverlay = 0x6FAB,302 // TrackTranslate = 0x6624,303 // TrackTranslateEditionUID = 0x66FC,304 // TrackTranslateCodec = 0x66BF,305 // TrackTranslateTrackID = 0x66A5,306 //video307 Video = 0xE0,308 FlagInterlaced = 0x9A,309 // StereoMode = 0x53B8,310 PixelWidth = 0xB0,311 PixelHeight = 0xBA,312 PixelCropBottom = 0x54AA,313 PixelCropTop = 0x54BB,314 PixelCropLeft = 0x54CC,315 PixelCropRight = 0x54DD,316 DisplayWidth = 0x54B0,317 DisplayHeight = 0x54BA,318 DisplayUnit = 0x54B2,319 AspectRatioType = 0x54B3,320 // ColourSpace = 0x2EB524,321 // GammaValue = 0x2FB523,322 FrameRate = 0x2383E3,323 //end video324 //audio325 Audio = 0xE1,326 SamplingFrequency = 0xB5,327 OutputSamplingFrequency = 0x78B5,328 Channels = 0x9F,329 // ChannelPositions = 0x7D7B,330 BitDepth = 0x6264,331 //end audio332 //content encoding333 // ContentEncodings = 0x6d80,334 // ContentEncoding = 0x6240,335 // ContentEncodingOrder = 0x5031,336 // ContentEncodingScope = 0x5032,337 // ContentEncodingType = 0x5033,338 // ContentCompression = 0x5034,339 // ContentCompAlgo = 0x4254,340 // ContentCompSettings = 0x4255,341 // ContentEncryption = 0x5035,342 // ContentEncAlgo = 0x47e1,343 // ContentEncKeyID = 0x47e2,344 // ContentSignature = 0x47e3,345 // ContentSigKeyID = 0x47e4,346 // ContentSigAlgo = 0x47e5,347 // ContentSigHashAlgo = 0x47e6,348 //end content encoding349 //Cueing Data350 Cues = 0x1C53BB6B,351 CuePoint = 0xBB,352 CueTime = 0xB3,353 CueTrackPositions = 0xB7,354 CueTrack = 0xF7,355 CueClusterPosition = 0xF1,356 CueBlockNumber = 0x5378357 // CueCodecState = 0xEA,358 // CueReference = 0xDB,359 // CueRefTime = 0x96,360 // CueRefCluster = 0x97,361 // CueRefNumber = 0x535F,362 // CueRefCodecState = 0xEB,363 //Attachment364 // Attachments = 0x1941A469,365 // AttachedFile = 0x61A7,366 // FileDescription = 0x467E,367 // FileName = 0x466E,368 // FileMimeType = 0x4660,369 // FileData = 0x465C,370 // FileUID = 0x46AE,371 // FileReferral = 0x4675,372 //Chapters373 // Chapters = 0x1043A770,374 // EditionEntry = 0x45B9,375 // EditionUID = 0x45BC,376 // EditionFlagHidden = 0x45BD,377 // EditionFlagDefault = 0x45DB,378 // EditionFlagOrdered = 0x45DD,379 // ChapterAtom = 0xB6,380 // ChapterUID = 0x73C4,381 // ChapterTimeStart = 0x91,382 // ChapterTimeEnd = 0x92,383 // ChapterFlagHidden = 0x98,384 // ChapterFlagEnabled = 0x4598,385 // ChapterSegmentUID = 0x6E67,386 // ChapterSegmentEditionUID = 0x6EBC,387 // ChapterPhysicalEquiv = 0x63C3,388 // ChapterTrack = 0x8F,389 // ChapterTrackNumber = 0x89,390 // ChapterDisplay = 0x80,391 // ChapString = 0x85,392 // ChapLanguage = 0x437C,393 // ChapCountry = 0x437E,394 // ChapProcess = 0x6944,395 // ChapProcessCodecID = 0x6955,396 // ChapProcessPrivate = 0x450D,397 // ChapProcessCommand = 0x6911,398 // ChapProcessTime = 0x6922,399 // ChapProcessData = 0x6933,400 //Tagging401 // Tags = 0x1254C367,402 // Tag = 0x7373,403 // Targets = 0x63C0,404 // TargetTypeValue = 0x68CA,405 // TargetType = 0x63CA,406 // Tagging_TrackUID = 0x63C5,407 // Tagging_EditionUID = 0x63C9,408 // Tagging_ChapterUID = 0x63C4,409 // AttachmentUID = 0x63C6,410 // SimpleTag = 0x67C8,411 // TagName = 0x45A3,412 // TagLanguage = 0x447A,413 // TagDefault = 0x4484,414 // TagString = 0x4487,415 // TagBinary = 0x4485,416 };417 418 struct CueEntry419 {420 uint32_t time;421 uint64_t loc;422 CueEntry(uint32_t t, uint64_t l) : time(t), loc(l) {}423 };424 425 bool m_bDebug;426 int64_t m_iLastPtsMs;427 int64_t m_iInitialPtsMs;428 vpx_rational_t m_Framerate;429 430 uint64_t m_uPositionReference;431 uint64_t m_uSeekInfoPos;432 uint64_t m_uSegmentInfoPos;433 uint64_t m_uTrackPos;434 uint64_t m_uCuePos;435 uint64_t m_uClusterPos;436 437 uint64_t m_uTrackIdPos;438 439 uint64_t m_uStartSegment;440 441 uint32_t m_uClusterTimecode;442 bool m_bClusterOpen;443 std::list<CueEntry> m_CueList;444 445 Ebml m_Ebml;446 RTFILE m_File;447 448 39 public: 449 40 WebMWriter(); 450 /* Creates output file */ 41 virtual ~WebMWriter(); 42 43 /* Creates output file 44 * 45 * @param a_pszFilename Name of the file to create. 46 * 47 * @returns VBox status code. */ 451 48 int create(const char *a_pszFilename); 452 /* closes the file */ 49 50 /* Closes output file. */ 453 51 void close(); 454 /* Writes WebM header to file 455 * Should be called before any writeBlock call 52 53 /* Writes WebM header to file. 54 * Should be called before any writeBlock call. 55 * 56 * @param a_pCfg Pointer to VPX Codec configuration structure. 57 * @param a_pFps Framerate information (frames per second). 58 * 59 * @returns VBox status code. 456 60 */ 457 61 int writeHeader(const vpx_codec_enc_cfg_t *a_pCfg, const vpx_rational *a_pFps); 458 /* Writes a block of compressed data */ 62 63 /* Writes a block of compressed data 64 * 65 * @param a_pCfg Pointer to VPX Codec configuration structure. 66 * @param a_pPkt VPX data packet. 67 * 68 * @returns VBox status code. 69 */ 459 70 int writeBlock(const vpx_codec_enc_cfg_t *a_pCfg, const vpx_codec_cx_pkt_t *a_pPkt); 460 /* Writes WebM footer 461 * No other write functions should be called after this one 71 72 /* Writes WebM footer. 73 * No other write functions should be called after this one. 74 * @param a_u64Hash Hash value for the data written. 75 * 76 * @returns VBox status code. 462 77 */ 463 78 int writeFooter(uint32_t a_u64Hash); 464 /* Returns current output file size */ 79 80 /* Gets current output file size. 81 * @returns File size in bytes. 82 */ 465 83 uint64_t getFileSize(); 466 /* Returns current free storage space 467 * available for the file 84 85 /* Gets current free storage space 86 * available for the file. 87 * 88 * @returns Available storage free space. 468 89 */ 469 90 uint64_t getAvailableSpace(); 470 91 471 92 private: 472 void writeSeekInfo(); 93 /* WebMWriter implementation. 94 * To isolate some include files */ 95 WebMWriter_Impl *m_Impl; 96 97 /* Not defined */ 473 98 void operator=(const WebMWriter &); 474 99 WebMWriter(const WebMWriter &);
Note:
See TracChangeset
for help on using the changeset viewer.