Changeset 68453 in vbox for trunk/src/VBox/Main/src-client
- Timestamp:
- Aug 17, 2017 8:18:11 PM (8 years ago)
- svn:sync-xref-src-repo-rev:
- 117596
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-client/VideoRec.cpp
r68431 r68453 25 25 #include <iprt/asm.h> 26 26 #include <iprt/assert.h> 27 #include <iprt/critsect.h> 27 28 #include <iprt/semaphore.h> 28 29 #include <iprt/thread.h> … … 45 46 #endif /* VBOX_WITH_LIBVPX */ 46 47 47 static int videoRecEncodeAndWrite(PVIDEORECSTREAM pStrm); 48 static int videoRecRGBToYUV(PVIDEORECSTREAM pStrm); 48 struct VIDEORECVIDEOFRAME; 49 typedef struct VIDEORECVIDEOFRAME *PVIDEORECVIDEOFRAME; 50 51 static int videoRecEncodeAndWrite(PVIDEORECSTREAM pStream, PVIDEORECVIDEOFRAME pFrame); 52 static int videoRecRGBToYUV(uint32_t uPixelFormat, 53 uint8_t *paDst, uint32_t uDstWidth, uint32_t uDstHeight, 54 uint8_t *paSrc, uint32_t uSrcWidth, uint32_t uSrcHeight); 55 56 int videoRecStreamLock(PVIDEORECSTREAM pStream); 57 int videoRecStreamUnlock(PVIDEORECSTREAM pStream); 49 58 50 59 using namespace com; 60 61 #if 0 62 /** Enables support for encoding multiple audio / video data frames at once. */ 63 #define VBOX_VIDEOREC_WITH_QUEUE 64 #endif 65 #ifdef DEBUG_andy 66 /** Enables dumping audio / video data for debugging reasons. */ 67 # define VBOX_VIDEOREC_DUMP 68 #endif 51 69 52 70 /** … … 57 75 /** Not initialized. */ 58 76 VIDEORECSTS_UNINITIALIZED = 0, 59 /** Initialized, idle. */ 60 VIDEORECSTS_IDLE = 1, 61 /** Currently busy, delay termination. */ 62 VIDEORECSTS_BUSY = 2, 77 /** Initialized. */ 78 VIDEORECSTS_INITIALIZED = 1, 63 79 /** The usual 32-bit hack. */ 64 80 VIDEORECSTS_32BIT_HACK = 0x7fffffff … … 71 87 { 72 88 /** Unknown pixel format. */ 73 VIDEORECPIXELFMT_UNKNOWN = 0,89 VIDEORECPIXELFMT_UNKNOWN = 0, 74 90 /** RGB 24. */ 75 VIDEORECPIXELFMT_RGB24 = 1,91 VIDEORECPIXELFMT_RGB24 = 1, 76 92 /** RGB 24. */ 77 VIDEORECPIXELFMT_RGB32 = 2,93 VIDEORECPIXELFMT_RGB32 = 2, 78 94 /** RGB 565. */ 79 VIDEORECPIXELFMT_RGB565 = 3 95 VIDEORECPIXELFMT_RGB565 = 3, 96 /** The usual 32-bit hack. */ 97 VIDEORECPIXELFMT_32BIT_HACK = 0x7fffffff 80 98 }; 81 99 … … 83 101 * Structure for keeping specific video recording codec data. 84 102 */ 85 typedef struct VIDEOREC CODEC103 typedef struct VIDEORECVIDEOCODEC 86 104 { 87 105 union … … 91 109 { 92 110 /** VPX codec context. */ 93 vpx_codec_ctx_t C odecCtx;111 vpx_codec_ctx_t Ctx; 94 112 /** VPX codec configuration. */ 95 vpx_codec_enc_cfg_t C onfig;113 vpx_codec_enc_cfg_t Cfg; 96 114 /** VPX image context. */ 97 115 vpx_image_t RawImage; 116 /** Encoder deadline. */ 117 unsigned int uEncoderDeadline; 98 118 } VPX; 99 119 #endif /* VBOX_WITH_LIBVPX */ 100 120 }; 101 } VIDEORECCODEC, *PVIDEORECCODEC; 121 } VIDEORECVIDEOCODEC, *PVIDEORECVIDEOCODEC; 122 123 /** 124 * Structure for keeping a single video recording video frame. 125 */ 126 typedef struct VIDEORECVIDEOFRAME 127 { 128 /** X resolution of this frame. */ 129 uint32_t uWidth; 130 /** Y resolution of this frame. */ 131 uint32_t uHeight; 132 /** Pixel format of this frame. */ 133 uint32_t uPixelFormat; 134 /** Time stamp (in ms). */ 135 uint64_t uTimeStampMs; 136 /** RGB buffer containing the unmodified frame buffer data from Main's display. */ 137 uint8_t *pu8RGBBuf; 138 /** Size (in bytes) of the RGB buffer. */ 139 size_t cbRGBBuf; 140 } VIDEORECVIDEOFRAME, *PVIDEORECVIDEOFRAME; 141 142 #ifdef VBOX_WITH_AUDIO_VIDEOREC 143 /** 144 * Structure for keeping a single video recording audio frame. 145 */ 146 typedef struct VIDEORECAUDIOFRAME 147 { 148 uint8_t abBuf[_64K]; /** @todo Fix! */ 149 uint32_t cbBuf; 150 /** Time stamp (in ms). */ 151 uint64_t uTimeStampMs; 152 } VIDEORECAUDIOFRAME, *PVIDEORECAUDIOFRAME; 153 #endif 102 154 103 155 /** … … 114 166 /** Track number of video stream. */ 115 167 uint8_t uTrackVideo; 116 /** Codec data. */117 VIDEORECCODEC Codec;118 168 /** Screen ID. */ 119 uint16_t uScreen ;169 uint16_t uScreenID; 120 170 /** Whether video recording is enabled or not. */ 121 171 bool fEnabled; 122 /** Time stamp (in ms) of the last frame we encoded. */ 123 uint64_t uLastTimeStampMs; 124 /** Time stamp (in ms) of the current frame. */ 125 uint64_t uCurTimeStampMs; 126 127 /** Whether the RGB buffer is filled or not. */ 128 bool fHasVideoData; 172 /** Critical section to serialize access. */ 173 RTCRITSECT CritSect; 129 174 130 175 struct 131 176 { 132 /** Target X resolution (in pixels). */ 133 uint32_t uDstWidth; 134 /** Target Y resolution (in pixels). */ 135 uint32_t uDstHeight; 136 /** X resolution of the last encoded frame. */ 137 uint32_t uSrcLastWidth; 138 /** Y resolution of the last encoded frame. */ 139 uint32_t uSrcLastHeight; 140 /** RGB buffer containing the most recent frame of Main's framebuffer. */ 141 uint8_t *pu8RgbBuf; 142 /** YUV buffer the encode function fetches the frame from. */ 143 uint8_t *pu8YuvBuf; 144 /** Pixel format of the current frame. */ 145 uint32_t uPixelFormat; 177 /** Codec-specific data. */ 178 VIDEORECVIDEOCODEC Codec; 146 179 /** Minimal delay (in ms) between two frames. */ 147 180 uint32_t uDelayMs; 148 /** Encoder deadline. */ 149 unsigned int uEncoderDeadline; 181 /** Target X resolution (in pixels). */ 182 uint32_t uWidth; 183 /** Target Y resolution (in pixels). */ 184 uint32_t uHeight; 185 /** Time stamp (in ms) of the last video frame we encoded. */ 186 uint64_t uLastTimeStampMs; 187 /** Pointer to the codec's internal YUV buffer. */ 188 uint8_t *pu8YuvBuf; 189 #ifdef VBOX_VIDEOREC_WITH_QUEUE 190 # error "Implement me!" 191 #else 192 VIDEORECVIDEOFRAME Frame; 193 bool fHasVideoData; 194 #endif 150 195 } Video; 151 196 } VIDEORECSTREAM, *PVIDEORECSTREAM; 152 197 153 #ifdef VBOX_WITH_AUDIO_VIDEOREC154 typedef struct VIDEORECAUDIOFRAME155 {156 uint8_t abBuf[_64K]; /** @todo Fix! */157 uint32_t cbBuf;158 /** Time stamp (in ms). */159 uint64_t uTimeStampMs;160 } VIDEORECAUDIOFRAME, *PVIDEORECAUDIOFRAME;161 #endif162 163 198 /** Vector of video recording streams. */ 164 199 typedef std::vector <PVIDEORECSTREAM> VideoRecStreams; … … 171 206 /** The current state. */ 172 207 uint32_t enmState; 208 /** Critical section to serialize access. */ 209 RTCRITSECT CritSect; 173 210 /** Semaphore to signal the encoding worker thread. */ 174 211 RTSEMEVENT WaitEvent; 175 /** Whether videorecording is enabled or not. */212 /** Whether recording is enabled or not. */ 176 213 bool fEnabled; 177 214 /** Shutdown indicator. */ … … 183 220 /** Maximal file size (in MB) to record. */ 184 221 uint32_t uMaxSizeMB; 185 /** Vector of current videorecording stream contexts. */222 /** Vector of current recording stream contexts. */ 186 223 VideoRecStreams vecStreams; 187 224 #ifdef VBOX_WITH_AUDIO_VIDEOREC 188 bool fHasAudioData; 189 VIDEORECAUDIOFRAME Audio; 225 struct 226 { 227 bool fHasAudioData; 228 VIDEORECAUDIOFRAME Frame; 229 } Audio; 190 230 #endif 191 231 } VIDEORECCONTEXT, *PVIDEORECCONTEXT; 192 232 233 #ifdef VBOX_VIDEOREC_DUMP 234 #pragma pack(push) 235 #pragma pack(1) 236 typedef struct 237 { 238 uint16_t u16Magic; 239 uint32_t u32Size; 240 uint16_t u16Reserved1; 241 uint16_t u16Reserved2; 242 uint32_t u32OffBits; 243 } VIDEORECBMPHDR, *PVIDEORECBMPHDR; 244 AssertCompileSize(VIDEORECBMPHDR, 14); 245 246 typedef struct 247 { 248 uint32_t u32Size; 249 uint32_t u32Width; 250 uint32_t u32Height; 251 uint16_t u16Planes; 252 uint16_t u16BitCount; 253 uint32_t u32Compression; 254 uint32_t u32SizeImage; 255 uint32_t u32XPelsPerMeter; 256 uint32_t u32YPelsPerMeter; 257 uint32_t u32ClrUsed; 258 uint32_t u32ClrImportant; 259 } VIDEORECBMPDIBHDR, *PVIDEORECBMPDIBHDR; 260 AssertCompileSize(VIDEORECBMPDIBHDR, 40); 261 262 #pragma pack(pop) 263 #endif /* VBOX_VIDEOREC_DUMP */ 193 264 194 265 /** … … 355 426 356 427 /** 357 * Convert an image to YUV420p format 358 * @returns true on success, false on failure 359 * @param aWidth width of image 360 * @param aHeight height of image 361 * @param aDestBuf an allocated memory buffer large enough to hold the 362 * destination image (i.e. width * height * 12bits) 363 * @param aSrcBuf the source image as an array of bytes 428 * Convert an image to YUV420p format. 429 * 430 * @return true on success, false on failure. 431 * @param aDstBuf The destination image buffer. 432 * @param aDstWidth Width (in pixel) of destination buffer. 433 * @param aDstHeight Height (in pixel) of destination buffer. 434 * @param aSrcBuf The source image buffer. 435 * @param aSrcWidth Width (in pixel) of source buffer. 436 * @param aSrcHeight Height (in pixel) of source buffer. 364 437 */ 365 438 template <class T> 366 inline bool colorConvWriteYUV420p(unsigned aWidth, unsigned aHeight, uint8_t *aDestBuf, uint8_t *aSrcBuf) 367 { 368 AssertReturn(!(aWidth & 1), false); 369 AssertReturn(!(aHeight & 1), false); 439 inline bool colorConvWriteYUV420p(uint8_t *aDstBuf, unsigned aDstWidth, unsigned aDstHeight, 440 uint8_t *aSrcBuf, unsigned aSrcWidth, unsigned aSrcHeight) 441 { 442 RT_NOREF(aDstWidth, aDstHeight); 443 444 AssertReturn(!(aSrcWidth & 1), false); 445 AssertReturn(!(aSrcHeight & 1), false); 446 370 447 bool fRc = true; 371 T iter1(a Width, aHeight, aSrcBuf);448 T iter1(aSrcWidth, aSrcHeight, aSrcBuf); 372 449 T iter2 = iter1; 373 iter2.skip(a Width);374 unsigned cPixels = a Width * aHeight;450 iter2.skip(aSrcWidth); 451 unsigned cPixels = aSrcWidth * aSrcHeight; 375 452 unsigned offY = 0; 376 453 unsigned offU = cPixels; 377 454 unsigned offV = cPixels + cPixels / 4; 378 unsigned const cyHalf = a Height / 2;379 unsigned const cxHalf = a Width / 2;455 unsigned const cyHalf = aSrcHeight / 2; 456 unsigned const cxHalf = aSrcWidth / 2; 380 457 for (unsigned i = 0; i < cyHalf && fRc; ++i) 381 458 { … … 385 462 fRc = iter1.getRGB(&red, &green, &blue); 386 463 AssertReturn(fRc, false); 387 aD estBuf[offY] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;464 aDstBuf[offY] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16; 388 465 unsigned u = (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4; 389 466 unsigned v = (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4; … … 391 468 fRc = iter1.getRGB(&red, &green, &blue); 392 469 AssertReturn(fRc, false); 393 aD estBuf[offY + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;470 aDstBuf[offY + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16; 394 471 u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4; 395 472 v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4; … … 397 474 fRc = iter2.getRGB(&red, &green, &blue); 398 475 AssertReturn(fRc, false); 399 aD estBuf[offY + aWidth] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;476 aDstBuf[offY + aSrcWidth] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16; 400 477 u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4; 401 478 v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4; … … 403 480 fRc = iter2.getRGB(&red, &green, &blue); 404 481 AssertReturn(fRc, false); 405 aD estBuf[offY + aWidth + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16;482 aDstBuf[offY + aSrcWidth + 1] = ((66 * red + 129 * green + 25 * blue + 128) >> 8) + 16; 406 483 u += (((-38 * red - 74 * green + 112 * blue + 128) >> 8) + 128) / 4; 407 484 v += (((112 * red - 94 * green - 18 * blue + 128) >> 8) + 128) / 4; 408 485 409 aD estBuf[offU] = u;410 aD estBuf[offV] = v;486 aDstBuf[offU] = u; 487 aDstBuf[offV] = v; 411 488 offY += 2; 412 489 ++offU; … … 414 491 } 415 492 416 iter1.skip(a Width);417 iter2.skip(a Width);418 offY += a Width;493 iter1.skip(aSrcWidth); 494 iter2.skip(aSrcWidth); 495 offY += aSrcWidth; 419 496 } 420 497 … … 476 553 477 554 #ifdef VBOX_WITH_AUDIO_VIDEOREC 478 const bool fHasAudioData = ASMAtomicReadBool(&pCtx->fHasAudioData); 479 #endif 555 PVIDEORECAUDIOFRAME pAudioFrame; 556 557 int rc2 = RTCritSectEnter(&pCtx->CritSect); 558 AssertRC(rc2); 559 560 const bool fEncodeAudio = pCtx->Audio.fHasAudioData; 561 if (fEncodeAudio) 562 { 563 /* 564 * Every recording stream needs to get the same audio data at a certain point in time. 565 * Do the multiplexing here to not block EMT for too long. 566 * 567 * For now just doing a simple copy of the current audio frame should be good enough. 568 */ 569 VIDEORECAUDIOFRAME audioFrame; 570 memcpy(&audioFrame, &pCtx->Audio.Frame, sizeof(VIDEORECAUDIOFRAME)); 571 pAudioFrame = &audioFrame; 572 573 pCtx->Audio.fHasAudioData = false; 574 } 575 576 rc2 = RTCritSectLeave(&pCtx->CritSect); 577 AssertRC(rc2); 578 #endif 579 480 580 /** @todo r=andy This is inefficient -- as we already wake up this thread 481 581 * for every screen from Main, we here go again (on every wake up) through … … 485 585 PVIDEORECSTREAM pStream = (*it); 486 586 587 videoRecStreamLock(pStream); 588 487 589 if (!pStream->fEnabled) 590 { 591 videoRecStreamUnlock(pStream); 488 592 continue; 489 490 if (ASMAtomicReadBool(&pStream->fHasVideoData)) 491 { 492 rc = videoRecRGBToYUV(pStream); 493 494 ASMAtomicWriteBool(&pStream->fHasVideoData, false); 495 496 if (RT_SUCCESS(rc)) 497 rc = videoRecEncodeAndWrite(pStream); 498 499 if (RT_FAILURE(rc)) 593 } 594 595 PVIDEORECVIDEOFRAME pVideoFrame = &pStream->Video.Frame; 596 const bool fEncodeVideo = pStream->Video.fHasVideoData; 597 598 if (fEncodeVideo) 599 { 600 pStream->Video.fHasVideoData = false; 601 602 rc = videoRecRGBToYUV(pVideoFrame->uPixelFormat, 603 /* Destination */ 604 pStream->Video.pu8YuvBuf, pVideoFrame->uWidth, pVideoFrame->uHeight, 605 /* Source */ 606 pVideoFrame->pu8RGBBuf, pStream->Video.uWidth, pStream->Video.uHeight); 607 } 608 609 if ( fEncodeVideo 610 && RT_SUCCESS(rc)) 611 { 612 rc = videoRecEncodeAndWrite(pStream, pVideoFrame); 613 } 614 615 videoRecStreamUnlock(pStream); 616 617 if (RT_FAILURE(rc)) 618 { 619 static unsigned s_cErrEnc = 100; 620 if (s_cErrEnc > 0) 500 621 { 501 static unsigned s_cErrEnc = 100; 502 if (s_cErrEnc > 0) 503 { 504 LogRel(("VideoRec: Error %Rrc encoding / writing video frame\n", rc)); 505 s_cErrEnc--; 506 } 622 LogRel(("VideoRec: Error %Rrc encoding / writing video frame\n", rc)); 623 s_cErrEnc--; 507 624 } 508 625 } 509 626 510 627 #ifdef VBOX_WITH_AUDIO_VIDEOREC 511 /* Each (enabled) screen has to get the audio data. */512 if (f HasAudioData)513 { 514 WebMWriter::BlockData_Opus blockData = { p Ctx->Audio.abBuf, pCtx->Audio.cbBuf, pCtx->Audio.uTimeStampMs };628 /* Each (enabled) screen has to get the same audio data. */ 629 if (fEncodeAudio) 630 { 631 WebMWriter::BlockData_Opus blockData = { pAudioFrame->abBuf, pAudioFrame->cbBuf, pAudioFrame->uTimeStampMs }; 515 632 rc = pStream->pEBML->WriteBlock(pStream->uTrackAudio, &blockData, sizeof(blockData)); 516 633 } 517 634 #endif 518 } /* for */ 519 520 #ifdef VBOX_WITH_AUDIO_VIDEOREC 521 if (fHasAudioData) 522 ASMAtomicWriteBool(&pCtx->fHasAudioData, false); 523 #endif 635 } 524 636 } 525 637 … … 539 651 AssertPtrReturn(ppCtx, VERR_INVALID_POINTER); 540 652 541 int rc = VINF_SUCCESS;542 543 653 PVIDEORECCONTEXT pCtx = (PVIDEORECCONTEXT)RTMemAllocZ(sizeof(VIDEORECCONTEXT)); 544 654 if (!pCtx) 545 655 return VERR_NO_MEMORY; 546 656 657 int rc = RTCritSectInit(&pCtx->CritSect); 658 if (RT_FAILURE(rc)) 659 return rc; 660 547 661 for (uint32_t uScreen = 0; uScreen < cScreens; uScreen++) 548 662 { … … 554 668 } 555 669 670 rc = RTCritSectInit(&pStream->CritSect); 671 if (RT_FAILURE(rc)) 672 break; 673 556 674 try 557 675 { 558 pStream->uScreen = uScreen;676 pStream->uScreenID = uScreen; 559 677 560 678 pCtx->vecStreams.push_back(pStream); … … 585 703 if (RT_SUCCESS(rc)) 586 704 { 587 pCtx->enmState = VIDEORECSTS_I DLE;705 pCtx->enmState = VIDEORECSTS_INITIALIZED; 588 706 pCtx->fEnabled = true; 589 707 … … 651 769 pStream->pEBML->Close(); 652 770 653 vpx_img_free(&pStream-> Codec.VPX.RawImage);654 vpx_codec_err_t rcv = vpx_codec_destroy(&pStream-> Codec.VPX.CodecCtx);771 vpx_img_free(&pStream->Video.Codec.VPX.RawImage); 772 vpx_codec_err_t rcv = vpx_codec_destroy(&pStream->Video.Codec.VPX.Ctx); 655 773 Assert(rcv == VPX_CODEC_OK); RT_NOREF(rcv); 656 774 657 if (pStream->Video.pu8RgbBuf) 658 { 659 RTMemFree(pStream->Video.pu8RgbBuf); 660 pStream->Video.pu8RgbBuf = NULL; 661 } 662 663 LogRel(("VideoRec: Recording screen #%u stopped\n", pStream->uScreen)); 775 #ifdef VBOX_VIDEOREC_WITH_QUEUE 776 # error "Implement me!" 777 #else 778 PVIDEORECVIDEOFRAME pFrame = &pStream->Video.Frame; 779 #endif 780 if (pFrame->pu8RGBBuf) 781 { 782 Assert(pFrame->cbRGBBuf); 783 784 RTMemFree(pFrame->pu8RGBBuf); 785 pFrame->pu8RGBBuf = NULL; 786 } 787 788 pFrame->cbRGBBuf = 0; 789 790 LogRel(("VideoRec: Recording screen #%u stopped\n", pStream->uScreenID)); 664 791 } 665 792 … … 672 799 it = pCtx->vecStreams.erase(it); 673 800 801 RTCritSectDelete(&pStream->CritSect); 802 674 803 RTMemFree(pStream); 675 804 pStream = NULL; … … 677 806 678 807 Assert(pCtx->vecStreams.empty()); 808 809 RTCritSectDelete(&pCtx->CritSect); 679 810 680 811 RTMemFree(pCtx); … … 707 838 708 839 return pStream; 840 } 841 842 /** 843 * Locks a recording stream. 844 * 845 * @returns IPRT status code. 846 * @param pStream Recording stream to lock. 847 */ 848 int videoRecStreamLock(PVIDEORECSTREAM pStream) 849 { 850 int rc = RTCritSectEnter(&pStream->CritSect); 851 AssertRC(rc); 852 853 return rc; 854 } 855 856 /** 857 * Unlocks a locked recording stream. 858 * 859 * @returns IPRT status code. 860 * @param pStream Recording stream to unlock. 861 */ 862 int videoRecStreamUnlock(PVIDEORECSTREAM pStream) 863 { 864 int rc = RTCritSectLeave(&pStream->CritSect); 865 AssertRC(rc); 866 867 return rc; 709 868 } 710 869 … … 743 902 pCtx->uMaxSizeMB = uMaxSizeMB; 744 903 745 pStream->Video.uDstWidth = uWidth; 746 pStream->Video.uDstHeight = uHeight; 747 pStream->Video.pu8RgbBuf = (uint8_t *)RTMemAllocZ(uWidth * uHeight * 4); 748 AssertReturn(pStream->Video.pu8RgbBuf, VERR_NO_MEMORY); 749 750 /* Play safe: the file must not exist, overwriting is potentially 751 * hazardous as nothing prevents the user from picking a file name of some 752 * other important file, causing unintentional data loss. */ 904 pStream->Video.uWidth = uWidth; 905 pStream->Video.uHeight = uHeight; 906 907 #ifndef VBOX_VIDEOREC_WITH_QUEUE 908 /* When not using a queue, we only use one frame per stream at once. 909 * So do the initialization here. */ 910 PVIDEORECVIDEOFRAME pFrame = &pStream->Video.Frame; 911 912 const size_t cbRGBBuf = pStream->Video.uWidth 913 * pStream->Video.uHeight 914 * 4 /* 32 BPP maximum */; 915 AssertReturn(cbRGBBuf, VERR_INVALID_PARAMETER); 916 917 pFrame->pu8RGBBuf = (uint8_t *)RTMemAllocZ(cbRGBBuf); 918 AssertReturn(pFrame->pu8RGBBuf, VERR_NO_MEMORY); 919 pFrame->cbRGBBuf = cbRGBBuf; 920 #endif 921 922 PVIDEORECVIDEOCODEC pVC = &pStream->Video.Codec; 753 923 754 924 #ifdef VBOX_WITH_LIBVPX 755 p Stream->Video.uEncoderDeadline = VPX_DL_REALTIME;756 757 vpx_codec_err_t rcv = vpx_codec_enc_config_default(DEFAULTCODEC, &p Stream->Codec.VPX.Config, 0);925 pVC->VPX.uEncoderDeadline = VPX_DL_REALTIME; 926 927 vpx_codec_err_t rcv = vpx_codec_enc_config_default(DEFAULTCODEC, &pVC->VPX.Cfg, 0); 758 928 if (rcv != VPX_CODEC_OK) 759 929 { … … 767 937 768 938 /* By default we enable everything (if available). */ 769 bool fHasVideoTrack = true;939 bool fHasVideoTrack = true; 770 940 #ifdef VBOX_WITH_AUDIO_VIDEOREC 771 941 bool fHasAudioTrack = true; … … 784 954 { 785 955 #ifdef VBOX_WITH_LIBVPX 786 p Stream->Video.uEncoderDeadline = VPX_DL_REALTIME;956 pVC->VPX.uEncoderDeadline = VPX_DL_REALTIME; 787 957 #endif 788 958 } 789 959 else if (value.compare("good", Utf8Str::CaseInsensitive) == 0) 790 960 { 791 p Stream->Video.uEncoderDeadline = 1000000 / uFPS;961 pVC->VPX.uEncoderDeadline = 1000000 / uFPS; 792 962 } 793 963 else if (value.compare("best", Utf8Str::CaseInsensitive) == 0) 794 964 { 795 965 #ifdef VBOX_WITH_LIBVPX 796 p Stream->Video.uEncoderDeadline = VPX_DL_BEST_QUALITY;966 pVC->VPX.uEncoderDeadline = VPX_DL_BEST_QUALITY; 797 967 #endif 798 968 } … … 800 970 { 801 971 LogRel(("VideoRec: Setting quality deadline to '%s'\n", value.c_str())); 802 p Stream->Video.uEncoderDeadline = value.toUInt32();972 pVC->VPX.uEncoderDeadline = value.toUInt32(); 803 973 } 804 974 } … … 806 976 { 807 977 #ifdef VBOX_WITH_AUDIO_VIDEOREC 808 if (value.compare("false", Utf8Str::CaseInsensitive) == 0) /* Disable audio. */978 if (value.compare("false", Utf8Str::CaseInsensitive) == 0) 809 979 { 810 980 fHasVideoTrack = false; … … 816 986 { 817 987 #ifdef VBOX_WITH_AUDIO_VIDEOREC 818 if (value.compare("false", Utf8Str::CaseInsensitive)) /* Disable audio. */988 if (value.compare("false", Utf8Str::CaseInsensitive)) 819 989 { 820 990 fHasAudioTrack = false; … … 853 1023 fOpen |= RTFILE_O_CREATE_REPLACE; 854 1024 #else 1025 /* Play safe: the file must not exist, overwriting is potentially 1026 * hazardous as nothing prevents the user from picking a file name of some 1027 * other important file, causing unintentional data loss. */ 855 1028 fOpen |= RTFILE_O_CREATE; 856 1029 #endif 857 1030 858 int rc = pStream->pEBML->Create(pszFile, fOpen, WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_VP8); 1031 int rc = pStream->pEBML->Create(pszFile, fOpen, 1032 #ifdef VBOX_WITH_AUDIO_VIDEOREC 1033 fHasAudioTrack ? WebMWriter::AudioCodec_Opus : WebMWriter::AudioCodec_None, 1034 #else 1035 WebMWriter::AudioCodec_None, 1036 #endif 1037 fHasVideoTrack ? WebMWriter::VideoCodec_VP8 : WebMWriter::VideoCodec_None); 859 1038 if (RT_FAILURE(rc)) 860 1039 { … … 915 1094 #ifdef VBOX_WITH_LIBVPX 916 1095 /* Target bitrate in kilobits per second. */ 917 p Stream->Codec.VPX.Config.rc_target_bitrate = uRate;1096 pVC->VPX.Cfg.rc_target_bitrate = uRate; 918 1097 /* Frame width. */ 919 p Stream->Codec.VPX.Config.g_w = uWidth;1098 pVC->VPX.Cfg.g_w = uWidth; 920 1099 /* Frame height. */ 921 p Stream->Codec.VPX.Config.g_h = uHeight;1100 pVC->VPX.Cfg.g_h = uHeight; 922 1101 /* 1ms per frame. */ 923 p Stream->Codec.VPX.Config.g_timebase.num = 1;924 p Stream->Codec.VPX.Config.g_timebase.den = 1000;1102 pVC->VPX.Cfg.g_timebase.num = 1; 1103 pVC->VPX.Cfg.g_timebase.den = 1000; 925 1104 /* Disable multithreading. */ 926 p Stream->Codec.VPX.Config.g_threads = 0;1105 pVC->VPX.Cfg.g_threads = 0; 927 1106 928 1107 /* Initialize codec. */ 929 rcv = vpx_codec_enc_init(&p Stream->Codec.VPX.CodecCtx, DEFAULTCODEC, &pStream->Codec.VPX.Config, 0);1108 rcv = vpx_codec_enc_init(&pVC->VPX.Ctx, DEFAULTCODEC, &pVC->VPX.Cfg, 0); 930 1109 if (rcv != VPX_CODEC_OK) 931 1110 { … … 934 1113 } 935 1114 936 if (!vpx_img_alloc(&p Stream->Codec.VPX.RawImage, VPX_IMG_FMT_I420, uWidth, uHeight, 1))1115 if (!vpx_img_alloc(&pVC->VPX.RawImage, VPX_IMG_FMT_I420, uWidth, uHeight, 1)) 937 1116 { 938 1117 LogFlow(("Failed to allocate image %dx%d", uWidth, uHeight)); … … 940 1119 } 941 1120 942 pStream->Video.pu8YuvBuf = pStream->Codec.VPX.RawImage.planes[0]; 1121 /* Save a pointer to the first raw YUV plane. */ 1122 pStream->Video.pu8YuvBuf = pVC->VPX.RawImage.planes[0]; 943 1123 #endif 944 1124 pStream->fEnabled = true; … … 958 1138 return false; 959 1139 960 uint32_t enmState = ASMAtomicReadU32(&pCtx->enmState); 961 962 return ( enmState == VIDEORECSTS_IDLE 963 || enmState == VIDEORECSTS_BUSY); 1140 return ASMAtomicReadBool(&pCtx->fEnabled); 964 1141 } 965 1142 … … 977 1154 AssertPtrReturn(pCtx, false); 978 1155 979 uint32_t enmState = ASMAtomicReadU32(&pCtx->enmState); 980 if (enmState != VIDEORECSTS_IDLE) 1156 if (ASMAtomicReadU32(&pCtx->enmState) != VIDEORECSTS_INITIALIZED) 981 1157 return false; 982 1158 … … 988 1164 } 989 1165 990 if (uTimeStampMs < pStream->uLastTimeStampMs + pStream->Video.uDelayMs) 1166 PVIDEORECVIDEOFRAME pLastFrame = &pStream->Video.Frame; 1167 1168 if (uTimeStampMs < pLastFrame->uTimeStampMs + pStream->Video.uDelayMs) 991 1169 return false; 992 993 if ( ASMAtomicReadBool(&pStream->fHasVideoData)994 #ifdef VBOX_WITH_AUDIO_VIDEOREC995 /* Check if we have audio data left for the current frame. */996 || ASMAtomicReadBool(&pCtx->fHasAudioData)997 #endif998 )999 {1000 return false;1001 }1002 1170 1003 1171 return true; … … 1035 1203 return true; 1036 1204 } 1205 1037 1206 /* Check for available free disk space */ 1038 if (pStream->pEBML->GetAvailableSpace() < 0x100000) 1207 if ( pStream->pEBML 1208 && pStream->pEBML->GetAvailableSpace() < 0x100000) /**@todo r=andy WTF? Fix this. */ 1039 1209 { 1040 1210 LogRel(("VideoRec: Not enough free storage space available, stopping video capture\n")); … … 1050 1220 * 1051 1221 * @returns IPRT status code. 1052 * @param pStream Stream to encode and write. 1053 */ 1054 static int videoRecEncodeAndWrite(PVIDEORECSTREAM pStream) 1222 * @param pStream Stream to encode and submit to. 1223 * @param pFrame Frame to encode and submit. 1224 */ 1225 static int videoRecEncodeAndWrite(PVIDEORECSTREAM pStream, PVIDEORECVIDEOFRAME pFrame) 1055 1226 { 1056 1227 int rc; 1228 1229 PVIDEORECVIDEOCODEC pVC = &pStream->Video.Codec; 1057 1230 1058 1231 #ifdef VBOX_WITH_LIBVPX 1059 1232 /* Presentation Time Stamp (PTS). */ 1060 vpx_codec_pts_t pts = p Stream->uCurTimeStampMs;1061 vpx_codec_err_t rcv = vpx_codec_encode(&p Stream->Codec.VPX.CodecCtx,1062 &p Stream->Codec.VPX.RawImage,1063 pts 1064 pStream->Video.uDelayMs 1065 0 1066 p Stream->Video.uEncoderDeadline/* Quality setting */);1233 vpx_codec_pts_t pts = pFrame->uTimeStampMs; 1234 vpx_codec_err_t rcv = vpx_codec_encode(&pVC->VPX.Ctx, 1235 &pVC->VPX.RawImage, 1236 pts /* Time stamp */, 1237 pStream->Video.uDelayMs /* How long to show this frame */, 1238 0 /* Flags */, 1239 pVC->VPX.uEncoderDeadline /* Quality setting */); 1067 1240 if (rcv != VPX_CODEC_OK) 1068 1241 { … … 1075 1248 for (;;) 1076 1249 { 1077 const vpx_codec_cx_pkt_t *pPacket = vpx_codec_get_cx_data(&p Stream->Codec.VPX.CodecCtx, &iter);1250 const vpx_codec_cx_pkt_t *pPacket = vpx_codec_get_cx_data(&pVC->VPX.Ctx, &iter); 1078 1251 if (!pPacket) 1079 1252 break; … … 1083 1256 case VPX_CODEC_CX_FRAME_PKT: 1084 1257 { 1085 WebMWriter::BlockData_VP8 blockData = { &p Stream->Codec.VPX.Config, pPacket };1258 WebMWriter::BlockData_VP8 blockData = { &pVC->VPX.Cfg, pPacket }; 1086 1259 rc = pStream->pEBML->WriteBlock(pStream->uTrackVideo, &blockData, sizeof(blockData)); 1087 1260 break; … … 1105 1278 * 1106 1279 * @returns IPRT status code. 1107 * @param pStream Recording stream to convert RGB to YUV video frame buffer for. 1108 */ 1109 static int videoRecRGBToYUV(PVIDEORECSTREAM pStream) 1110 { 1111 switch (pStream->Video.uPixelFormat) 1280 * TODO 1281 */ 1282 static int videoRecRGBToYUV(uint32_t uPixelFormat, 1283 uint8_t *paDst, uint32_t uDstWidth, uint32_t uDstHeight, 1284 uint8_t *paSrc, uint32_t uSrcWidth, uint32_t uSrcHeight) 1285 { 1286 switch (uPixelFormat) 1112 1287 { 1113 1288 case VIDEORECPIXELFMT_RGB32: 1114 LogFlow(("32 bit\n")); 1115 if (!colorConvWriteYUV420p<ColorConvBGRA32Iter>(pStream->Video.uDstWidth, 1116 pStream->Video.uDstHeight, 1117 pStream->Video.pu8YuvBuf, 1118 pStream->Video.pu8RgbBuf)) 1289 if (!colorConvWriteYUV420p<ColorConvBGRA32Iter>(paDst, uDstWidth, uDstHeight, 1290 paSrc, uSrcWidth, uSrcHeight)) 1119 1291 return VERR_INVALID_PARAMETER; 1120 1292 break; 1121 1293 case VIDEORECPIXELFMT_RGB24: 1122 LogFlow(("24 bit\n")); 1123 if (!colorConvWriteYUV420p<ColorConvBGR24Iter>(pStream->Video.uDstWidth, 1124 pStream->Video.uDstHeight, 1125 pStream->Video.pu8YuvBuf, 1126 pStream->Video.pu8RgbBuf)) 1294 if (!colorConvWriteYUV420p<ColorConvBGR24Iter>(paDst, uDstWidth, uDstHeight, 1295 paSrc, uSrcWidth, uSrcHeight)) 1127 1296 return VERR_INVALID_PARAMETER; 1128 1297 break; 1129 1298 case VIDEORECPIXELFMT_RGB565: 1130 LogFlow(("565 bit\n")); 1131 if (!colorConvWriteYUV420p<ColorConvBGR565Iter>(pStream->Video.uDstWidth, 1132 pStream->Video.uDstHeight, 1133 pStream->Video.pu8YuvBuf, 1134 pStream->Video.pu8RgbBuf)) 1299 if (!colorConvWriteYUV420p<ColorConvBGR565Iter>(paDst, uDstWidth, uDstHeight, 1300 paSrc, uSrcWidth, uSrcHeight)) 1135 1301 return VERR_INVALID_PARAMETER; 1136 1302 break; 1137 1303 default: 1304 AssertFailed(); 1138 1305 return VERR_NOT_SUPPORTED; 1139 1306 } … … 1157 1324 AssertReturn(cbData <= _64K, VERR_INVALID_PARAMETER); 1158 1325 1159 /* Do not execute during termination and guard against termination. */1160 if ( !ASMAtomicCmpXchgU32(&pCtx->enmState, VIDEORECSTS_BUSY, VIDEORECSTS_IDLE))1161 return VINF_TRY_AGAIN;1326 int rc = RTCritSectEnter(&pCtx->CritSect); 1327 if (RT_FAILURE(rc)) 1328 return rc; 1162 1329 1163 1330 /* To save time spent in EMT, do the required audio multiplexing in the encoding thread. … … 1166 1333 * audio data at the same given point in time. 1167 1334 */ 1168 1169 if (ASMAtomicReadBool(&pCtx->fHasAudioData)) 1170 return VERR_TRY_AGAIN; /* Previous frame not yet encoded. */ 1171 1172 memcpy(pCtx->Audio.abBuf, pvData, RT_MIN(_64K, cbData)); 1173 1174 pCtx->Audio.cbBuf = cbData; 1175 pCtx->Audio.uTimeStampMs = uTimeStampMs; 1176 1177 ASMAtomicWriteBool(&pCtx->fHasAudioData, true); 1178 RTSemEventSignal(pCtx->WaitEvent); 1335 PVIDEORECAUDIOFRAME pFrame = &pCtx->Audio.Frame; 1336 1337 memcpy(pFrame->abBuf, pvData, RT_MIN(_64K /** @todo Fix! */, cbData)); 1338 1339 pFrame->cbBuf = cbData; 1340 pFrame->uTimeStampMs = uTimeStampMs; 1341 1342 pCtx->Audio.fHasAudioData = true; 1343 1344 rc = RTCritSectLeave(&pCtx->CritSect); 1345 if (RT_SUCCESS(rc)) 1346 rc = RTSemEventSignal(pCtx->WaitEvent); 1347 1348 return rc; 1179 1349 #else 1180 1350 RT_NOREF(pCtx, pvData, cbData, uTimeStampMs); 1181 #endif1182 1351 return VINF_SUCCESS; 1352 #endif 1183 1353 } 1184 1354 … … 1207 1377 uint64_t uTimeStampMs) 1208 1378 { 1209 /* Do not execute during termination and guard against termination. */ 1210 if (!ASMAtomicCmpXchgU32(&pCtx->enmState, VIDEORECSTS_BUSY, VIDEORECSTS_IDLE)) 1211 return VINF_TRY_AGAIN; 1212 1213 int rc = VINF_SUCCESS; 1379 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1380 AssertReturn(uSrcWidth, VERR_INVALID_PARAMETER); 1381 AssertReturn(uSrcHeight, VERR_INVALID_PARAMETER); 1382 AssertReturn(puSrcData, VERR_INVALID_POINTER); 1383 1384 PVIDEORECSTREAM pStream = videoRecStreamGet(pCtx, uScreen); 1385 if (!pStream) 1386 return VERR_NOT_FOUND; 1387 1388 int rc = RTCritSectEnter(&pStream->CritSect); 1389 if (RT_FAILURE(rc)) 1390 return rc; 1391 1214 1392 do 1215 1393 { 1216 AssertPtrBreakStmt(pCtx, rc = VERR_INVALID_POINTER);1217 AssertBreakStmt(uSrcWidth, rc = VERR_INVALID_PARAMETER);1218 AssertBreakStmt(uSrcHeight, rc = VERR_INVALID_PARAMETER);1219 AssertPtrBreakStmt(puSrcData, rc = VERR_INVALID_POINTER);1220 1221 PVIDEORECSTREAM pStream = videoRecStreamGet(pCtx, uScreen);1222 if (!pStream)1223 {1224 rc = VERR_NOT_FOUND;1225 break;1226 }1227 1228 1394 if (!pStream->fEnabled) 1229 1395 { … … 1232 1398 } 1233 1399 1234 if (uTimeStampMs < pStream-> uLastTimeStampMs + pStream->Video.uDelayMs)1400 if (uTimeStampMs < pStream->Video.uLastTimeStampMs + pStream->Video.uDelayMs) 1235 1401 { 1236 1402 rc = VINF_TRY_AGAIN; /* Respect maximum frames per second. */ … … 1238 1404 } 1239 1405 1240 if (ASMAtomicReadBool(&pStream->fHasVideoData)) 1241 { 1242 rc = VERR_TRY_AGAIN; /* Previous frame not yet encoded. */ 1243 break; 1244 } 1245 1246 pStream->uLastTimeStampMs = uTimeStampMs; 1247 1248 int xDiff = ((int)pStream->Video.uDstWidth - (int)uSrcWidth) / 2; 1406 pStream->Video.uLastTimeStampMs = uTimeStampMs; 1407 1408 int xDiff = ((int)pStream->Video.uWidth - (int)uSrcWidth) / 2; 1249 1409 uint32_t w = uSrcWidth; 1250 1410 if ((int)w + xDiff + (int)x <= 0) /* Nothing visible. */ … … 1265 1425 1266 1426 uint32_t h = uSrcHeight; 1267 int yDiff = ((int)pStream->Video.u DstHeight - (int)uSrcHeight) / 2;1427 int yDiff = ((int)pStream->Video.uHeight - (int)uSrcHeight) / 2; 1268 1428 if ((int)h + yDiff + (int)y <= 0) /* Nothing visible. */ 1269 1429 { … … 1282 1442 destY = y + yDiff; 1283 1443 1284 if ( destX > pStream->Video.u DstWidth1285 || destY > pStream->Video.u DstHeight)1444 if ( destX > pStream->Video.uWidth 1445 || destY > pStream->Video.uHeight) 1286 1446 { 1287 1447 rc = VERR_INVALID_PARAMETER; /* Nothing visible. */ … … 1289 1449 } 1290 1450 1291 if (destX + w > pStream->Video.uDstWidth) 1292 w = pStream->Video.uDstWidth - destX; 1293 1294 if (destY + h > pStream->Video.uDstHeight) 1295 h = pStream->Video.uDstHeight - destY; 1296 1297 /* Calculate bytes per pixel. */ 1298 uint32_t bpp = 1; 1451 if (destX + w > pStream->Video.uWidth) 1452 w = pStream->Video.uWidth - destX; 1453 1454 if (destY + h > pStream->Video.uHeight) 1455 h = pStream->Video.uHeight - destY; 1456 1457 #ifdef VBOX_VIDEOREC_WITH_QUEUE 1458 # error "Implement me!" 1459 #else 1460 PVIDEORECVIDEOFRAME pFrame = &pStream->Video.Frame; 1461 #endif 1462 /* Calculate bytes per pixel and set pixel format. */ 1463 const unsigned uBytesPerPixel = uBPP / 8; 1299 1464 if (uPixelFormat == BitmapFormat_BGR) 1300 1465 { … … 1302 1467 { 1303 1468 case 32: 1304 pStream->Video.uPixelFormat = VIDEORECPIXELFMT_RGB32; 1305 bpp = 4; 1469 pFrame->uPixelFormat = VIDEORECPIXELFMT_RGB32; 1306 1470 break; 1307 1471 case 24: 1308 pStream->Video.uPixelFormat = VIDEORECPIXELFMT_RGB24; 1309 bpp = 3; 1472 pFrame->uPixelFormat = VIDEORECPIXELFMT_RGB24; 1310 1473 break; 1311 1474 case 16: 1312 pStream->Video.uPixelFormat = VIDEORECPIXELFMT_RGB565; 1313 bpp = 2; 1475 pFrame->uPixelFormat = VIDEORECPIXELFMT_RGB565; 1314 1476 break; 1315 1477 default: 1316 AssertMsgFailed(("Unknown color depth ! mBitsPerPixel=%d\n", uBPP));1478 AssertMsgFailed(("Unknown color depth (%RU32)\n", uBPP)); 1317 1479 break; 1318 1480 } 1319 1481 } 1320 1482 else 1321 AssertMsgFailed(("Unknown pixel format! mPixelFormat=%d\n", pStream->Video.uPixelFormat)); 1322 1323 /* One of the dimensions of the current frame is smaller than before so 1324 * clear the entire buffer to prevent artifacts from the previous frame. */ 1325 if ( uSrcWidth < pStream->Video.uSrcLastWidth 1326 || uSrcHeight < pStream->Video.uSrcLastHeight) 1327 memset(pStream->Video.pu8RgbBuf, 0, pStream->Video.uDstWidth * pStream->Video.uDstHeight * 4); 1328 1329 pStream->Video.uSrcLastWidth = uSrcWidth; 1330 pStream->Video.uSrcLastHeight = uSrcHeight; 1331 1483 AssertMsgFailed(("Unknown pixel format (%RU32)\n", uPixelFormat)); 1484 1485 #ifndef VBOX_VIDEOREC_WITH_QUEUE 1486 /* If we don't use a queue then we have to compare the dimensions 1487 * of the current frame with the previous frame: 1488 * 1489 * If it's smaller than before then clear the entire buffer to prevent artifacts 1490 * from the previous frame. */ 1491 if ( uSrcWidth < pFrame->uWidth 1492 || uSrcHeight < pFrame->uHeight) 1493 { 1494 /** @todo r=andy Only clear dirty areas. */ 1495 RT_BZERO(pFrame->pu8RGBBuf, pFrame->cbRGBBuf); 1496 } 1497 #endif 1332 1498 /* Calculate start offset in source and destination buffers. */ 1333 uint32_t offSrc = y * uBytesPerLine + x * bpp; 1334 uint32_t offDst = (destY * pStream->Video.uDstWidth + destX) * bpp; 1499 uint32_t offSrc = y * uBytesPerLine + x * uBytesPerPixel; 1500 uint32_t offDst = (destY * pStream->Video.uWidth + destX) * uBytesPerPixel; 1501 1502 #ifdef VBOX_VIDEOREC_DUMP 1503 VIDEORECBMPHDR bmpHdr; 1504 RT_ZERO(bmpHdr); 1505 1506 VIDEORECBMPDIBHDR bmpDIBHdr; 1507 RT_ZERO(bmpDIBHdr); 1508 1509 bmpHdr.u16Magic = 0x4d42; /* Magic */ 1510 bmpHdr.u32Size = (uint32_t)(sizeof(VIDEORECBMPHDR) + sizeof(VIDEORECBMPDIBHDR) + (w * h * uBytesPerPixel)); 1511 bmpHdr.u32OffBits = (uint32_t)(sizeof(VIDEORECBMPHDR) + sizeof(VIDEORECBMPDIBHDR)); 1512 1513 bmpDIBHdr.u32Size = sizeof(VIDEORECBMPDIBHDR); 1514 bmpDIBHdr.u32Width = w; 1515 bmpDIBHdr.u32Height = h; 1516 bmpDIBHdr.u16Planes = 1; 1517 bmpDIBHdr.u16BitCount = uBPP; 1518 bmpDIBHdr.u32XPelsPerMeter = 5000; 1519 bmpDIBHdr.u32YPelsPerMeter = 5000; 1520 1521 RTFILE fh; 1522 int rc2 = RTFileOpen(&fh, "/tmp/VideoRecFrame.bmp", 1523 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 1524 if (RT_SUCCESS(rc2)) 1525 { 1526 RTFileWrite(fh, &bmpHdr, sizeof(bmpHdr), NULL); 1527 RTFileWrite(fh, &bmpDIBHdr, sizeof(bmpDIBHdr), NULL); 1528 } 1529 #endif 1530 Assert(pFrame->cbRGBBuf >= w * h * uBytesPerPixel); 1335 1531 1336 1532 /* Do the copy. */ … … 1338 1534 { 1339 1535 /* Overflow check. */ 1340 Assert(offSrc + w * bpp <= uSrcHeight * uBytesPerLine); 1341 Assert(offDst + w * bpp <= pStream->Video.uDstHeight * pStream->Video.uDstWidth * bpp); 1342 1343 memcpy(pStream->Video.pu8RgbBuf + offDst, puSrcData + offSrc, w * bpp); 1344 1536 Assert(offSrc + w * uBytesPerPixel <= uSrcHeight * uBytesPerLine); 1537 Assert(offDst + w * uBytesPerPixel <= pStream->Video.uHeight * pStream->Video.uWidth * uBytesPerPixel); 1538 1539 memcpy(pFrame->pu8RGBBuf + offDst, puSrcData + offSrc, w * uBytesPerPixel); 1540 1541 #ifdef VBOX_VIDEOREC_DUMP 1542 if (RT_SUCCESS(rc2)) 1543 RTFileWrite(fh, pFrame->pu8RGBBuf + offDst, w * uBytesPerPixel, NULL); 1544 #endif 1345 1545 offSrc += uBytesPerLine; 1346 offDst += pStream->Video.uDstWidth * bpp; 1347 } 1348 1349 pStream->uCurTimeStampMs = uTimeStampMs; 1350 1351 ASMAtomicWriteBool(&pStream->fHasVideoData, true); 1352 RTSemEventSignal(pCtx->WaitEvent); 1546 offDst += pStream->Video.uWidth * uBytesPerPixel; 1547 } 1548 1549 #ifdef VBOX_VIDEOREC_DUMP 1550 if (RT_SUCCESS(rc2)) 1551 RTFileClose(fh); 1552 #endif 1553 pFrame->uTimeStampMs = uTimeStampMs; 1554 pFrame->uWidth = uSrcWidth; 1555 pFrame->uHeight = uSrcHeight; 1556 1557 pStream->Video.fHasVideoData = true; 1353 1558 1354 1559 } while (0); 1355 1560 1356 ASMAtomicCmpXchgU32(&pCtx->enmState, VIDEORECSTS_IDLE, VIDEORECSTS_BUSY); 1561 int rc2 = RTCritSectLeave(&pStream->CritSect); 1562 if (RT_SUCCESS(rc2)) 1563 { 1564 if ( RT_SUCCESS(rc) 1565 && rc != VINF_TRY_AGAIN) /* Only signal the thread if operation was successful. */ 1566 { 1567 rc2 = RTSemEventSignal(pCtx->WaitEvent); 1568 } 1569 } 1570 1571 if (RT_SUCCESS(rc)) 1572 rc = rc2; 1357 1573 1358 1574 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.