Changeset 65256 in vbox for trunk/src/VBox
- Timestamp:
- Jan 12, 2017 11:11:03 AM (8 years ago)
- Location:
- trunk/src/VBox/Main/src-client
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-client/DrvAudioVideoRec.cpp
r65212 r65256 33 33 #include <iprt/mem.h> 34 34 #include <iprt/cdefs.h> 35 #include <iprt/circbuf.h>36 35 37 36 #include <VBox/vmm/pdmaudioifs.h> … … 90 89 uint64_t old_ticks; 91 90 uint64_t cSamplesSentPerSec; 92 /** Codec data.91 /** Codec-specific data. 93 92 * As every stream can be different, one codec per stream is needed. */ 94 93 AVRECCODEC Codec; 94 /** (Audio) frame buffer. */ 95 uint8_t *pvFrameBuf; 96 size_t cbFrameBufSize; 97 size_t cbFrameBufUsed; 98 size_t offFrameBufRead; 99 size_t offFrameBufWrite; 95 100 } AVRECSTREAMOUT, *PAVRECSTREAMOUT; 96 101 … … 133 138 if (RT_SUCCESS(rc)) 134 139 { 135 OpusEncoder *pEnc = NULL; 136 137 int orc; 138 pEnc = opus_encoder_create(48000 /* Hz */, 2 /* Stereo */, OPUS_APPLICATION_AUDIO, &orc); 139 if (orc != OPUS_OK) 140 size_t cbFrameBuf = sizeof(uint8_t) * _8K; /** @todo Make this configurable */ 141 142 pStreamOut->pvFrameBuf = (uint8_t *)RTMemAlloc(cbFrameBuf); 143 if (pStreamOut->pvFrameBuf) 140 144 { 141 LogRel(("VideoRec: Audio codec failed to initialize: %s\n", opus_strerror(orc))); 142 return VERR_AUDIO_BACKEND_INIT_FAILED; 143 } 144 145 AssertPtr(pEnc); 146 147 orc = opus_encoder_ctl(pEnc, OPUS_SET_BITRATE(pCfgReq->uHz)); 148 if (orc != OPUS_OK) 149 { 150 LogRel(("VideoRec: Audio codec failed to set bitrate: %s\n", opus_strerror(orc))); 151 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 152 } 153 else 154 { 155 pStreamOut->Codec.Opus.pEnc = pEnc; 156 157 if (pCfgAcq) 158 pCfgAcq->cSampleBufferSize = _4K; /** @todo Make this configurable. */ 145 pStreamOut->cbFrameBufSize = cbFrameBuf; 146 pStreamOut->cbFrameBufUsed = 0; 147 pStreamOut->offFrameBufRead = 0; 148 pStreamOut->offFrameBufWrite = 0; 149 150 OpusEncoder *pEnc = NULL; 151 152 int orc; 153 pEnc = opus_encoder_create(48000 /* Hz */, 2 /* Stereo */, OPUS_APPLICATION_AUDIO, &orc); 154 if (orc != OPUS_OK) 155 { 156 LogRel(("VideoRec: Audio codec failed to initialize: %s\n", opus_strerror(orc))); 157 return VERR_AUDIO_BACKEND_INIT_FAILED; 158 } 159 160 AssertPtr(pEnc); 161 162 #if 0 163 orc = opus_encoder_ctl(pEnc, OPUS_SET_BITRATE(DrvAudioHlpCalcBitrate())); 164 if (orc != OPUS_OK) 165 { 166 LogRel(("VideoRec: Audio codec failed to set bitrate: %s\n", opus_strerror(orc))); 167 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 168 } 169 else 170 { 171 #endif 172 pStreamOut->Codec.Opus.pEnc = pEnc; 173 174 if (pCfgAcq) 175 pCfgAcq->cSampleBufferSize = _4K; /** @todo Make this configurable. */ 176 // } 159 177 } 160 178 } … … 205 223 { 206 224 pThis->pEBML = new WebMWriter(); 207 rc = pThis->pEBML->create("/tmp/test.webm", RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE, 208 WebMWriter::Mode_Audio, /** @todo Fix path! */ 225 rc = pThis->pEBML->Create("/tmp/acap.webm", RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE, /** @todo Fix path! */ 209 226 WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_None); 227 if (RT_SUCCESS(rc)) 228 rc = pThis->pEBML->AddAudioTrack(44100.0, 44100, 2, 16); 210 229 break; 211 230 } … … 257 276 */ 258 277 static DECLCALLBACK(int) drvAudioVideoRecStreamPlay(PPDMIHOSTAUDIO pInterface, 259 PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 278 PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, 279 uint32_t *pcbWritten) 260 280 { 261 281 RT_NOREF2(pvBuf, cbBuf); … … 291 311 292 312 /* 293 * Call the encoder serverwith the data.313 * Call the encoder with the data. 294 314 */ 295 uint32_t cReadTotal = 0; 296 297 uint 8_t abDst[_4K];298 opus_int32 cbDst = (opus_int32)sizeof(abDst);299 300 PPDMAUDIOSAMPLE pSamples;301 uint32_t cRead;302 int rc = AudioMixBufAcquire(&pStream->MixBuf, cSamplesToSend,303 &pSamples, &cRead);304 if ( RT_SUCCESS(rc)305 && cRead)306 { 307 cReadTotal = cRead;308 309 opus_int32 orc = opus_encode(pStreamOut->Codec.Opus.pEnc, (opus_int16 *)pSamples, cRead, abDst, cbDst);310 if (orc != OPUS_OK)311 LogFunc(("Encoding (1) failed: %s\n", opus_strerror(orc)));312 313 if ( rc == VINF_TRY_AGAIN)315 316 /** @todo For now we ASSUME 25 FPS. */ 317 uint16_t csFrameSize = /*pStreamOut->Props.uHz*/ 48000 / 25; 318 size_t cbFrameSize = AUDIOMIXBUF_S2B(&pStream->MixBuf, csFrameSize); 319 320 uint32_t csRead = 0; 321 int rc = AudioMixBufReadCirc(&pStream->MixBuf, (uint8_t *)&pStreamOut->pvFrameBuf[pStreamOut->offFrameBufWrite], 322 pStreamOut->cbFrameBufSize - pStreamOut->offFrameBufWrite, &csRead); 323 if (RT_SUCCESS(rc)) 324 { 325 const uint32_t cbRead = AUDIOMIXBUF_S2B(&pStream->MixBuf, csRead); 326 327 pStreamOut->offFrameBufWrite = 328 (pStreamOut->offFrameBufWrite + cbRead) % pStreamOut->cbFrameBufSize; 329 Assert(pStreamOut->offFrameBufWrite <= pStreamOut->cbFrameBufSize); 330 pStreamOut->cbFrameBufUsed += cbRead; 331 Assert(pStreamOut->cbFrameBufUsed <= pStreamOut->cbFrameBufSize); 332 333 if (pStreamOut->cbFrameBufUsed >= cbFrameSize) 314 334 { 315 rc = AudioMixBufAcquire(&pStream->MixBuf, cSamplesToSend - cRead, 316 &pSamples, &cRead); 317 318 319 320 cReadTotal += cRead; 335 /* Opus always encodes PER FRAME, that is, 2.5, 5, 10, 20, 40 or 60 ms of audio data. */ 336 uint8_t abDst[_4K]; 337 size_t cbDst = sizeof(abDst); 338 339 /* Call the encoder to encode our input samples. */ 340 opus_int32 cbWritten = opus_encode(pStreamOut->Codec.Opus.pEnc, 341 (opus_int16 *)&pStreamOut->pvFrameBuf[pStreamOut->offFrameBufRead], 342 csFrameSize, abDst, cbDst); 343 if (cbWritten > 0) 344 { 345 pStreamOut->offFrameBufRead = (pStreamOut->offFrameBufRead + cbWritten) % pStreamOut->cbFrameBufSize; 346 Assert(pStreamOut->cbFrameBufUsed >= cbFrameSize); 347 pStreamOut->cbFrameBufUsed -= cbFrameSize; 348 349 /* Call the WebM writer to actually write the encoded audio data. */ 350 WebMWriter::BlockData_Opus blockData = { abDst, cbDst }; 351 rc = pThis->pEBML->WriteBlock(WebMWriter::BlockType_Audio, &blockData, sizeof(blockData)); 352 AssertRC(rc); 353 } 354 else if (cbWritten < 0) 355 AssertMsgFailed(("Encoding failed: %s\n", opus_strerror(cbWritten))); 321 356 } 322 357 } 323 358 324 AudioMixBufFinish(&pStream->MixBuf, cSamplesToSend); 359 if (csRead) 360 AudioMixBufFinish(&pStream->MixBuf, csRead); 325 361 326 362 /* … … 329 365 */ 330 366 if (pcbWritten) 331 *pcbWritten = c ReadTotal;332 333 LogFlowFunc(("c ReadTotal=%RU32, rc=%Rrc\n", cReadTotal, rc));367 *pcbWritten = csRead; 368 369 LogFlowFunc(("csRead=%RU32, rc=%Rrc\n", csRead, rc)); 334 370 return rc; 335 371 } … … 341 377 RT_NOREF(pThis); 342 378 PAVRECSTREAMOUT pStreamOut = (PAVRECSTREAMOUT)pStream; 379 380 if (pStreamOut->pvFrameBuf) 381 { 382 Assert(pStreamOut->cbFrameBufSize); 383 RTMemFree(pStreamOut->pvFrameBuf); 384 pStreamOut->pvFrameBuf = NULL; 385 } 343 386 344 387 if (pStreamOut->Codec.Opus.pEnc) … … 386 429 if (pThis->pEBML) 387 430 { 388 rc = pThis->pEBML->writeFooter(0 /* Hash */); 389 AssertRC(rc); 390 391 pThis->pEBML->close(); 431 pThis->pEBML->Close(); 392 432 393 433 delete pThis->pEBML; -
trunk/src/VBox/Main/src-client/EbmlWriter.cpp
r65212 r65256 19 19 #include <list> 20 20 #include <stack> 21 #include <iprt/string.h>22 #include <iprt/file.h>23 21 #include <iprt/asm.h> 24 22 #include <iprt/cdefs.h> 25 23 #include <iprt/err.h> 24 #include <iprt/file.h> 25 #include <iprt/rand.h> 26 #include <iprt/string.h> 27 26 28 #include <VBox/log.h> 29 27 30 #include "EbmlWriter.h" 28 31 #include "EbmlIDs.h" 32 #include "Logging.h" 29 33 30 34 … … 48 52 public: 49 53 54 Ebml(void) 55 : m_File(NIL_RTFILE) { } 56 57 virtual ~Ebml(void) { close(); } 58 59 public: 60 50 61 /** Creates EBML output file. */ 51 62 inline int create(const char *a_pszFilename, uint64_t fOpen) … … 55 66 56 67 /** Returns file size. */ 57 inline uint64_t getFileSize( )68 inline uint64_t getFileSize(void) 58 69 { 59 70 return RTFileTell(m_File); … … 61 72 62 73 /** Get reference to file descriptor */ 63 inline const RTFILE &getFile( )74 inline const RTFILE &getFile(void) 64 75 { 65 76 return m_File; … … 67 78 68 79 /** Returns available space on storage. */ 69 inline uint64_t getAvailableSpace( )80 inline uint64_t getAvailableSpace(void) 70 81 { 71 82 RTFOFF pcbFree; … … 75 86 76 87 /** Closes the file. */ 77 inline void close() 78 { 88 inline void close(void) 89 { 90 if (!isOpen()) 91 return; 92 93 AssertMsg(m_Elements.size() == 0, 94 ("%zu elements are not closed yet (next element to close is 0x%x)\n", 95 m_Elements.size(), m_Elements.top().classId)); 96 79 97 RTFileClose(m_File); 98 m_File = NIL_RTFILE; 99 } 100 101 /** 102 * Returns whether the file is open or not. 103 * 104 * @returns True if open, false if not. 105 */ 106 inline bool isOpen(void) 107 { 108 return RTFileIsValid(m_File); 80 109 } 81 110 … … 99 128 * to the function. Otherwise it may mean that we have a bug in the code. 100 129 */ 101 if(m_Elements.empty() || m_Elements.top().classId != classId) throw VERR_INTERNAL_ERROR; 130 AssertMsg(!m_Elements.empty(), ("No elements to close anymore\n")); 131 AssertMsg(m_Elements.top().classId == classId, 132 ("Ending sub element 0x%x is in wrong order (next to close is 0x%x)\n", classId, m_Elements.top().classId)); 102 133 103 134 uint64_t uPos = RTFileTell(m_File); … … 156 187 157 188 /** Writes raw data to file. */ 158 inline void write(const void *data, size_t size) 159 { 160 int rc = RTFileWrite(m_File, data, size, NULL); 161 if (!RT_SUCCESS(rc)) throw rc; 189 inline int write(const void *data, size_t size) 190 { 191 return RTFileWrite(m_File, data, size, NULL); 162 192 } 163 193 … … 229 259 class WebMWriter_Impl 230 260 { 231 struct CueEntry 232 { 261 /** 262 * Structure for keeping a cue entry. 263 */ 264 struct WebMCueEntry 265 { 266 WebMCueEntry(uint32_t t, uint64_t l) 267 : time(t), loc(l) {} 268 233 269 uint32_t time; 234 270 uint64_t loc; 235 CueEntry(uint32_t t, uint64_t l) : time(t), loc(l) {} 271 }; 272 273 /** 274 * Track type enumeration. 275 */ 276 enum WebMTrackType 277 { 278 /** Unknown / invalid type. */ 279 WebMTrackType_Invalid = 0, 280 /** Only writes audio. */ 281 WebMTrackType_Audio = 1, 282 /** Only writes video. */ 283 WebMTrackType_Video = 2 284 }; 285 286 /** 287 * Structure for keeping a track entry. 288 */ 289 struct WebMTrack 290 { 291 WebMTrack(WebMTrackType a_enmType, uint64_t a_offID) 292 : enmType(a_enmType) 293 , offID(a_offID) 294 { 295 uID = RTRandU32(); 296 } 297 298 /** The type of this track. */ 299 WebMTrackType enmType; 300 /** The track's UUID. */ 301 uint32_t uID; 302 /** Absolute offset in file of track ID. 303 * Needed to write the hash sum within the footer. */ 304 uint64_t offID; 236 305 }; 237 306 … … 243 312 struct OpusPrivData 244 313 { 245 uint8_t au8Head[8] 246 uint8_t u8Version 247 uint8_t c8Channels ;248 uint16_t u16PreSkip 249 uint32_t u32SampleRate ;250 uint16_t u16Gain 251 uint8_t u8Mapping _family = 0;314 uint8_t au8Head[8] = { 0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64 }; 315 uint8_t u8Version = 1; 316 uint8_t c8Channels = 0; 317 uint16_t u16PreSkip = 0; 318 uint32_t u32SampleRate = 0; 319 uint16_t u16Gain = 0; 320 uint8_t u8MappingFamily = 0; 252 321 }; 253 322 # pragma pack(pop) 254 323 #endif /* VBOX_WITH_AUDIO_VIDEOREC */ 255 324 256 /** Operation mode. */257 WebMWriter::Mode m_enmMode;258 325 /** Audio codec to use. */ 259 WebMWriter::AudioCodec m_enmAudioCodec;326 WebMWriter::AudioCodec m_enmAudioCodec; 260 327 /** Video codec to use. */ 261 WebMWriter::VideoCodec m_enmVideoCodec; 262 263 bool m_fDebug; 264 265 /** Timestamp of initial PTS (Presentation Time Stamp). */ 266 int64_t m_tsInitialPtsMs; 267 /** Timestamp of last written PTS (Presentation Time Stamp). */ 268 int64_t m_tsLastPtsMs; 269 270 vpx_rational_t m_Framerate; 328 WebMWriter::VideoCodec m_enmVideoCodec; 329 330 /** This PTS (Presentation Time Stamp) acts as our master clock for synchronizing streams. */ 331 uint64_t m_uPts; 332 /** Timestamp (in ms) of initial PTS. */ 333 int64_t m_tsInitialPtsMs; 334 /** Timestamp (in ms) of last written PTS. */ 335 int64_t m_tsLastPtsMs; 271 336 272 337 /** Start offset (in bytes) of current segment. */ 273 uint64_t m_offSegCurStart;338 uint64_t m_offSegCurStart; 274 339 275 340 /** Start offset (in bytes) of seeking info segment. */ 276 uint64_t m_offSegSeekInfoStart;277 /** Offset (in bytes) for current seek info element. */278 uint64_t m_offSeekInfo;341 uint64_t m_offSegSeekInfoStart; 342 /** Start offset (in bytes) of general info segment. */ 343 uint64_t m_offSegInfoStart; 279 344 280 345 /** Start offset (in bytes) of tracks segment. */ 281 uint64_t m_offSegTracksStart;346 uint64_t m_offSegTracksStart; 282 347 283 348 /** Absolute position of cue segment. */ 284 uint64_t m_uCuePos;349 uint64_t m_offSegCuesStart; 285 350 /** List of cue points. Needed for seeking table. */ 286 std::list<CueEntry> m_lstCue; 287 288 uint64_t m_uTrackIdPos; 351 std::list<WebMCueEntry> m_lstCue; 352 353 /** List of tracks. */ 354 std::list<WebMTrack> m_lstTracks; 355 bool m_fTracksOpen; 289 356 290 357 /** Timestamp (in ms) when the current cluster has been opened. */ 291 uint32_t m_tsClusterOpenMs;358 uint32_t m_tsClusterOpenMs; 292 359 /** Whether we're currently in an opened cluster segment. */ 293 bool m_fClusterOpen;360 bool m_fClusterOpen; 294 361 /** Absolute position (in bytes) of current cluster within file. 295 362 * Needed for seeking info table. */ 296 uint64_t m_offSegClusterStart;297 298 Ebml m_Ebml;363 uint64_t m_offSegClusterStart; 364 365 Ebml m_Ebml; 299 366 300 367 public: 301 368 302 369 WebMWriter_Impl() : 303 m_enmMode(WebMWriter::Mode_Unknown) 304 , m_fDebug(false) 370 m_uPts(0) 305 371 , m_tsInitialPtsMs(-1) 306 372 , m_tsLastPtsMs(-1) 307 , m_Framerate()308 373 , m_offSegCurStart(0) 309 374 , m_offSegSeekInfoStart(0) 310 , m_offSe ekInfo(0)375 , m_offSegInfoStart(0) 311 376 , m_offSegTracksStart(0) 312 , m_ uCuePos(0)313 , m_ uTrackIdPos(0)377 , m_offSegCuesStart(0) 378 , m_fTracksOpen(false) 314 379 , m_tsClusterOpenMs(0) 315 380 , m_fClusterOpen(false) 316 381 , m_offSegClusterStart(0) {} 317 382 318 void writeHeader(const vpx_codec_enc_cfg_t *a_pCfg, const struct vpx_rational *a_pFps) 319 { 383 int AddAudioTrack(float fSamplingHz, float fOutputHz, uint8_t cChannels, uint8_t cBitDepth) 384 { 385 m_Ebml.subStart(TrackEntry); 386 m_Ebml.serializeUnsignedInteger(TrackNumber, (uint8_t)m_lstTracks.size()); 387 /** @todo Implement track's "Language" property? Currently this defaults to English ("eng"). */ 388 389 WebMTrack TrackAudio(WebMTrackType_Audio, RTFileTell(m_Ebml.getFile())); 390 m_lstTracks.push_back(TrackAudio); 391 392 /** @todo Resolve codec type. */ 393 OpusPrivData opusPrivData; 394 395 m_Ebml.serializeUnsignedInteger(TrackUID, TrackAudio.uID, 4) 396 .serializeUnsignedInteger(TrackType, 2 /* Audio */) 397 .serializeString(CodecID, "A_OPUS") 398 .serializeData(CodecPrivate, &opusPrivData, sizeof(opusPrivData)) 399 .subStart(Audio) 400 .serializeFloat(SamplingFrequency, fSamplingHz) 401 .serializeFloat(OutputSamplingFrequency, fOutputHz) 402 .serializeUnsignedInteger(Channels, cChannels) 403 .serializeUnsignedInteger(BitDepth, cBitDepth) 404 .subEnd(Audio) 405 .subEnd(TrackEntry); 406 407 return VINF_SUCCESS; 408 } 409 410 int AddVideoTrack(uint16_t uWidth, uint16_t uHeight, double dbFPS) 411 { 412 m_Ebml.subStart(TrackEntry); 413 m_Ebml.serializeUnsignedInteger(TrackNumber, (uint8_t)m_lstTracks.size()); 414 415 WebMTrack TrackVideo(WebMTrackType_Video, RTFileTell(m_Ebml.getFile())); 416 m_lstTracks.push_back(TrackVideo); 417 418 /** @todo Resolve codec type. */ 419 420 m_Ebml.serializeUnsignedInteger(TrackUID, TrackVideo.uID /* UID */, 4) 421 .serializeUnsignedInteger(TrackType, 1 /* Video */) 422 .serializeString(CodecID, "V_VP8") 423 .subStart(Video) 424 .serializeUnsignedInteger(PixelWidth, uWidth) 425 .serializeUnsignedInteger(PixelHeight, uHeight) 426 .serializeFloat(FrameRate, dbFPS) 427 .subEnd(Video) 428 .subEnd(TrackEntry); 429 430 return VINF_SUCCESS; 431 } 432 433 int writeHeader(void) 434 { 435 LogFunc(("Header @ %RU64\n", RTFileTell(m_Ebml.getFile()))); 436 320 437 m_Ebml.subStart(EBML) 321 438 .serializeUnsignedInteger(EBMLVersion, 1) … … 330 447 m_Ebml.subStart(Segment); 331 448 332 m_Framerate = *a_pFps;333 334 449 /* Save offset of current segment. */ 335 450 m_offSegCurStart = RTFileTell(m_Ebml.getFile()); … … 340 455 m_offSegTracksStart = RTFileTell(m_Ebml.getFile()); 341 456 457 /* The tracks segment starts right after this header. */ 342 458 m_Ebml.subStart(Tracks); 343 344 /* Write video? */ 345 if ( m_enmMode == WebMWriter::Mode_Video 346 || m_enmMode == WebMWriter::Mode_AudioVideo) 347 { 348 /* 349 * Video track. 350 */ 351 m_Ebml.subStart(TrackEntry); 352 m_Ebml.serializeUnsignedInteger(TrackNumber, 1); 353 354 m_uTrackIdPos = RTFileTell(m_Ebml.getFile()); 355 356 m_Ebml.serializeUnsignedInteger(TrackUID, 0 /* UID */, 4) 357 .serializeUnsignedInteger(TrackType, 1 /* Video */) 358 .serializeString(CodecID, "V_VP8") 359 .subStart(Video) 360 .serializeUnsignedInteger(PixelWidth, a_pCfg->g_w) 361 .serializeUnsignedInteger(PixelHeight, a_pCfg->g_h) 362 .serializeFloat(FrameRate, (double) a_pFps->num / a_pFps->den) 363 .subEnd(Video) 364 .subEnd(TrackEntry); 365 } 366 367 #ifdef VBOX_WITH_AUDIO_VIDEOREC 368 if ( m_enmMode == WebMWriter::Mode_Audio 369 || m_enmMode == WebMWriter::Mode_AudioVideo) 370 { 371 /* 372 * Audio track. 373 */ 374 m_Ebml.subStart(TrackEntry); 375 m_Ebml.serializeUnsignedInteger(TrackNumber, 2); 376 /** @todo Implement track's "Language" property? Currently this defaults to English ("eng"). */ 377 378 OpusPrivData opusPrivData; 379 380 m_Ebml.serializeUnsignedInteger(TrackUID, 1 /* UID */, 4) 381 .serializeUnsignedInteger(TrackType, 2 /* Audio */) 382 .serializeString(CodecID, "A_OPUS") 383 .serializeData(CodecPrivate, &opusPrivData, sizeof(opusPrivData)) 384 .subStart(Audio) 385 .serializeFloat(SamplingFrequency, 44100.0) 386 .serializeFloat(OutputSamplingFrequency, 44100.0) 387 .serializeUnsignedInteger(Channels, 2) 388 .serializeUnsignedInteger(BitDepth, 16) 389 .subEnd(Audio) 390 .subEnd(TrackEntry); 391 } 392 #endif 393 394 m_Ebml.subEnd(Tracks); 395 } 396 397 void writeBlock(const vpx_codec_enc_cfg_t *a_pCfg, const vpx_codec_cx_pkt_t *a_pPkt) 459 m_fTracksOpen = true; 460 461 return VINF_SUCCESS; 462 } 463 464 int writeSimpleBlockInternal(uint8_t uTrackID, uint16_t uTimecode, const void *pvData, size_t cbData, uint8_t fFlags) 465 { 466 LogFunc(("SimpleBlock @ %RU64 (T%RU8, TS=%RU16, %zu bytes)\n", RTFileTell(m_Ebml.getFile()), uTrackID, uTimecode, cbData)); 467 468 /* Write a "Simple Block". */ 469 m_Ebml.writeClassId(SimpleBlock); 470 /* Block size. */ 471 m_Ebml.writeUnsignedInteger(0x10000000u | (1 /* Track number. */ 472 + 2 /* Timecode .*/ 473 + 1 /* Flags. */ 474 + cbData /* Actual frame data. */), 4); 475 /* Track number. */ 476 m_Ebml.writeSize(uTrackID); 477 /* Timecode (relative to cluster opening timecode). */ 478 m_Ebml.writeUnsignedInteger(uTimecode, 2); 479 /* Flags. */ 480 m_Ebml.writeUnsignedInteger(fFlags, 1); 481 /* Frame data. */ 482 m_Ebml.write(pvData, cbData); 483 484 return VINF_SUCCESS; 485 } 486 487 int writeBlockVP8(const vpx_codec_enc_cfg_t *a_pCfg, const vpx_codec_cx_pkt_t *a_pPkt) 398 488 { 399 489 /* Calculate the PTS of this frame in milliseconds. */ 400 int64_t iPtsMs = a_pPkt->data.frame.pts * 1000401 * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den;402 403 if ( iPtsMs <= m_tsLastPtsMs)404 iPtsMs = m_tsLastPtsMs + 1;405 406 m_tsLastPtsMs = iPtsMs;490 int64_t tsPtsMs = a_pPkt->data.frame.pts * 1000 491 * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den; 492 493 if (tsPtsMs <= m_tsLastPtsMs) 494 tsPtsMs = m_tsLastPtsMs + 1; 495 496 m_tsLastPtsMs = tsPtsMs; 407 497 408 498 if (m_tsInitialPtsMs < 0) 409 m_tsInitialPtsMs = m_tsLastPtsMs;499 m_tsInitialPtsMs = m_tsLastPtsMs; 410 500 411 501 /* Calculate the relative time of this block. */ 412 uint16_t uBlockTimecode= 0;413 bool fClusterStart 414 415 if ( iPtsMs - m_tsClusterOpenMs > 65536)502 uint16_t tsBlockMs = 0; 503 bool fClusterStart = false; 504 505 if (tsPtsMs - m_tsClusterOpenMs > 65536) 416 506 fClusterStart = true; 417 507 else 418 uBlockTimecode = static_cast<uint16_t>(iPtsMs - m_tsClusterOpenMs); 419 420 bool fKeyframe = RT_BOOL(a_pPkt->data.frame.flags & VPX_FRAME_IS_KEY); 508 { 509 /* Calculate the block's timecode, which is relative to the Cluster timecode. */ 510 tsBlockMs = static_cast<uint16_t>(tsPtsMs - m_tsClusterOpenMs); 511 } 512 513 const bool fKeyframe = RT_BOOL(a_pPkt->data.frame.flags & VPX_FRAME_IS_KEY); 421 514 422 515 if ( fClusterStart 423 516 || fKeyframe) 424 517 { 425 if (m_fClusterOpen) 518 if (m_fClusterOpen) /* Close current cluster first. */ 426 519 m_Ebml.subEnd(Cluster); 427 520 521 tsBlockMs = 0; 522 428 523 /* Open a new cluster. */ 429 uBlockTimecode = 0; 430 m_fClusterOpen = true; 431 m_tsClusterOpenMs = (uint32_t)iPtsMs; 524 m_fClusterOpen = true; 525 m_tsClusterOpenMs = (uint32_t)tsPtsMs; 432 526 m_offSegClusterStart = RTFileTell(m_Ebml.getFile()); 527 528 LogFunc(("Cluster @ %RU64\n", m_offSegClusterStart)); 529 433 530 m_Ebml.subStart(Cluster) 434 531 .serializeUnsignedInteger(Timecode, m_tsClusterOpenMs); … … 437 534 if (fKeyframe) 438 535 { 439 CueEntry cue(m_tsClusterOpenMs, m_offSegClusterStart);536 WebMCueEntry cue(m_tsClusterOpenMs, m_offSegClusterStart); 440 537 m_lstCue.push_back(cue); 441 538 } 442 539 } 443 540 444 /* Write a "Simple Block". */ 445 m_Ebml.writeClassId(SimpleBlock); 446 m_Ebml.writeUnsignedInteger(0x10000000u | (4 + a_pPkt->data.frame.sz), 4); 447 m_Ebml.writeSize(1); 448 m_Ebml.writeUnsignedInteger(uBlockTimecode, 2); 449 m_Ebml.writeUnsignedInteger((fKeyframe ? 0x80 : 0) | (a_pPkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE ? 0x08 : 0), 1); 450 m_Ebml.write(a_pPkt->data.frame.buf, a_pPkt->data.frame.sz); 451 } 452 453 void writeFooter(uint32_t a_u64Hash) 454 { 541 uint8_t fFlags = 0; 542 if (fKeyframe) 543 fFlags |= 0x80; /* Key frame. */ 544 if (a_pPkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) 545 fFlags |= 0x08; /* Invisible frame. */ 546 547 return writeSimpleBlockInternal(0 /** @todo FIX! */, tsBlockMs, a_pPkt->data.frame.buf, a_pPkt->data.frame.sz, fFlags); 548 } 549 550 #ifdef VBOX_WITH_AUDIO_VIDEOREC 551 /* Audio blocks that have same absolute timecode as video blocks SHOULD be written before the video blocks. */ 552 int writeBlockOpus(const void *pvData, size_t cbData) 553 { 554 static uint16_t s_uTimecode = 0; 555 556 return writeSimpleBlockInternal(1 /** @todo FIX! */, s_uTimecode++, pvData, cbData, 0 /* Flags */); 557 } 558 #endif 559 560 int WriteBlock(WebMWriter::BlockType blockType, const void *pvData, size_t cbData) 561 { 562 int rc; 563 564 if (m_fTracksOpen) 565 { 566 m_Ebml.subEnd(Tracks); 567 m_fTracksOpen = false; 568 } 569 570 switch (blockType) 571 { 572 #ifdef VBOX_WITH_AUDIO_VIDEOREC 573 case WebMWriter::BlockType_Audio: 574 { 575 if (m_enmAudioCodec == WebMWriter::AudioCodec_Opus) 576 { 577 Assert(cbData == sizeof(WebMWriter::BlockData_Opus)); 578 WebMWriter::BlockData_Opus *pData = (WebMWriter::BlockData_Opus *)pvData; 579 rc = writeBlockOpus(pData->pvData, pData->cbData); 580 } 581 else 582 rc = VERR_NOT_SUPPORTED; 583 break; 584 } 585 #endif 586 case WebMWriter::BlockType_Video: 587 { 588 if (m_enmVideoCodec == WebMWriter::VideoCodec_VP8) 589 { 590 Assert(cbData == sizeof(WebMWriter::BlockData_VP8)); 591 WebMWriter::BlockData_VP8 *pData = (WebMWriter::BlockData_VP8 *)pvData; 592 rc = writeBlockVP8(pData->pCfg, pData->pPkt); 593 } 594 else 595 rc = VERR_NOT_SUPPORTED; 596 break; 597 } 598 599 default: 600 rc = VERR_NOT_SUPPORTED; 601 break; 602 } 603 604 return rc; 605 } 606 607 int writeFooter(void) 608 { 609 if (m_fTracksOpen) 610 { 611 m_Ebml.subEnd(Tracks); 612 m_fTracksOpen = false; 613 } 614 455 615 if (m_fClusterOpen) 616 { 456 617 m_Ebml.subEnd(Cluster); 457 458 m_uCuePos = RTFileTell(m_Ebml.getFile()); 618 m_fClusterOpen = false; 619 } 620 621 /* 622 * Write Cues segment. 623 */ 624 LogFunc(("Cues @ %RU64\n", RTFileTell(m_Ebml.getFile()))); 625 626 m_offSegCuesStart = RTFileTell(m_Ebml.getFile()); 627 459 628 m_Ebml.subStart(Cues); 460 for (std::list<CueEntry>::iterator it = m_lstCue.begin(); it != m_lstCue.end(); ++it) 629 630 for (std::list<WebMCueEntry>::iterator it = m_lstCue.begin(); it != m_lstCue.end(); ++it) 461 631 { 462 m_Ebml.subStart(CuePoint)463 .serializeUnsignedInteger(CueTime, it->time)464 .subStart(CueTrackPositions)465 .serializeUnsignedInteger(CueTrack, 1)466 .serializeUnsignedInteger(CueClusterPosition, it->loc - m_offSegCurStart, 8)467 .subEnd(CueTrackPositions)468 .subEnd(CuePoint);632 m_Ebml.subStart(CuePoint) 633 .serializeUnsignedInteger(CueTime, it->time) 634 .subStart(CueTrackPositions) 635 .serializeUnsignedInteger(CueTrack, 1) 636 .serializeUnsignedInteger(CueClusterPosition, it->loc - m_offSegCurStart, 8) 637 .subEnd(CueTrackPositions) 638 .subEnd(CuePoint); 469 639 } 470 640 … … 472 642 .subEnd(Segment); 473 643 644 /* 645 * Update SeekHead / Info segment. 646 */ 647 474 648 writeSeekInfo(); 475 649 476 int rc = RTFileSeek(m_Ebml.getFile(), m_uTrackIdPos, RTFILE_SEEK_BEGIN, NULL); 477 if (!RT_SUCCESS(rc)) throw rc; 478 479 m_Ebml.serializeUnsignedInteger(TrackUID, (m_fDebug ? 0xDEADBEEF : a_u64Hash), 4); 480 481 rc = RTFileSeek(m_Ebml.getFile(), 0, RTFILE_SEEK_END, NULL); 482 if (!RT_SUCCESS(rc)) throw rc; 483 } 484 650 return RTFileSeek(m_Ebml.getFile(), 0, RTFILE_SEEK_END, NULL); 651 } 652 653 friend class Ebml; 485 654 friend class WebMWriter; 486 655 … … 489 658 void writeSeekInfo(void) 490 659 { 491 uint64_t uPos = RTFileTell(m_Ebml.getFile());492 660 if (m_offSegSeekInfoStart) 493 661 RTFileSeek(m_Ebml.getFile(), m_offSegSeekInfoStart, RTFILE_SEEK_BEGIN, NULL); 494 662 else 495 m_offSegSeekInfoStart = uPos; 663 m_offSegSeekInfoStart = RTFileTell(m_Ebml.getFile()); 664 665 LogFunc(("SeekHead @ %RU64\n", m_offSegSeekInfoStart)); 496 666 497 667 m_Ebml.subStart(SeekHead) … … 504 674 .subStart(Seek) 505 675 .serializeUnsignedInteger(SeekID, Cues) 506 .serializeUnsignedInteger(SeekPosition, m_ uCuePos- m_offSegCurStart, 8)676 .serializeUnsignedInteger(SeekPosition, m_offSegCuesStart - m_offSegCurStart, 8) 507 677 .subEnd(Seek) 508 678 509 679 .subStart(Seek) 510 680 .serializeUnsignedInteger(SeekID, Info) 511 .serializeUnsignedInteger(SeekPosition, m_offSe ekInfo- m_offSegCurStart, 8)681 .serializeUnsignedInteger(SeekPosition, m_offSegInfoStart - m_offSegCurStart, 8) 512 682 .subEnd(Seek) 513 683 514 684 .subEnd(SeekHead); 515 685 516 int64_t iFrameTime = (int64_t)1000 * m_Framerate.den / m_Framerate.num; 517 m_offSeekInfo = RTFileTell(m_Ebml.getFile()); 686 int64_t iFrameTime = (int64_t)1000 * 1 / 25; //m_Framerate.den / m_Framerate.num; /** @todo Fix this! */ 687 m_offSegInfoStart = RTFileTell(m_Ebml.getFile()); 688 689 LogFunc(("Info @ %RU64\n", m_offSegInfoStart)); 518 690 519 691 char szVersion[64]; 520 RTStrPrintf(szVersion, sizeof(szVersion), "vpxenc%s", 521 m_fDebug ? "" : vpx_codec_version_str()); 692 RTStrPrintf(szVersion, sizeof(szVersion), "vpxenc%s", vpx_codec_version_str()); /** @todo Make this configurable? */ 522 693 523 694 m_Ebml.subStart(Info) … … 535 706 { 536 707 if (m_pImpl) 708 { 709 Close(); 537 710 delete m_pImpl; 711 } 538 712 } 539 713 540 int WebMWriter:: create(const char *a_pszFilename, uint64_t a_fOpen, WebMWriter::Mode a_enmMode,714 int WebMWriter::Create(const char *a_pszFilename, uint64_t a_fOpen, 541 715 WebMWriter::AudioCodec a_enmAudioCodec, WebMWriter::VideoCodec a_enmVideoCodec) 542 716 { 543 m_pImpl->m_enmMode = a_enmMode;544 m_pImpl->m_enmAudioCodec = a_enmAudioCodec;545 m_pImpl->m_enmVideoCodec = a_enmVideoCodec;546 547 return m_pImpl->m_Ebml.create(a_pszFilename, a_fOpen);548 }549 550 void WebMWriter::close(void)551 {552 m_pImpl->m_Ebml.close();553 }554 555 int WebMWriter::writeHeader(const vpx_codec_enc_cfg_t *a_pCfg, const vpx_rational *a_pFps)556 {557 717 try 558 718 { 559 m_pImpl->writeHeader(a_pCfg, a_pFps); 719 m_pImpl->m_enmAudioCodec = a_enmAudioCodec; 720 m_pImpl->m_enmVideoCodec = a_enmVideoCodec; 721 722 LogFunc(("Creating '%s'\n", a_pszFilename)); 723 724 int rc = m_pImpl->m_Ebml.create(a_pszFilename, a_fOpen); 725 if (RT_SUCCESS(rc)) 726 rc = m_pImpl->writeHeader(); 560 727 } 561 728 catch(int rc) … … 566 733 } 567 734 568 int WebMWriter::writeBlock(const vpx_codec_enc_cfg_t *a_pCfg, const vpx_codec_cx_pkt_t *a_pPkt) 569 { 735 int WebMWriter::Close(void) 736 { 737 if (!m_pImpl->m_Ebml.isOpen()) 738 return VINF_SUCCESS; 739 740 int rc = m_pImpl->writeFooter(); 741 742 /* Close the file in any case. */ 743 m_pImpl->m_Ebml.close(); 744 745 return rc; 746 } 747 748 int WebMWriter::AddAudioTrack(float fSamplingHz, float fOutputHz, uint8_t cChannels, uint8_t cBitDepth) 749 { 750 return m_pImpl->AddAudioTrack(fSamplingHz, fOutputHz, cChannels, cBitDepth); 751 } 752 753 int WebMWriter::AddVideoTrack(uint16_t uWidth, uint16_t uHeight, double dbFPS) 754 { 755 return m_pImpl->AddVideoTrack(uWidth, uHeight, dbFPS); 756 } 757 758 int WebMWriter::WriteBlock(WebMWriter::BlockType blockType, const void *pvData, size_t cbData) 759 { 760 int rc; 761 570 762 try 571 763 { 572 m_pImpl->writeBlock(a_pCfg, a_pPkt);573 } 574 catch(int rc )575 { 576 r eturn rc;577 } 578 return VINF_SUCCESS;764 rc = m_pImpl->WriteBlock(blockType, pvData, cbData); 765 } 766 catch(int rc2) 767 { 768 rc = rc2; 769 } 770 return rc; 579 771 } 580 772 581 int WebMWriter::writeFooter(uint32_t a_u64Hash) 582 { 583 try 584 { 585 m_pImpl->writeFooter(a_u64Hash); 586 } 587 catch(int rc) 588 { 589 return rc; 590 } 591 return VINF_SUCCESS; 592 } 593 594 uint64_t WebMWriter::getFileSize() 773 uint64_t WebMWriter::GetFileSize(void) 595 774 { 596 775 return m_pImpl->m_Ebml.getFileSize(); 597 776 } 598 777 599 uint64_t WebMWriter:: getAvailableSpace()778 uint64_t WebMWriter::GetAvailableSpace(void) 600 779 { 601 780 return m_pImpl->m_Ebml.getAvailableSpace(); -
trunk/src/VBox/Main/src-client/EbmlWriter.h
r65212 r65256 59 59 }; 60 60 61 struct BlockData 61 /** 62 * Block data for VP8-encoded video data. 63 */ 64 struct BlockData_VP8 62 65 { 63 void *pvData;64 size_t cbData;66 const vpx_codec_enc_cfg_t *pCfg; 67 const vpx_codec_cx_pkt_t *pPkt; 65 68 }; 66 69 67 70 /** 68 * Operation mode -- this specifies what to write.71 * Block data for Opus-encoded audio data. 69 72 */ 70 enum Mode73 struct BlockData_Opus 71 74 { 72 /** Unknown / invalid mode. */ 73 Mode_Unknown = 0, 74 /** Only writes audio. */ 75 Mode_Audio = 1, 76 /** Only writes video. */ 77 Mode_Video = 2, 78 /** Writes audio and video. */ 79 Mode_AudioVideo = 3 75 /** Pointer to encoded Opus audio data. */ 76 const void *pvData; 77 /** Size (in bytes) of encoded Opus audio data. */ 78 size_t cbData; 79 }; 80 81 /** 82 * Block type to write. 83 */ 84 enum BlockType 85 { 86 BlockType_Invalid = 0, 87 BlockType_Audio = 1, 88 BlockType_Video = 2, 89 BlockType_Raw = 3 80 90 }; 81 91 … … 90 100 * @param a_pszFilename Name of the file to create. 91 101 * @param a_fOpen File open mode of type RTFILE_O_. 92 * @param a_enmMode Operation mode.93 102 * @param a_enmAudioCodec Audio codec to use. 94 103 * @param a_enmVideoCodec Video codec to use. 95 104 * 96 105 * @returns VBox status code. */ 97 int create(const char *a_pszFilename, uint64_t a_fOpen, WebMWriter::Mode a_enmMode,106 int Create(const char *a_pszFilename, uint64_t a_fOpen, 98 107 WebMWriter::AudioCodec a_enmAudioCodec, WebMWriter::VideoCodec a_enmVideoCodec); 99 108 100 109 /** Closes output file. */ 101 void close();110 int Close(void); 102 111 103 /** 104 * Writes WebM header to file. 105 * Should be called before any writeBlock call. 106 * 107 * @param a_pCfg Pointer to VPX Codec configuration structure. 108 * @param a_pFps Framerate information (frames per second). 109 * 110 * @returns VBox status code. 111 */ 112 int writeHeader(const vpx_codec_enc_cfg_t *a_pCfg, const vpx_rational *a_pFps); 112 int AddAudioTrack(float fSamplingHz, float fOutputHz, uint8_t cChannels, uint8_t cBitDepth); 113 114 int AddVideoTrack(uint16_t uWidth, uint16_t uHeight, double dbFPS); 113 115 114 116 /** 115 117 * Writes a block of compressed data. 116 118 * 117 * @param a_pCfg Pointer to VPX Codec configuration structure. 118 * @param a_pPkt VPX data packet. 119 * @param blockType Block type to write. 120 * @param pvData Pointer to block data to write. 121 * @param cbData Size (in bytes) of block data to write. 119 122 * 120 123 * @returns VBox status code. 121 124 */ 122 int writeBlock(const vpx_codec_enc_cfg_t *a_pCfg, const vpx_codec_cx_pkt_t *a_pPkt); 123 124 /** 125 * Writes WebM footer. 126 * No other write functions should be called after this one. 127 * 128 * @param a_u64Hash Hash value for the data written. 129 * 130 * @returns VBox status code. 131 */ 132 int writeFooter(uint32_t a_u64Hash); 125 int WriteBlock(WebMWriter::BlockType blockType, const void *pvData, size_t cbData); 133 126 134 127 /** … … 137 130 * @returns File size in bytes. 138 131 */ 139 uint64_t getFileSize(void);132 uint64_t GetFileSize(void); 140 133 141 134 /** … … 144 137 * @returns Available storage free space. 145 138 */ 146 uint64_t getAvailableSpace(void);139 uint64_t GetAvailableSpace(void); 147 140 148 141 private: -
trunk/src/VBox/Main/src-client/VideoRec.cpp
r65224 r65256 578 578 { 579 579 AssertPtr(pStream->pEBML); 580 int rc = pStream->pEBML->writeFooter(0); 581 AssertRC(rc); 582 583 pStream->pEBML->close(); 580 pStream->pEBML->Close(); 584 581 585 582 vpx_img_free(&pStream->Codec.VPX.RawImage); … … 659 656 size_t pos = 0; 660 657 661 /* By default we enable both, video and audio recording (if available). */ 658 /* By default we enable everything (if available). */ 659 bool fHasVideoTrack = true; 662 660 #ifdef VBOX_WITH_AUDIO_VIDEOREC 663 WebMWriter::Mode enmMode = WebMWriter::Mode_AudioVideo; 664 #else 665 WebMWriter::Mode enmMode = WebMWriter::Mode_Video; 661 bool fHasAudioTrack = true; 666 662 #endif 667 663 668 do { 669 670 com::Utf8Str key, value; 671 pos = options.parseKeyValue(key, value, pos); 672 664 com::Utf8Str key, value; 665 while ((pos = options.parseKeyValue(key, value, pos)) != com::Utf8Str::npos) 666 { 673 667 if (key.compare("vc_quality", Utf8Str::CaseInsensitive) == 0) 674 668 { … … 687 681 else 688 682 { 689 LogRel(("VideoRec: Setting squality deadline to '%s'\n", value.c_str()));683 LogRel(("VideoRec: Setting quality deadline to '%s'\n", value.c_str())); 690 684 pStream->uEncoderDeadline = value.toUInt32(); 691 685 } 692 686 } 693 if (key.compare("vc_enabled", Utf8Str::CaseInsensitive) == 0)687 else if (key.compare("vc_enabled", Utf8Str::CaseInsensitive) == 0) 694 688 { 695 689 #ifdef VBOX_WITH_AUDIO_VIDEOREC 696 690 if (value.compare("false", Utf8Str::CaseInsensitive) == 0) /* Disable audio. */ 697 691 { 698 enmMode = WebMWriter::Mode_Audio;692 fHasVideoTrack = false; 699 693 LogRel(("VideoRec: Only audio will be recorded\n")); 700 694 } 701 695 #endif 702 696 } 703 if (key.compare("ac_enabled", Utf8Str::CaseInsensitive) == 0)697 else if (key.compare("ac_enabled", Utf8Str::CaseInsensitive) == 0) 704 698 { 705 699 #ifdef VBOX_WITH_AUDIO_VIDEOREC 706 700 if (value.compare("false", Utf8Str::CaseInsensitive)) /* Disable audio. */ 707 701 { 708 enmMode = WebMWriter::Mode_Video;702 fHasAudioTrack = false; 709 703 LogRel(("VideoRec: Only video will be recorded\n")); 710 704 } … … 714 708 LogRel(("VideoRec: Unknown option '%s' (value '%s'), skipping\n", key.c_str(), value.c_str())); 715 709 716 } while(pos != com::Utf8Str::npos);710 } /* while */ 717 711 718 712 uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE; … … 723 717 #endif 724 718 725 int rc = pStream->pEBML->create(pszFile, fOpen, enmMode, 726 WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_VP8); 719 int rc = pStream->pEBML->Create(pszFile, fOpen, WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_VP8); 727 720 if (RT_FAILURE(rc)) 728 721 { … … 745 738 pStream->uDelay = 1000 / uFps; 746 739 747 struct vpx_rational arg_framerate = { (int)uFps, 1 }; 748 rc = pStream->pEBML->writeHeader(&pStream->Codec.VPX.Config, &arg_framerate); 749 AssertRCReturn(rc, rc); 740 if (fHasVideoTrack) 741 { 742 rc = pStream->pEBML->AddVideoTrack(pStream->Codec.VPX.Config.g_w, /* Width */ 743 pStream->Codec.VPX.Config.g_h, /* Height */ 744 uFps); 745 if (RT_FAILURE(rc)) 746 { 747 LogRel(("VideoRec: Failed to add video track to output file '%s' (%Rrc)\n", pszFile, rc)); 748 return rc; 749 } 750 } 750 751 751 752 /* Initialize codec */ … … 762 763 return VERR_NO_MEMORY; 763 764 } 765 764 766 pStream->pu8YuvBuf = pStream->Codec.VPX.RawImage.planes[0]; 765 767 766 768 pCtx->fEnabled = true; 767 769 pStream->fEnabled = true; 770 768 771 return VINF_SUCCESS; 769 772 } … … 832 835 if (pCtx->uMaxFileSize > 0) 833 836 { 834 uint64_t sizeInMB = pStream->pEBML-> getFileSize() / (1024 * 1024);837 uint64_t sizeInMB = pStream->pEBML->GetFileSize() / (1024 * 1024); 835 838 if(sizeInMB >= pCtx->uMaxFileSize) 836 839 return true; 837 840 } 838 841 /* Check for available free disk space */ 839 if (pStream->pEBML-> getAvailableSpace() < 0x100000)842 if (pStream->pEBML->GetAvailableSpace() < 0x100000) 840 843 { 841 844 LogRel(("VideoRec: Not enough free storage space available, stopping video capture\n")); … … 873 876 for (;;) 874 877 { 875 const vpx_codec_cx_pkt_t *pkt = vpx_codec_get_cx_data(&pStream->Codec.VPX.CodecCtx, &iter); 876 if (!pkt) 877 break; 878 switch (pkt->kind) 878 const vpx_codec_cx_pkt_t *pPacket = vpx_codec_get_cx_data(&pStream->Codec.VPX.CodecCtx, &iter); 879 if (!pPacket) 880 break; 881 882 switch (pPacket->kind) 879 883 { 880 884 case VPX_CODEC_CX_FRAME_PKT: 881 rc = pStream->pEBML->writeBlock(&pStream->Codec.VPX.Config, pkt); 885 { 886 WebMWriter::BlockData_VP8 blockData { &pStream->Codec.VPX.Config, pPacket }; 887 rc = pStream->pEBML->WriteBlock(WebMWriter::BlockType_Video, &blockData, sizeof(blockData)); 882 888 break; 889 } 890 883 891 default: 884 LogFlow(("Unexpected CODEC Packet.\n"));892 LogFlow(("Unexpected CODEC packet kind %ld\n", pPacket->kind)); 885 893 break; 886 894 }
Note:
See TracChangeset
for help on using the changeset viewer.