Changeset 52791 in vbox for trunk/src/VBox/Main/src-client
- Timestamp:
- Sep 18, 2014 4:11:50 PM (11 years ago)
- svn:sync-xref-src-repo-rev:
- 96177
- Location:
- trunk/src/VBox/Main/src-client
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-client/EbmlWriter.cpp
r52432 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 … … 20 20 * 21 21 * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 22 * 22 23 * Use of this source code is governed by a BSD-style license 23 24 * that can be found in the LICENSE file in the root of the source … … 27 28 */ 28 29 30 #include <list> 31 #include <stack> 32 #include <iprt/string.h> 33 #include <iprt/file.h> 34 #include <iprt/asm.h> 35 #include <iprt/cdefs.h> 36 #include <iprt/err.h> 37 #include <VBox/log.h> 29 38 #include "EbmlWriter.h" 30 #include <VBox/log.h> 31 32 uint64_t WebMWriter::getFileSize() 33 { 34 return RTFileTell(m_File); 35 } 36 37 uint64_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 44 WebMWriter::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 60 int 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 70 void WebMWriter::close() 71 { 72 RTFileClose(m_File); 73 } 74 75 void 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 117 int WebMWriter::writeHeader(const vpx_codec_enc_cfg_t *a_pCfg, 118 const struct vpx_rational *a_pFps) 119 { 120 try 121 { 122 39 40 /* Matroska EBML Class IDs supported by WebM */ 41 enum Mkv 42 { 43 EBML = 0x1A45DFA3, 44 EBMLVersion = 0x4286, 45 EBMLReadVersion = 0x42F7, 46 EBMLMaxIDLength = 0x42F2, 47 EBMLMaxSizeLength = 0x42F3, 48 DocType = 0x4282, 49 DocTypeVersion = 0x4287, 50 DocTypeReadVersion = 0x4285, 51 // CRC_32 = 0xBF, 52 Void = 0xEC, 53 SignatureSlot = 0x1B538667, 54 SignatureAlgo = 0x7E8A, 55 SignatureHash = 0x7E9A, 56 SignaturePublicKey = 0x7EA5, 57 Signature = 0x7EB5, 58 SignatureElements = 0x7E5B, 59 SignatureElementList = 0x7E7B, 60 SignedElement = 0x6532, 61 //segment 62 Segment = 0x18538067, 63 //Meta Seek Information 64 SeekHead = 0x114D9B74, 65 Seek = 0x4DBB, 66 SeekID = 0x53AB, 67 SeekPosition = 0x53AC, 68 //Segment Information 69 Info = 0x1549A966, 70 // SegmentUID = 0x73A4, 71 // SegmentFilename = 0x7384, 72 // PrevUID = 0x3CB923, 73 // PrevFilename = 0x3C83AB, 74 // NextUID = 0x3EB923, 75 // NextFilename = 0x3E83BB, 76 // SegmentFamily = 0x4444, 77 // ChapterTranslate = 0x6924, 78 // ChapterTranslateEditionUID = 0x69FC, 79 // ChapterTranslateCodec = 0x69BF, 80 // ChapterTranslateID = 0x69A5, 81 TimecodeScale = 0x2AD7B1, 82 Segment_Duration = 0x4489, 83 DateUTC = 0x4461, 84 // Title = 0x7BA9, 85 MuxingApp = 0x4D80, 86 WritingApp = 0x5741, 87 //Cluster 88 Cluster = 0x1F43B675, 89 Timecode = 0xE7, 90 // SilentTracks = 0x5854, 91 // SilentTrackNumber = 0x58D7, 92 // Position = 0xA7, 93 PrevSize = 0xAB, 94 BlockGroup = 0xA0, 95 Block = 0xA1, 96 // BlockVirtual = 0xA2, 97 // BlockAdditions = 0x75A1, 98 // BlockMore = 0xA6, 99 // BlockAddID = 0xEE, 100 // BlockAdditional = 0xA5, 101 BlockDuration = 0x9B, 102 // ReferencePriority = 0xFA, 103 ReferenceBlock = 0xFB, 104 // ReferenceVirtual = 0xFD, 105 // CodecState = 0xA4, 106 // Slices = 0x8E, 107 // TimeSlice = 0xE8, 108 LaceNumber = 0xCC, 109 // FrameNumber = 0xCD, 110 // BlockAdditionID = 0xCB, 111 // MkvDelay = 0xCE, 112 // Cluster_Duration = 0xCF, 113 SimpleBlock = 0xA3, 114 // EncryptedBlock = 0xAF, 115 //Track 116 Tracks = 0x1654AE6B, 117 TrackEntry = 0xAE, 118 TrackNumber = 0xD7, 119 TrackUID = 0x73C5, 120 TrackType = 0x83, 121 FlagEnabled = 0xB9, 122 FlagDefault = 0x88, 123 FlagForced = 0x55AA, 124 FlagLacing = 0x9C, 125 // MinCache = 0x6DE7, 126 // MaxCache = 0x6DF8, 127 DefaultDuration = 0x23E383, 128 // TrackTimecodeScale = 0x23314F, 129 // TrackOffset = 0x537F, 130 // MaxBlockAdditionID = 0x55EE, 131 Name = 0x536E, 132 Language = 0x22B59C, 133 CodecID = 0x86, 134 CodecPrivate = 0x63A2, 135 CodecName = 0x258688, 136 // AttachmentLink = 0x7446, 137 // CodecSettings = 0x3A9697, 138 // CodecInfoURL = 0x3B4040, 139 // CodecDownloadURL = 0x26B240, 140 // CodecDecodeAll = 0xAA, 141 // TrackOverlay = 0x6FAB, 142 // TrackTranslate = 0x6624, 143 // TrackTranslateEditionUID = 0x66FC, 144 // TrackTranslateCodec = 0x66BF, 145 // TrackTranslateTrackID = 0x66A5, 146 //video 147 Video = 0xE0, 148 FlagInterlaced = 0x9A, 149 // StereoMode = 0x53B8, 150 PixelWidth = 0xB0, 151 PixelHeight = 0xBA, 152 PixelCropBottom = 0x54AA, 153 PixelCropTop = 0x54BB, 154 PixelCropLeft = 0x54CC, 155 PixelCropRight = 0x54DD, 156 DisplayWidth = 0x54B0, 157 DisplayHeight = 0x54BA, 158 DisplayUnit = 0x54B2, 159 AspectRatioType = 0x54B3, 160 // ColourSpace = 0x2EB524, 161 // GammaValue = 0x2FB523, 162 FrameRate = 0x2383E3, 163 //end video 164 //audio 165 Audio = 0xE1, 166 SamplingFrequency = 0xB5, 167 OutputSamplingFrequency = 0x78B5, 168 Channels = 0x9F, 169 // ChannelPositions = 0x7D7B, 170 BitDepth = 0x6264, 171 //end audio 172 //content encoding 173 // ContentEncodings = 0x6d80, 174 // ContentEncoding = 0x6240, 175 // ContentEncodingOrder = 0x5031, 176 // ContentEncodingScope = 0x5032, 177 // ContentEncodingType = 0x5033, 178 // ContentCompression = 0x5034, 179 // ContentCompAlgo = 0x4254, 180 // ContentCompSettings = 0x4255, 181 // ContentEncryption = 0x5035, 182 // ContentEncAlgo = 0x47e1, 183 // ContentEncKeyID = 0x47e2, 184 // ContentSignature = 0x47e3, 185 // ContentSigKeyID = 0x47e4, 186 // ContentSigAlgo = 0x47e5, 187 // ContentSigHashAlgo = 0x47e6, 188 //end content encoding 189 //Cueing Data 190 Cues = 0x1C53BB6B, 191 CuePoint = 0xBB, 192 CueTime = 0xB3, 193 CueTrackPositions = 0xB7, 194 CueTrack = 0xF7, 195 CueClusterPosition = 0xF1, 196 CueBlockNumber = 0x5378 197 // CueCodecState = 0xEA, 198 // CueReference = 0xDB, 199 // CueRefTime = 0x96, 200 // CueRefCluster = 0x97, 201 // CueRefNumber = 0x535F, 202 // CueRefCodecState = 0xEB, 203 //Attachment 204 // Attachments = 0x1941A469, 205 // AttachedFile = 0x61A7, 206 // FileDescription = 0x467E, 207 // FileName = 0x466E, 208 // FileMimeType = 0x4660, 209 // FileData = 0x465C, 210 // FileUID = 0x46AE, 211 // FileReferral = 0x4675, 212 //Chapters 213 // Chapters = 0x1043A770, 214 // EditionEntry = 0x45B9, 215 // EditionUID = 0x45BC, 216 // EditionFlagHidden = 0x45BD, 217 // EditionFlagDefault = 0x45DB, 218 // EditionFlagOrdered = 0x45DD, 219 // ChapterAtom = 0xB6, 220 // ChapterUID = 0x73C4, 221 // ChapterTimeStart = 0x91, 222 // ChapterTimeEnd = 0x92, 223 // ChapterFlagHidden = 0x98, 224 // ChapterFlagEnabled = 0x4598, 225 // ChapterSegmentUID = 0x6E67, 226 // ChapterSegmentEditionUID = 0x6EBC, 227 // ChapterPhysicalEquiv = 0x63C3, 228 // ChapterTrack = 0x8F, 229 // ChapterTrackNumber = 0x89, 230 // ChapterDisplay = 0x80, 231 // ChapString = 0x85, 232 // ChapLanguage = 0x437C, 233 // ChapCountry = 0x437E, 234 // ChapProcess = 0x6944, 235 // ChapProcessCodecID = 0x6955, 236 // ChapProcessPrivate = 0x450D, 237 // ChapProcessCommand = 0x6911, 238 // ChapProcessTime = 0x6922, 239 // ChapProcessData = 0x6933, 240 //Tagging 241 // Tags = 0x1254C367, 242 // Tag = 0x7373, 243 // Targets = 0x63C0, 244 // TargetTypeValue = 0x68CA, 245 // TargetType = 0x63CA, 246 // Tagging_TrackUID = 0x63C5, 247 // Tagging_EditionUID = 0x63C9, 248 // Tagging_ChapterUID = 0x63C4, 249 // AttachmentUID = 0x63C6, 250 // SimpleTag = 0x67C8, 251 // TagName = 0x45A3, 252 // TagLanguage = 0x447A, 253 // TagDefault = 0x4484, 254 // TagString = 0x4487, 255 // TagBinary = 0x4485, 256 }; 257 258 class Ebml 259 { 260 public: 261 typedef uint32_t EbmlClassId; 262 263 private: 264 265 struct EbmlSubElement 266 { 267 uint64_t offset; 268 EbmlClassId classId; 269 EbmlSubElement(uint64_t offs, EbmlClassId cid) : offset(offs), classId(cid) {} 270 }; 271 272 std::stack<EbmlSubElement> m_Elements; 273 RTFILE m_File; 274 275 public: 276 277 /* Creates EBML output file. */ 278 inline int create(const char *a_pszFilename) 279 { 280 return RTFileOpen(&m_File, a_pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 281 } 282 283 /* Returns file size. */ 284 inline uint64_t getFileSize() 285 { 286 return RTFileTell(m_File); 287 } 288 289 /* Get reference to file descriptor */ 290 inline const RTFILE &getFile() 291 { 292 return m_File; 293 } 294 295 /* Returns available space on storage. */ 296 inline uint64_t getAvailableSpace() 297 { 298 RTFOFF pcbFree; 299 int rc = RTFileQueryFsSizes(m_File, NULL, &pcbFree, 0, 0); 300 return (RT_SUCCESS(rc)? (uint64_t)pcbFree : UINT64_MAX); 301 } 302 303 /* Closes the file. */ 304 inline void close() 305 { 306 RTFileClose(m_File); 307 } 308 309 /* Starts an EBML sub-element. */ 310 inline Ebml &subStart(EbmlClassId classId) 311 { 312 writeClassId(classId); 313 /* store the current file offset. */ 314 m_Elements.push(EbmlSubElement(RTFileTell(m_File), classId)); 315 /* Indicates that size of the element 316 * is unkown (as according to EBML specs). 317 */ 318 writeUnsignedInteger(UINT64_C(0x01FFFFFFFFFFFFFF)); 319 return *this; 320 } 321 322 /* Ends an EBML sub-element. */ 323 inline Ebml &subEnd(EbmlClassId classId) 324 { 325 /* Class ID on the top of the stack should match the class ID passed 326 * to the function. Otherwise it may mean that we have a bug in the code. 327 */ 328 if(m_Elements.empty() || m_Elements.top().classId != classId) throw VERR_INTERNAL_ERROR; 329 330 uint64_t uPos = RTFileTell(m_File); 331 uint64_t uSize = uPos - m_Elements.top().offset - 8; 332 RTFileSeek(m_File, m_Elements.top().offset, RTFILE_SEEK_BEGIN, NULL); 333 334 /* make sure that size will be serialized as uint64 */ 335 writeUnsignedInteger(uSize | UINT64_C(0x0100000000000000)); 336 RTFileSeek(m_File, uPos, RTFILE_SEEK_BEGIN, NULL); 337 m_Elements.pop(); 338 return *this; 339 } 340 341 /* Serializes a null-terminated string. */ 342 inline Ebml &serializeString(EbmlClassId classId, const char *str) 343 { 344 writeClassId(classId); 345 uint64_t size = strlen(str); 346 writeSize(size); 347 write(str, size); 348 return *this; 349 } 350 351 /* Serializes an UNSIGNED integer 352 * If size is zero then it will be detected automatically. */ 353 inline Ebml &serializeUnsignedInteger(EbmlClassId classId, uint64_t parm, size_t size = 0) 354 { 355 writeClassId(classId); 356 if (!size) size = getSizeOfUInt(parm); 357 writeSize(size); 358 writeUnsignedInteger(parm, size); 359 return *this; 360 } 361 362 /* Serializes a floating point value. 363 * Only 8-bytes double precision values are supported 364 * by this function. 365 */ 366 inline Ebml &serializeFloat(EbmlClassId classId, double value) 367 { 368 writeClassId(classId); 369 writeSize(sizeof(double)); 370 writeUnsignedInteger(*reinterpret_cast<uint64_t*>(&value)); 371 return *this; 372 } 373 374 /* Writes raw data to file. */ 375 inline void write(const void *data, size_t size) 376 { 377 int rc = RTFileWrite(m_File, data, size, NULL); 378 if (!RT_SUCCESS(rc)) throw rc; 379 } 380 381 /* Writes an unsigned integer of variable of fixed size. */ 382 inline void writeUnsignedInteger(uint64_t value, size_t size = sizeof(uint64_t)) 383 { 384 /* convert to big-endian */ 385 value = RT_H2BE_U64(value); 386 write(reinterpret_cast<uint8_t*>(&value) + sizeof(value) - size, size); 387 } 388 389 /* Writes EBML class ID to file. 390 * EBML ID already has a UTF8-like represenation 391 * so getSizeOfUInt is used to determine 392 * the number of its bytes. 393 */ 394 inline void writeClassId(EbmlClassId parm) 395 { 396 writeUnsignedInteger(parm, getSizeOfUInt(parm)); 397 } 398 399 /* Writes data size value. */ 400 inline void writeSize(uint64_t parm) 401 { 402 /* The following expression defines the size of the value that will be serialized 403 * as an EBML UTF-8 like integer (with trailing bits represeting its size): 404 1xxx xxxx - value 0 to 2^7-2 405 01xx xxxx xxxx xxxx - value 0 to 2^14-2 406 001x xxxx xxxx xxxx xxxx xxxx - value 0 to 2^21-2 407 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^28-2 408 0000 1xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^35-2 409 0000 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^42-2 410 0000 001x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^49-2 411 0000 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^56-2 412 */ 413 size_t size = 8 - ! (parm & (UINT64_MAX << 49)) - ! (parm & (UINT64_MAX << 42)) - 414 ! (parm & (UINT64_MAX << 35)) - ! (parm & (UINT64_MAX << 28)) - 415 ! (parm & (UINT64_MAX << 21)) - ! (parm & (UINT64_MAX << 14)) - 416 ! (parm & (UINT64_MAX << 7)); 417 /* One is subtracted in order to avoid loosing significant bit when size = 8. */ 418 uint64_t mask = RT_BIT_64(size * 8 - 1); 419 writeUnsignedInteger((parm & (((mask << 1) - 1) >> size)) | (mask >> (size - 1)), size); 420 } 421 /* Size calculation for variable size UNSIGNED integer. 422 * The function defines the size of the number by trimming 423 * consequent trailing zero bytes starting from the most significant. 424 * The following statement is always true: 425 * 1 <= getSizeOfUInt(arg) <= 8. 426 * 427 * Every !(arg & (UINT64_MAX << X)) expression gives one 428 * if an only if all the bits from X to 63 are set to zero. 429 */ 430 static inline size_t getSizeOfUInt(uint64_t arg) 431 { 432 return 8 - ! (arg & (UINT64_MAX << 56)) - ! (arg & (UINT64_MAX << 48)) - 433 ! (arg & (UINT64_MAX << 40)) - ! (arg & (UINT64_MAX << 32)) - 434 ! (arg & (UINT64_MAX << 24)) - ! (arg & (UINT64_MAX << 16)) - 435 ! (arg & (UINT64_MAX << 8)); 436 } 437 438 private: 439 void operator=(const Ebml &); 440 441 }; 442 443 class WebMWriter_Impl 444 { 445 446 struct CueEntry 447 { 448 uint32_t time; 449 uint64_t loc; 450 CueEntry(uint32_t t, uint64_t l) : time(t), loc(l) {} 451 }; 452 453 bool m_bDebug; 454 int64_t m_iLastPtsMs; 455 int64_t m_iInitialPtsMs; 456 vpx_rational_t m_Framerate; 457 458 uint64_t m_uPositionReference; 459 uint64_t m_uSeekInfoPos; 460 uint64_t m_uSegmentInfoPos; 461 uint64_t m_uTrackPos; 462 uint64_t m_uCuePos; 463 uint64_t m_uClusterPos; 464 465 uint64_t m_uTrackIdPos; 466 467 uint64_t m_uStartSegment; 468 469 uint32_t m_uClusterTimecode; 470 bool m_bClusterOpen; 471 472 std::list<CueEntry> m_CueList; 473 474 Ebml m_Ebml; 475 476 public: 477 478 WebMWriter_Impl::WebMWriter_Impl() : 479 m_bDebug(false), 480 m_iLastPtsMs(-1), 481 m_iInitialPtsMs(-1), 482 m_Framerate(), 483 m_uPositionReference(0), 484 m_uSeekInfoPos(0), 485 m_uSegmentInfoPos(0), 486 m_uTrackPos(0), 487 m_uCuePos(0), 488 m_uClusterPos(0), 489 m_uTrackIdPos(0), 490 m_uStartSegment(0), 491 m_uClusterTimecode(0), 492 m_bClusterOpen(false) {} 493 494 void writeHeader(const vpx_codec_enc_cfg_t *a_pCfg, 495 const struct vpx_rational *a_pFps) 496 { 123 497 m_Ebml.subStart(EBML) 124 498 .serializeUnsignedInteger(EBMLVersion, 1) … … 133 507 m_Ebml.subStart(Segment); 134 508 135 m_uPositionReference = RTFileTell(m_ File);509 m_uPositionReference = RTFileTell(m_Ebml.getFile()); 136 510 m_Framerate = *a_pFps; 137 511 138 512 writeSeekInfo(); 139 513 140 m_uTrackPos = RTFileTell(m_ File);514 m_uTrackPos = RTFileTell(m_Ebml.getFile()); 141 515 142 516 m_Ebml.subStart(Tracks) … … 144 518 .serializeUnsignedInteger(TrackNumber, 1); 145 519 146 m_uTrackIdPos = RTFileTell(m_ File);520 m_uTrackIdPos = RTFileTell(m_Ebml.getFile()); 147 521 148 522 m_Ebml.serializeUnsignedInteger(TrackUID, 0, 4) … … 156 530 .subEnd(TrackEntry) 157 531 .subEnd(Tracks); 158 159 } 160 catch(int rc) 161 { 162 return rc; 163 } 164 return VINF_SUCCESS; 165 } 166 167 int WebMWriter::writeBlock(const vpx_codec_enc_cfg_t *a_pCfg, 168 const vpx_codec_cx_pkt_t *a_pPkt) 169 { 170 try 532 } 533 534 void writeBlock(const vpx_codec_enc_cfg_t *a_pCfg, 535 const vpx_codec_cx_pkt_t *a_pPkt) 171 536 { 172 537 uint16_t uBlockTimecode = 0; … … 200 565 m_bClusterOpen = true; 201 566 m_uClusterTimecode = (uint32_t)iPtsMs; 202 m_uClusterPos = RTFileTell(m_ File);567 m_uClusterPos = RTFileTell(m_Ebml.getFile()); 203 568 m_Ebml.subStart(Cluster) 204 569 .serializeUnsignedInteger(Timecode, m_uClusterTimecode); … … 220 585 m_Ebml.write(a_pPkt->data.frame.buf, a_pPkt->data.frame.sz); 221 586 } 222 catch(int rc) 223 { 224 return rc; 225 } 226 return VINF_SUCCESS; 227 } 228 229 int WebMWriter::writeFooter(uint32_t a_u64Hash) 230 { 231 try 587 588 void writeFooter(uint32_t a_u64Hash) 232 589 { 233 590 if (m_bClusterOpen) 234 591 m_Ebml.subEnd(Cluster); 235 592 236 m_uCuePos = RTFileTell(m_ File);593 m_uCuePos = RTFileTell(m_Ebml.getFile()); 237 594 m_Ebml.subStart(Cues); 238 595 for (std::list<CueEntry>::iterator it = m_CueList.begin(); it != m_CueList.end(); ++it) … … 252 609 writeSeekInfo(); 253 610 254 int rc = RTFileSeek(m_ File, m_uTrackIdPos, RTFILE_SEEK_BEGIN, NULL);611 int rc = RTFileSeek(m_Ebml.getFile(), m_uTrackIdPos, RTFILE_SEEK_BEGIN, NULL); 255 612 if (!RT_SUCCESS(rc)) throw rc; 256 613 257 614 m_Ebml.serializeUnsignedInteger(TrackUID, (m_bDebug ? 0xDEADBEEF : a_u64Hash), 4); 258 615 259 rc = RTFileSeek(m_ File, 0, RTFILE_SEEK_END, NULL);616 rc = RTFileSeek(m_Ebml.getFile(), 0, RTFILE_SEEK_END, NULL); 260 617 if (!RT_SUCCESS(rc)) throw rc; 618 } 619 620 friend class WebMWriter; 621 622 private: 623 624 void writeSeekInfo() 625 { 626 uint64_t uPos = RTFileTell(m_Ebml.getFile()); 627 if (m_uSeekInfoPos) 628 RTFileSeek(m_Ebml.getFile(), m_uSeekInfoPos, RTFILE_SEEK_BEGIN, NULL); 629 else 630 m_uSeekInfoPos = uPos; 631 632 m_Ebml.subStart(SeekHead) 633 634 .subStart(Seek) 635 .serializeUnsignedInteger(SeekID, Tracks) 636 .serializeUnsignedInteger(SeekPosition, m_uTrackPos - m_uPositionReference, 8) 637 .subEnd(Seek) 638 639 .subStart(Seek) 640 .serializeUnsignedInteger(SeekID, Cues) 641 .serializeUnsignedInteger(SeekPosition, m_uCuePos - m_uPositionReference, 8) 642 .subEnd(Seek) 643 644 .subStart(Seek) 645 .serializeUnsignedInteger(SeekID, Info) 646 .serializeUnsignedInteger(SeekPosition, m_uSegmentInfoPos - m_uPositionReference, 8) 647 .subEnd(Seek) 648 649 .subEnd(SeekHead); 650 651 int64_t iFrameTime = (int64_t)1000 * m_Framerate.den / m_Framerate.num; 652 m_uSegmentInfoPos = RTFileTell(m_Ebml.getFile()); 653 654 char szVersion[64]; 655 RTStrPrintf(szVersion, sizeof(szVersion), "vpxenc%s", 656 m_bDebug ? "" : vpx_codec_version_str()); 657 658 m_Ebml.subStart(Info) 659 .serializeUnsignedInteger(TimecodeScale, 1000000) 660 .serializeFloat(Segment_Duration, m_iLastPtsMs + iFrameTime - m_iInitialPtsMs) 661 .serializeString(MuxingApp, szVersion) 662 .serializeString(WritingApp, szVersion) 663 .subEnd(Info); 664 } 665 }; 666 667 WebMWriter::WebMWriter() : m_Impl(new WebMWriter_Impl()) {} 668 669 WebMWriter::~WebMWriter() 670 { 671 delete m_Impl; 672 } 673 674 int WebMWriter::create(const char *a_pszFilename) 675 { 676 return m_Impl->m_Ebml.create(a_pszFilename); 677 } 678 679 void WebMWriter::close() 680 { 681 m_Impl->m_Ebml.close(); 682 } 683 684 int WebMWriter::writeHeader(const vpx_codec_enc_cfg_t *a_pCfg, const vpx_rational *a_pFps) 685 { 686 try 687 { 688 m_Impl->writeHeader(a_pCfg, a_pFps); 261 689 } 262 690 catch(int rc) … … 266 694 return VINF_SUCCESS; 267 695 } 696 697 int WebMWriter::writeBlock(const vpx_codec_enc_cfg_t *a_pCfg, const vpx_codec_cx_pkt_t *a_pPkt) 698 { 699 try 700 { 701 m_Impl->writeBlock(a_pCfg, a_pPkt); 702 } 703 catch(int rc) 704 { 705 return rc; 706 } 707 return VINF_SUCCESS; 708 } 709 710 int WebMWriter::writeFooter(uint32_t a_u64Hash) 711 { 712 try 713 { 714 m_Impl->writeFooter(a_u64Hash); 715 } 716 catch(int rc) 717 { 718 return rc; 719 } 720 return VINF_SUCCESS; 721 } 722 723 uint64_t WebMWriter::getFileSize() 724 { 725 return m_Impl->m_Ebml.getFileSize(); 726 } 727 728 uint64_t WebMWriter::getAvailableSpace() 729 { 730 return m_Impl->m_Ebml.getAvailableSpace(); 731 } -
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 &); -
trunk/src/VBox/Main/src-client/VideoRec.cpp
r52383 r52791 22 22 #include <iprt/semaphore.h> 23 23 #include <iprt/thread.h> 24 #include <iprt/time.h> 24 25 25 26 #include <VBox/com/VirtualBox.h> … … 443 444 for (unsigned uScreen = 0; uScreen < cScreens; uScreen++) 444 445 { 445 /* Since we allocate without using standard c++ new mechanism446 /* Since we allocate without using standard C++ new mechanism 446 447 * it is required to call placement new for correct initialization 447 * of some members*/448 * of the object. */ 448 449 new (&pCtx->Strm[uScreen] + RT_OFFSETOF(VIDEORECSTREAM, Ebml)) WebMWriter(); 449 450 } … … 621 622 pStrm->pu8RgbBuf = NULL; 622 623 } 623 /* explicit deinitilization of Ebml object since it was create using placement new*/624 /* Explicitly deinitilize Ebml object since it was created using placement new. */ 624 625 pStrm->Ebml.~WebMWriter(); 625 626 }
Note:
See TracChangeset
for help on using the changeset viewer.