Changeset 41953 in vbox for trunk/src/VBox
- Timestamp:
- Jun 28, 2012 10:22:52 AM (12 years ago)
- Location:
- trunk/src/VBox/Frontends/VBoxHeadless/VideoCapture
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxHeadless/VideoCapture/FFmpegFB.cpp
r33540 r41953 76 76 * it is called. 77 77 */ 78 #ifdef VBOX_WITH_VPX 78 79 FFmpegFB::FFmpegFB(ULONG width, ULONG height, ULONG bitrate, 79 80 com::Bstr filename) : … … 86 87 mFrameWidth(width), mFrameHeight(height), 87 88 mYUVFrameSize(width * height * 3 / 2), 88 mRGBBuffer(0), mpFormatContext(0), mpStream(0),89 mRGBBuffer(0), 89 90 mOutOfMemory(false), mToggle(false) 91 #else 92 FFmpegFB::FFmpegFB(ULONG width, ULONG height, ULONG bitrate, 93 com::Bstr filename) : 94 mpFormatContext(0), mpStream(0), 95 mfUrlOpen(false), 96 mBitRate(bitrate), 97 mPixelFormat(FramebufferPixelFormat_Opaque), 98 mBitsPerPixel(0), 99 mFileName(filename), 100 mBytesPerLine(0), 101 mFrameWidth(width), mFrameHeight(height), 102 mYUVFrameSize(width * height * 3 / 2),mRGBBuffer(0), 103 mOutOfMemory(false), mToggle(false) 104 #endif 90 105 { 91 106 ULONG cPixels = width * height; 92 107 108 #ifdef VBOX_WITH_VPX 109 Assert(width % 2 == 0 && height % 2 == 0); 110 /* For temporary RGB frame we allocate enough memory to deal with 111 RGB16 to RGB32 */ 112 mTempRGBBuffer = reinterpret_cast<uint8_t *>(malloc(cPixels * 4)); 113 if (mTempRGBBuffer == 0) 114 goto nomem_temp_rgb_buffer; 115 mYUVBuffer = reinterpret_cast<uint8_t *>(malloc(mYUVFrameSize)); 116 if (mYUVBuffer == 0) 117 goto nomem_yuv_buffer; 118 return; 119 120 /* C-based memory allocation and how to deal with it in C++ :) */ 121 nomem_yuv_buffer: 122 Log(("Failed to allocate memory for mYUVBuffer\n")); 123 free(mYUVBuffer); 124 nomem_temp_rgb_buffer: 125 Log(("Failed to allocate memory for mTempRGBBuffer\n")); 126 free(mTempRGBBuffer); 127 mOutOfMemory = true; 128 #else 93 129 LogFlow(("Creating FFmpegFB object %p, width=%lu, height=%lu\n", 94 130 this, (unsigned long) width, (unsigned long) height)); … … 124 160 Log(("Failed to allocate memory for mTempRGBBuffer\n")); 125 161 mOutOfMemory = true; 162 #endif 126 163 } 127 164 … … 133 170 { 134 171 LogFlow(("Destroying FFmpegFB object %p\n", this)); 172 #ifdef VBOX_WITH_VPX 173 /* Dummy update to make sure we get all the frame (timing). */ 174 NotifyUpdate(0, 0, 0, 0); 175 /* Write the last pending frame before exiting */ 176 int rc = do_rgb_to_yuv_conversion(); 177 if (rc == S_OK) 178 do_encoding_and_write(); 179 # if 1 180 /* Add another 10 seconds. */ 181 for (int i = 10*25; i > 0; i--) 182 do_encoding_and_write(); 183 # endif 184 Ebml_WriteWebMFileFooter(&ebml, 0); 185 if(ebml.stream) 186 fclose(ebml.stream); 187 vpx_codec_destroy(&mVpxCodec); 188 RTCritSectDelete(&mCritSect); 189 190 /* We have already freed the stream above */ 191 if (mTempRGBBuffer != 0) 192 free(mTempRGBBuffer); 193 if (mYUVBuffer != 0) 194 free(mYUVBuffer); 195 if (mRGBBuffer != 0) 196 RTMemFree(mRGBBuffer); 197 #else 135 198 if (mpFormatContext != 0) 136 199 { … … 143 206 if (rc == S_OK) 144 207 do_encoding_and_write(); 145 # if 1208 # if 1 146 209 /* Add another 10 seconds. */ 147 210 for (int i = 10*25; i > 0; i--) 148 211 do_encoding_and_write(); 149 # endif212 # endif 150 213 /* write a png file of the last frame */ 151 214 write_png(); … … 158 221 } 159 222 /* Changed sometime between 50.5.0 and 52.7.0 */ 160 # if LIBAVFORMAT_VERSION_INT >= (52 << 16)223 # if LIBAVFORMAT_VERSION_INT >= (52 << 16) 161 224 url_fclose(mpFormatContext->pb); 162 # else /* older version */225 # else /* older version */ 163 226 url_fclose(&mpFormatContext->pb); 164 # endif /* older version */227 # endif /* older version */ 165 228 } 166 229 av_free(mpFormatContext); … … 179 242 if (mRGBBuffer != 0) 180 243 RTMemFree(mRGBBuffer); 244 #endif 181 245 } 182 246 … … 201 265 if (mOutOfMemory == true) 202 266 return E_OUTOFMEMORY; 203 int rc = RTCritSectInit(&mCritSect); 267 int rc; 268 int rcOpenFile; 269 int rcOpenCodec; 270 271 #ifdef VBOX_WITH_VPX 272 mFrameCount = 0; 273 memset(&ebml, 0, sizeof(struct EbmlGlobal)); 274 ebml.last_pts_ms = -1; 275 rc = RTCritSectInit(&mCritSect); 276 AssertReturn(rc == VINF_SUCCESS, E_UNEXPECTED); 277 rcOpenFile = open_output_file(); 278 AssertReturn(rcOpenFile == S_OK, rcOpenFile); 279 rcOpenCodec = open_codec(); 280 AssertReturn(rcOpenCodec == S_OK, rcOpenCodec); 281 #else 282 rc = RTCritSectInit(&mCritSect); 204 283 AssertReturn(rc == VINF_SUCCESS, E_UNEXPECTED); 205 284 int rcSetupLibrary = setup_library(); … … 207 286 int rcSetupFormat = setup_output_format(); 208 287 AssertReturn(rcSetupFormat == S_OK, rcSetupFormat); 209 intrcOpenCodec = open_codec();288 rcOpenCodec = open_codec(); 210 289 AssertReturn(rcOpenCodec == S_OK, rcOpenCodec); 211 intrcOpenFile = open_output_file();290 rcOpenFile = open_output_file(); 212 291 AssertReturn(rcOpenFile == S_OK, rcOpenFile); 292 213 293 /* Fill in the picture data for the AVFrame - not particularly 214 294 elegant, but that is the API. */ 215 295 avpicture_fill((AVPicture *) mFrame, mYUVBuffer, PIX_FMT_YUV420P, 216 296 mFrameWidth, mFrameHeight); 297 #endif 298 217 299 /* Set the initial framebuffer size to the mpeg frame dimensions */ 218 300 BOOL finished; … … 536 618 switch (bitsPerPixel) 537 619 { 620 #ifdef VBOX_WITH_VPX 621 case 32: 622 mFFMPEGPixelFormat = VPX_IMG_FMT_RGB32; 623 Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB32\n")); 624 break; 625 case 24: 626 mFFMPEGPixelFormat = VPX_IMG_FMT_RGB24; 627 Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB24\n")); 628 break; 629 case 16: 630 mFFMPEGPixelFormat = VPX_IMG_FMT_RGB565; 631 Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB565\n")); 632 break; 633 #else 538 634 case 32: 539 635 mFFMPEGPixelFormat = PIX_FMT_RGBA32; … … 548 644 Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to PIX_FMT_RGB565\n")); 549 645 break; 646 #endif 550 647 default: 551 648 fallback = true; … … 572 669 /* we always fallback to 32bpp RGB */ 573 670 mPixelFormat = FramebufferPixelFormat_FOURCC_RGB; 671 #ifdef VBOX_WITH_VPX 672 mFFMPEGPixelFormat = VPX_IMG_FMT_RGB32; 673 Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to VPX_IMG_FMT_RGB32\n")); 674 #else 574 675 mFFMPEGPixelFormat = PIX_FMT_RGBA32; 575 676 Log2(("FFmpeg::RequestResize: setting ffmpeg pixel format to PIX_FMT_RGBA32\n")); 677 #endif 576 678 577 679 mBytesPerLine = w * 4; … … 637 739 ////////////////////////////////////////////////////////////////////////// 638 740 // 639 741 #ifndef VBOX_WITH_VPX 640 742 HRESULT FFmpegFB::setup_library() 641 743 { … … 669 771 AVOutputFormat *pOutFormat = guess_format(0, com::Utf8Str(mFileName).c_str(), 670 772 0); 671 # ifdef VBOX_SHOW_AVAILABLE_FORMATS773 # ifdef VBOX_SHOW_AVAILABLE_FORMATS 672 774 if (!pOutFormat) 673 775 { … … 676 778 list_formats(); 677 779 } 678 # endif780 # endif 679 781 AssertMsgReturn(pOutFormat != 0, 680 782 ("Could not deduce output format from file name\n"), … … 692 794 int rcSetParam = av_set_parameters(mpFormatContext, 0); 693 795 AssertReturn(rcSetParam >= 0, E_UNEXPECTED); 694 # if 1 /* bird: This works for me on the mac, please review & test elsewhere. */796 # if 1 /* bird: This works for me on the mac, please review & test elsewhere. */ 695 797 /* Fill in any uninitialized parameters like opt_output_file in ffpmeg.c does. 696 798 This fixes most of the buffer underflow warnings: … … 700 802 if (!mpFormatContext->max_delay) 701 803 mpFormatContext->max_delay = (int)(0.7 * AV_TIME_BASE); 702 # endif804 # endif 703 805 return S_OK; 704 806 } … … 722 824 return S_OK; 723 825 } 724 826 #endif 725 827 726 828 /** … … 734 836 HRESULT FFmpegFB::open_codec() 735 837 { 838 #ifdef VBOX_WITH_VPX 839 vpx_codec_err_t res; 840 /* Populate encoder configuration */ 841 if ((res = vpx_codec_enc_config_default(interface, &mVpxConfig, 0))) 842 { 843 LogFlow(("Failed to configure codec \n")); 844 AssertReturn(res == 0, E_UNEXPECTED); 845 } 846 847 mVpxConfig.rc_target_bitrate = 512; 848 mVpxConfig.g_w = mFrameWidth; 849 mVpxConfig.g_h = mFrameHeight; 850 mVpxConfig.g_timebase.den = 30; 851 mVpxConfig.g_timebase.num = 1; 852 mVpxConfig.g_threads = 8; 853 854 vpx_rational ebmlFPS = mVpxConfig.g_timebase; 855 struct vpx_rational arg_framerate = {30, 1}; 856 Ebml_WriteWebMFileHeader(&ebml, &mVpxConfig, &arg_framerate); 857 mDuration = (float)arg_framerate.den / (float)arg_framerate.num * 1000; 858 859 /* Initialize codec */ 860 if (vpx_codec_enc_init(&mVpxCodec, interface, &mVpxConfig, 0)) 861 { 862 LogFlow(("Failed to initialize encoder")); 863 AssertReturn(res == 0, E_UNEXPECTED); 864 } 865 #else 736 866 Assert(mpFormatContext != 0); 737 867 Assert(mpStream != 0); … … 740 870 AssertReturn(pCodecContext != 0, E_UNEXPECTED); 741 871 AVCodec *pCodec = avcodec_find_encoder(pOutFormat->video_codec); 742 # ifdef VBOX_SHOW_AVAILABLE_FORMATS872 # ifdef VBOX_SHOW_AVAILABLE_FORMATS 743 873 if (!pCodec) 744 874 { … … 747 877 list_formats(); 748 878 } 749 # endif879 # endif 750 880 AssertReturn(pCodec != 0, E_UNEXPECTED); 751 881 pCodecContext->codec_id = pOutFormat->video_codec; … … 768 898 int rcOpenCodec = avcodec_open(pCodecContext, pCodec); 769 899 AssertReturn(rcOpenCodec >= 0, E_UNEXPECTED); 900 #endif 770 901 return S_OK; 771 902 } … … 782 913 HRESULT FFmpegFB::open_output_file() 783 914 { 915 #ifdef VBOX_WITH_VPX 916 char szFileName[RTPATH_MAX]; 917 strcpy(szFileName, com::Utf8Str(mFileName).c_str()); 918 ebml.stream = fopen(szFileName, "wb"); 919 if (!ebml.stream) 920 { 921 LogFlow(("Failed to open the output File \n")); 922 return E_FAIL; 923 } 924 return S_OK; 925 #else 784 926 char szFileName[RTPATH_MAX]; 785 927 Assert(mpFormatContext); … … 791 933 mfUrlOpen = true; 792 934 av_write_header(mpFormatContext); 935 #endif 793 936 return S_OK; 794 937 } … … 891 1034 switch (mFFMPEGPixelFormat) 892 1035 { 1036 #ifdef VBOX_WITH_VPX 1037 case VPX_IMG_FMT_RGB32: 1038 if (!FFmpegWriteYUV420p<FFmpegBGRA32Iter>(mFrameWidth, mFrameHeight, 1039 mYUVBuffer, mTempRGBBuffer)) 1040 return E_UNEXPECTED; 1041 break; 1042 case VPX_IMG_FMT_RGB24: 1043 if (!FFmpegWriteYUV420p<FFmpegBGR24Iter>(mFrameWidth, mFrameHeight, 1044 mYUVBuffer, mTempRGBBuffer)) 1045 return E_UNEXPECTED; 1046 break; 1047 case VPX_IMG_FMT_RGB565: 1048 if (!FFmpegWriteYUV420p<FFmpegBGR565Iter>(mFrameWidth, mFrameHeight, 1049 mYUVBuffer, mTempRGBBuffer)) 1050 return E_UNEXPECTED; 1051 break; 1052 #else 893 1053 case PIX_FMT_RGBA32: 894 1054 if (!FFmpegWriteYUV420p<FFmpegBGRA32Iter>(mFrameWidth, mFrameHeight, … … 906 1066 return E_UNEXPECTED; 907 1067 break; 1068 1069 #endif 908 1070 default: 909 1071 return E_UNEXPECTED; … … 912 1074 } 913 1075 914 915 1076 /** 916 1077 * Encode the YUV framebuffer as an MPEG frame and write it to the file. … … 920 1081 HRESULT FFmpegFB::do_encoding_and_write() 921 1082 { 922 AVCodecContext *pContext = mpStream->codec; 1083 923 1084 924 1085 /* A hack: ffmpeg mpeg2 only writes a frame if something has … … 930 1091 mYUVBuffer[0] &= 0xfe; 931 1092 mToggle = !mToggle; 1093 1094 #ifdef VBOX_WITH_VPX 1095 vpx_image_t VpxRawImage; 1096 vpx_codec_err_t res; 1097 const vpx_codec_cx_pkt_t *pkt; 1098 vpx_codec_iter_t iter = NULL; 1099 1100 if (mFrameWidth < 16 || mFrameWidth%2 || mFrameHeight <16 || mFrameHeight%2) 1101 LogFlow(("Invalid resolution: %ldx%ld", mFrameWidth, mFrameHeight)); 1102 1103 if (!vpx_img_alloc(&VpxRawImage, VPX_IMG_FMT_YV12, mFrameWidth, mFrameHeight, 1)) 1104 { 1105 LogFlow(("Faile tod allocate image", mFrameWidth, mFrameHeight)); 1106 return E_OUTOFMEMORY; 1107 } 1108 1109 if (mYUVBuffer != NULL) 1110 { 1111 AssertReturn(VpxRawImage.w*VpxRawImage.h*3/2 <= sizeof(mYUVFrameSize), E_UNEXPECTED); 1112 memcpy(VpxRawImage.planes[0], (uint8_t *)mYUVBuffer, VpxRawImage.w*VpxRawImage.h*3/2); 1113 } 1114 1115 if ((res = vpx_codec_encode(&mVpxCodec, &VpxRawImage , mFrameCount, 1116 mDuration, 0, VPX_DL_REALTIME))) 1117 { 1118 LogFlow(("Failed to encode: %s\n", vpx_codec_err_to_string(res))); 1119 AssertReturn(res != 0, E_UNEXPECTED); 1120 1121 } 1122 while ((pkt = vpx_codec_get_cx_data(&mVpxCodec, &iter))) 1123 { 1124 switch (pkt->kind) 1125 { 1126 case VPX_CODEC_CX_FRAME_PKT: 1127 Ebml_WriteWebMBlock(&ebml, &mVpxConfig, pkt); 1128 break; 1129 default: 1130 break; 1131 } 1132 } 1133 mFrameCount++; 1134 #else 1135 AVCodecContext *pContext = mpStream->codec; 932 1136 int cSize = avcodec_encode_video(pContext, mOutBuf, mYUVFrameSize * 2, 933 1137 mFrame); … … 953 1157 AssertReturn(rcWriteFrame == 0, E_UNEXPECTED); 954 1158 } 955 return S_OK; 956 } 957 958 1159 #endif 1160 return S_OK; 1161 } 1162 1163 #ifndef VBOX_WITH_VPX 959 1164 /** 960 1165 * Capture the current (i.e. the last) frame as a PNG file with the … … 1063 1268 return errorCode; 1064 1269 } 1065 1270 #endif 1066 1271 1067 1272 #ifdef VBOX_WITH_XPCOM -
trunk/src/VBox/Frontends/VBoxHeadless/VideoCapture/FFmpegFB.h
r41216 r41953 21 21 22 22 #include <VBox/com/VirtualBox.h> 23 23 #include "EbmlWriter.h" 24 24 #include <iprt/uuid.h> 25 25 … … 30 30 #include <iprt/critsect.h> 31 31 32 #ifdef DEBUG 33 # define VBOX_DEBUG_FF DEBUG 34 # include <avcodec.h> 35 # include <avformat.h> 36 # undef DEBUG 37 # define DEBUG VBOX_DEBUG_FF 38 #else /* DEBUG not defined */ 39 # include <avcodec.h> 40 # include <avformat.h> 41 #endif /* DEBUG not defined */ 32 #ifdef VBOX_WITH_VPX 33 #include <stdarg.h> 34 #include <string.h> 35 #define VPX_CODEC_DISABLE_COMPAT 1 36 #include <vp8cx.h> 37 #include <vpx_image.h> 38 #include <vpx_mem.h> 39 #define interface (vpx_codec_vp8_cx()) 40 #else 41 # ifdef DEBUG 42 # define VBOX_DEBUG_FF DEBUG 43 # include <avcodec.h> 44 # include <avformat.h> 45 # undef DEBUG 46 # define DEBUG VBOX_DEBUG_FF 47 # else /* DEBUG not defined */ 48 # include <avcodec.h> 49 # include <avformat.h> 50 # endif /* DEBUG not defined */ 51 #endif 52 42 53 43 54 class FFmpegFB : VBOX_SCRIPTABLE_IMPL(IFramebuffer) … … 89 100 90 101 STDMETHOD(ProcessVHWACommand)(BYTE *pCommand); 91 92 private: 102 public: 103 private: 104 #ifdef VBOX_WITH_VPX 105 EbmlGlobal ebml; 106 vpx_codec_ctx_t mVpxCodec; 107 vpx_codec_enc_cfg_t mVpxConfig; 108 FILE * mOutputFile; 109 unsigned long mDuration; 110 uint32_t mFrameCount; 111 112 #else 113 /** Pointer to ffmpeg's format information context */ 114 AVFormatContext *mpFormatContext; 115 /** ffmpeg context containing information about the stream */ 116 AVStream *mpStream; 117 /** Information for ffmpeg describing the current frame */ 118 AVFrame *mFrame; 119 120 HRESULT setup_library(); 121 HRESULT setup_output_format(); 122 HRESULT list_formats(); 123 #endif 93 124 /** true if url_fopen actually succeeded */ 94 125 bool mfUrlOpen; … … 131 162 /** time at which the last "real" frame was created */ 132 163 int64_t mLastTime; 133 /** Pointer to ffmpeg's format information context */134 AVFormatContext *mpFormatContext;135 /** ffmpeg context containing information about the stream */136 AVStream *mpStream;137 /** Information for ffmpeg describing the current frame */138 AVFrame *mFrame;139 164 /** ffmpeg pixel format of guest framebuffer */ 140 165 int mFFMPEGPixelFormat; … … 147 172 bool mToggle; 148 173 149 HRESULT setup_library(); 150 HRESULT setup_output_format(); 151 HRESULT list_formats(); 174 152 175 HRESULT open_codec(); 153 176 HRESULT open_output_file(); -
trunk/src/VBox/Frontends/VBoxHeadless/VideoCapture/Makefile.kmk
r41477 r41953 21 21 DLLS += VBoxFFmpegFB 22 22 VBoxFFmpegFB_TEMPLATE = VBOXMAINCLIENTDLL 23 VBoxFFmpegFB_SDKS = VBOX_FFMPEG VBOX_LIBPNG VBOX_ZLIB 24 VBoxFFmpegFB_SOURCES = FFmpegFB.cpp 23 #VBoxFFmpegFB_DEFS += \ 24 VBOX_WITH_VPX 25 VBoxFFmpegFB_SDKS = VBOX_FFMPEG VBOX_LIBPNG VBOX_ZLIB VBOX_VPX 26 VBoxFFmpegFB_SOURCES += \ 27 FFmpegFB.cpp \ 28 EbmlWriter.cpp 25 29 VBoxFFmpegFB_CXXFLAGS.linux += -fPIC 26 30
Note:
See TracChangeset
for help on using the changeset viewer.