Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                          License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
     14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
     15 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
     16 // Third party copyrights are property of their respective owners.
     17 //
     18 // Redistribution and use in source and binary forms, with or without modification,
     19 // are permitted provided that the following conditions are met:
     20 //
     21 //   * Redistribution's of source code must retain the above copyright notice,
     22 //     this list of conditions and the following disclaimer.
     23 //
     24 //   * Redistribution's in binary form must reproduce the above copyright notice,
     25 //     this list of conditions and the following disclaimer in the documentation
     26 //     and/or other materials provided with the distribution.
     27 //
     28 //   * The name of the copyright holders may not be used to endorse or promote products
     29 //     derived from this software without specific prior written permission.
     30 //
     31 // This software is provided by the copyright holders and contributors "as is" and
     32 // any express or implied warranties, including, but not limited to, the implied
     33 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     34 // In no event shall the Intel Corporation or contributors be liable for any direct,
     35 // indirect, incidental, special, exemplary, or consequential damages
     36 // (including, but not limited to, procurement of substitute goods or services;
     37 // loss of use, data, or profits; or business interruption) however caused
     38 // and on any theory of liability, whether in contract, strict liability,
     39 // or tort (including negligence or otherwise) arising in any way out of
     40 // the use of this software, even if advised of the possibility of such damage.
     41 //
     42 //M*/
     43 
     44 #include "precomp.hpp"
     45 
     46 using namespace cv;
     47 using namespace cv::cuda;
     48 using namespace cv::cudacodec;
     49 
     50 #if !defined(HAVE_NVCUVID) || !defined(WIN32)
     51 
     52 cv::cudacodec::EncoderParams::EncoderParams() { throw_no_cuda(); }
     53 cv::cudacodec::EncoderParams::EncoderParams(const String&) { throw_no_cuda(); }
     54 void cv::cudacodec::EncoderParams::load(const String&) { throw_no_cuda(); }
     55 void cv::cudacodec::EncoderParams::save(const String&) const { throw_no_cuda(); }
     56 
     57 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const String&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
     58 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const String&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
     59 
     60 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
     61 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
     62 
     63 #else // !defined HAVE_CUDA || !defined WIN32
     64 
     65 void RGB_to_YV12(const GpuMat& src, GpuMat& dst);
     66 
     67 ///////////////////////////////////////////////////////////////////////////
     68 // VideoWriterImpl
     69 
     70 namespace
     71 {
     72     class NVEncoderWrapper
     73     {
     74     public:
     75         NVEncoderWrapper() : encoder_(0)
     76         {
     77             int err;
     78 
     79             err = NVGetHWEncodeCaps();
     80             if (err)
     81                 CV_Error(Error::GpuNotSupported, "No CUDA capability present");
     82 
     83             // Create the Encoder API Interface
     84             err = NVCreateEncoder(&encoder_);
     85             CV_Assert( err == 0 );
     86         }
     87 
     88         ~NVEncoderWrapper()
     89         {
     90             if (encoder_)
     91                 NVDestroyEncoder(encoder_);
     92         }
     93 
     94         operator NVEncoder() const
     95         {
     96             return encoder_;
     97         }
     98 
     99     private:
    100         NVEncoder encoder_;
    101     };
    102 
    103     enum CodecType
    104     {
    105         MPEG1, // not supported yet
    106         MPEG2, // not supported yet
    107         MPEG4, // not supported yet
    108         H264
    109     };
    110 
    111     class VideoWriterImpl : public VideoWriter
    112     {
    113     public:
    114         VideoWriterImpl(const Ptr<EncoderCallBack>& callback, Size frameSize, double fps, SurfaceFormat format, CodecType codec = H264);
    115         VideoWriterImpl(const Ptr<EncoderCallBack>& callback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec = H264);
    116 
    117         void write(InputArray frame, bool lastFrame = false);
    118 
    119         EncoderParams getEncoderParams() const;
    120 
    121     private:
    122         void initEncoder(double fps);
    123         void setEncodeParams(const EncoderParams& params);
    124         void initGpuMemory();
    125         void initCallBacks();
    126         void createHWEncoder();
    127 
    128         Ptr<EncoderCallBack> callback_;
    129         Size frameSize_;
    130 
    131         CodecType codec_;
    132         SurfaceFormat inputFormat_;
    133         NVVE_SurfaceFormat surfaceFormat_;
    134 
    135         NVEncoderWrapper encoder_;
    136 
    137         GpuMat videoFrame_;
    138         CUvideoctxlock cuCtxLock_;
    139 
    140         // CallBacks
    141 
    142         static unsigned char* NVENCAPI HandleAcquireBitStream(int* pBufferSize, void* pUserdata);
    143         static void NVENCAPI HandleReleaseBitStream(int nBytesInBuffer, unsigned char* cb, void* pUserdata);
    144         static void NVENCAPI HandleOnBeginFrame(const NVVE_BeginFrameInfo* pbfi, void* pUserdata);
    145         static void NVENCAPI HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata);
    146     };
    147 
    148     VideoWriterImpl::VideoWriterImpl(const Ptr<EncoderCallBack>& callback, Size frameSize, double fps, SurfaceFormat format, CodecType codec) :
    149         callback_(callback),
    150         frameSize_(frameSize),
    151         codec_(codec),
    152         inputFormat_(format),
    153         cuCtxLock_(0)
    154     {
    155         surfaceFormat_ = (inputFormat_ == SF_BGR ? YV12 : static_cast<NVVE_SurfaceFormat>(inputFormat_));
    156 
    157         initEncoder(fps);
    158 
    159         initGpuMemory();
    160 
    161         initCallBacks();
    162 
    163         createHWEncoder();
    164     }
    165 
    166     VideoWriterImpl::VideoWriterImpl(const Ptr<EncoderCallBack>& callback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec) :
    167         callback_(callback),
    168         frameSize_(frameSize),
    169         codec_(codec),
    170         inputFormat_(format),
    171         cuCtxLock_(0)
    172     {
    173         surfaceFormat_ = (inputFormat_ == SF_BGR ? YV12 : static_cast<NVVE_SurfaceFormat>(inputFormat_));
    174 
    175         initEncoder(fps);
    176 
    177         setEncodeParams(params);
    178 
    179         initGpuMemory();
    180 
    181         initCallBacks();
    182 
    183         createHWEncoder();
    184     }
    185 
    186     void VideoWriterImpl::initEncoder(double fps)
    187     {
    188         int err;
    189 
    190         // Set codec
    191 
    192         static const unsigned long codecs_id[] =
    193         {
    194             NV_CODEC_TYPE_MPEG1, NV_CODEC_TYPE_MPEG2, NV_CODEC_TYPE_MPEG4, NV_CODEC_TYPE_H264, NV_CODEC_TYPE_VC1
    195         };
    196         err = NVSetCodec(encoder_, codecs_id[codec_]);
    197         if (err)
    198             CV_Error(Error::StsNotImplemented, "Codec format is not supported");
    199 
    200         // Set default params
    201 
    202         err = NVSetDefaultParam(encoder_);
    203         CV_Assert( err == 0 );
    204 
    205         // Set some common params
    206 
    207         int inputSize[] = { frameSize_.width, frameSize_.height };
    208         err = NVSetParamValue(encoder_, NVVE_IN_SIZE, &inputSize);
    209         CV_Assert( err == 0 );
    210         err = NVSetParamValue(encoder_, NVVE_OUT_SIZE, &inputSize);
    211         CV_Assert( err == 0 );
    212 
    213         int aspectRatio[] = { frameSize_.width, frameSize_.height, ASPECT_RATIO_DAR };
    214         err = NVSetParamValue(encoder_, NVVE_ASPECT_RATIO, &aspectRatio);
    215         CV_Assert( err == 0 );
    216 
    217         // FPS
    218 
    219         int frame_rate = static_cast<int>(fps + 0.5);
    220         int frame_rate_base = 1;
    221         while (fabs(static_cast<double>(frame_rate) / frame_rate_base) - fps > 0.001)
    222         {
    223             frame_rate_base *= 10;
    224             frame_rate = static_cast<int>(fps*frame_rate_base + 0.5);
    225         }
    226         int FrameRate[] = { frame_rate, frame_rate_base };
    227         err = NVSetParamValue(encoder_, NVVE_FRAME_RATE, &FrameRate);
    228         CV_Assert( err == 0 );
    229 
    230         // Select device for encoding
    231 
    232         int gpuID = getDevice();
    233         err = NVSetParamValue(encoder_, NVVE_FORCE_GPU_SELECTION, &gpuID);
    234         CV_Assert( err == 0 );
    235     }
    236 
    237     void VideoWriterImpl::setEncodeParams(const EncoderParams& params)
    238     {
    239         int err;
    240 
    241         int P_Interval = params.P_Interval;
    242         err = NVSetParamValue(encoder_, NVVE_P_INTERVAL, &P_Interval);
    243         CV_Assert( err == 0 );
    244 
    245         int IDR_Period = params.IDR_Period;
    246         err = NVSetParamValue(encoder_, NVVE_IDR_PERIOD, &IDR_Period);
    247         CV_Assert( err == 0 );
    248 
    249         int DynamicGOP = params.DynamicGOP;
    250         err = NVSetParamValue(encoder_, NVVE_DYNAMIC_GOP, &DynamicGOP);
    251         CV_Assert( err == 0 );
    252 
    253         NVVE_RateCtrlType RCType = static_cast<NVVE_RateCtrlType>(params.RCType);
    254         err = NVSetParamValue(encoder_, NVVE_RC_TYPE, &RCType);
    255         CV_Assert( err == 0 );
    256 
    257         int AvgBitrate = params.AvgBitrate;
    258         err = NVSetParamValue(encoder_, NVVE_AVG_BITRATE, &AvgBitrate);
    259         CV_Assert( err == 0 );
    260 
    261         int PeakBitrate = params.PeakBitrate;
    262         err = NVSetParamValue(encoder_, NVVE_PEAK_BITRATE, &PeakBitrate);
    263         CV_Assert( err == 0 );
    264 
    265         int QP_Level_Intra = params.QP_Level_Intra;
    266         err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTRA, &QP_Level_Intra);
    267         CV_Assert( err == 0 );
    268 
    269         int QP_Level_InterP = params.QP_Level_InterP;
    270         err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTER_P, &QP_Level_InterP);
    271         CV_Assert( err == 0 );
    272 
    273         int QP_Level_InterB = params.QP_Level_InterB;
    274         err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTER_B, &QP_Level_InterB);
    275         CV_Assert( err == 0 );
    276 
    277         int DeblockMode = params.DeblockMode;
    278         err = NVSetParamValue(encoder_, NVVE_DEBLOCK_MODE, &DeblockMode);
    279         CV_Assert( err == 0 );
    280 
    281         int ProfileLevel = params.ProfileLevel;
    282         err = NVSetParamValue(encoder_, NVVE_PROFILE_LEVEL, &ProfileLevel);
    283         CV_Assert( err == 0 );
    284 
    285         int ForceIntra = params.ForceIntra;
    286         err = NVSetParamValue(encoder_, NVVE_FORCE_INTRA, &ForceIntra);
    287         CV_Assert( err == 0 );
    288 
    289         int ForceIDR = params.ForceIDR;
    290         err = NVSetParamValue(encoder_, NVVE_FORCE_IDR, &ForceIDR);
    291         CV_Assert( err == 0 );
    292 
    293         int ClearStat = params.ClearStat;
    294         err = NVSetParamValue(encoder_, NVVE_CLEAR_STAT, &ClearStat);
    295         CV_Assert( err == 0 );
    296 
    297         NVVE_DI_MODE DIMode = static_cast<NVVE_DI_MODE>(params.DIMode);
    298         err = NVSetParamValue(encoder_, NVVE_SET_DEINTERLACE, &DIMode);
    299         CV_Assert( err == 0 );
    300 
    301         if (params.Presets != -1)
    302         {
    303             NVVE_PRESETS_TARGET Presets = static_cast<NVVE_PRESETS_TARGET>(params.Presets);
    304             err = NVSetParamValue(encoder_, NVVE_PRESETS, &Presets);
    305             CV_Assert( err == 0 );
    306         }
    307 
    308         int DisableCabac = params.DisableCabac;
    309         err = NVSetParamValue(encoder_, NVVE_DISABLE_CABAC, &DisableCabac);
    310         CV_Assert( err == 0 );
    311 
    312         int NaluFramingType = params.NaluFramingType;
    313         err = NVSetParamValue(encoder_, NVVE_CONFIGURE_NALU_FRAMING_TYPE, &NaluFramingType);
    314         CV_Assert( err == 0 );
    315 
    316         int DisableSPSPPS = params.DisableSPSPPS;
    317         err = NVSetParamValue(encoder_, NVVE_DISABLE_SPS_PPS, &DisableSPSPPS);
    318         CV_Assert( err == 0 );
    319     }
    320 
    321     EncoderParams VideoWriterImpl::getEncoderParams() const
    322     {
    323         int err;
    324 
    325         EncoderParams params;
    326 
    327         int P_Interval;
    328         err = NVGetParamValue(encoder_, NVVE_P_INTERVAL, &P_Interval);
    329         CV_Assert( err == 0 );
    330         params.P_Interval = P_Interval;
    331 
    332         int IDR_Period;
    333         err = NVGetParamValue(encoder_, NVVE_IDR_PERIOD, &IDR_Period);
    334         CV_Assert( err == 0 );
    335         params.IDR_Period = IDR_Period;
    336 
    337         int DynamicGOP;
    338         err = NVGetParamValue(encoder_, NVVE_DYNAMIC_GOP, &DynamicGOP);
    339         CV_Assert( err == 0 );
    340         params.DynamicGOP = DynamicGOP;
    341 
    342         NVVE_RateCtrlType RCType;
    343         err = NVGetParamValue(encoder_, NVVE_RC_TYPE, &RCType);
    344         CV_Assert( err == 0 );
    345         params.RCType = RCType;
    346 
    347         int AvgBitrate;
    348         err = NVGetParamValue(encoder_, NVVE_AVG_BITRATE, &AvgBitrate);
    349         CV_Assert( err == 0 );
    350         params.AvgBitrate = AvgBitrate;
    351 
    352         int PeakBitrate;
    353         err = NVGetParamValue(encoder_, NVVE_PEAK_BITRATE, &PeakBitrate);
    354         CV_Assert( err == 0 );
    355         params.PeakBitrate = PeakBitrate;
    356 
    357         int QP_Level_Intra;
    358         err = NVGetParamValue(encoder_, NVVE_QP_LEVEL_INTRA, &QP_Level_Intra);
    359         CV_Assert( err == 0 );
    360         params.QP_Level_Intra = QP_Level_Intra;
    361 
    362         int QP_Level_InterP;
    363         err = NVGetParamValue(encoder_, NVVE_QP_LEVEL_INTER_P, &QP_Level_InterP);
    364         CV_Assert( err == 0 );
    365         params.QP_Level_InterP = QP_Level_InterP;
    366 
    367         int QP_Level_InterB;
    368         err = NVGetParamValue(encoder_, NVVE_QP_LEVEL_INTER_B, &QP_Level_InterB);
    369         CV_Assert( err == 0 );
    370         params.QP_Level_InterB = QP_Level_InterB;
    371 
    372         int DeblockMode;
    373         err = NVGetParamValue(encoder_, NVVE_DEBLOCK_MODE, &DeblockMode);
    374         CV_Assert( err == 0 );
    375         params.DeblockMode = DeblockMode;
    376 
    377         int ProfileLevel;
    378         err = NVGetParamValue(encoder_, NVVE_PROFILE_LEVEL, &ProfileLevel);
    379         CV_Assert( err == 0 );
    380         params.ProfileLevel = ProfileLevel;
    381 
    382         int ForceIntra;
    383         err = NVGetParamValue(encoder_, NVVE_FORCE_INTRA, &ForceIntra);
    384         CV_Assert( err == 0 );
    385         params.ForceIntra = ForceIntra;
    386 
    387         int ForceIDR;
    388         err = NVGetParamValue(encoder_, NVVE_FORCE_IDR, &ForceIDR);
    389         CV_Assert( err == 0 );
    390         params.ForceIDR = ForceIDR;
    391 
    392         int ClearStat;
    393         err = NVGetParamValue(encoder_, NVVE_CLEAR_STAT, &ClearStat);
    394         CV_Assert( err == 0 );
    395         params.ClearStat = ClearStat;
    396 
    397         NVVE_DI_MODE DIMode;
    398         err = NVGetParamValue(encoder_, NVVE_SET_DEINTERLACE, &DIMode);
    399         CV_Assert( err == 0 );
    400         params.DIMode = DIMode;
    401 
    402         params.Presets = -1;
    403 
    404         int DisableCabac;
    405         err = NVGetParamValue(encoder_, NVVE_DISABLE_CABAC, &DisableCabac);
    406         CV_Assert( err == 0 );
    407         params.DisableCabac = DisableCabac;
    408 
    409         int NaluFramingType;
    410         err = NVGetParamValue(encoder_, NVVE_CONFIGURE_NALU_FRAMING_TYPE, &NaluFramingType);
    411         CV_Assert( err == 0 );
    412         params.NaluFramingType = NaluFramingType;
    413 
    414         int DisableSPSPPS;
    415         err = NVGetParamValue(encoder_, NVVE_DISABLE_SPS_PPS, &DisableSPSPPS);
    416         CV_Assert( err == 0 );
    417         params.DisableSPSPPS = DisableSPSPPS;
    418 
    419         return params;
    420     }
    421 
    422     void VideoWriterImpl::initGpuMemory()
    423     {
    424         int err;
    425 
    426         // initialize context
    427         GpuMat temp(1, 1, CV_8U);
    428         temp.release();
    429 
    430         static const int bpp[] =
    431         {
    432             16, // UYVY, 4:2:2
    433             16, // YUY2, 4:2:2
    434             12, // YV12, 4:2:0
    435             12, // NV12, 4:2:0
    436             12, // IYUV, 4:2:0
    437         };
    438 
    439         CUcontext cuContext;
    440         cuSafeCall( cuCtxGetCurrent(&cuContext) );
    441 
    442         // Allocate the CUDA memory Pitched Surface
    443         if (surfaceFormat_ == UYVY || surfaceFormat_ == YUY2)
    444             videoFrame_.create(frameSize_.height, (frameSize_.width * bpp[surfaceFormat_]) / 8, CV_8UC1);
    445         else
    446             videoFrame_.create((frameSize_.height * bpp[surfaceFormat_]) / 8, frameSize_.width, CV_8UC1);
    447 
    448         // Create the Video Context Lock (used for synchronization)
    449         cuSafeCall( cuvidCtxLockCreate(&cuCtxLock_, cuContext) );
    450 
    451         // If we are using GPU Device Memory with NVCUVENC, it is necessary to create a
    452         // CUDA Context with a Context Lock cuvidCtxLock.  The Context Lock needs to be passed to NVCUVENC
    453 
    454         int iUseDeviceMem = 1;
    455         err = NVSetParamValue(encoder_, NVVE_DEVICE_MEMORY_INPUT, &iUseDeviceMem);
    456         CV_Assert( err == 0 );
    457 
    458         err = NVSetParamValue(encoder_, NVVE_DEVICE_CTX_LOCK, &cuCtxLock_);
    459         CV_Assert( err == 0 );
    460     }
    461 
    462     void VideoWriterImpl::initCallBacks()
    463     {
    464         NVVE_CallbackParams cb;
    465         memset(&cb, 0, sizeof(NVVE_CallbackParams));
    466 
    467         cb.pfnacquirebitstream = HandleAcquireBitStream;
    468         cb.pfnonbeginframe     = HandleOnBeginFrame;
    469         cb.pfnonendframe       = HandleOnEndFrame;
    470         cb.pfnreleasebitstream = HandleReleaseBitStream;
    471 
    472         NVRegisterCB(encoder_, cb, this);
    473     }
    474 
    475     void VideoWriterImpl::createHWEncoder()
    476     {
    477         int err;
    478 
    479         // Create the NVIDIA HW resources for Encoding on NVIDIA hardware
    480         err = NVCreateHWEncoder(encoder_);
    481         CV_Assert( err == 0 );
    482     }
    483 
    484     // UYVY/YUY2 are both 4:2:2 formats (16bpc)
    485     // Luma, U, V are interleaved, chroma is subsampled (w/2,h)
    486     void copyUYVYorYUY2Frame(Size frameSize, const GpuMat& src, GpuMat& dst)
    487     {
    488         // Source is YUVY/YUY2 4:2:2, the YUV data in a packed and interleaved
    489 
    490         // YUV Copy setup
    491         CUDA_MEMCPY2D stCopyYUV422;
    492         memset(&stCopyYUV422, 0, sizeof(CUDA_MEMCPY2D));
    493 
    494         stCopyYUV422.srcXInBytes          = 0;
    495         stCopyYUV422.srcY                 = 0;
    496         stCopyYUV422.srcMemoryType        = CU_MEMORYTYPE_DEVICE;
    497         stCopyYUV422.srcHost              = 0;
    498         stCopyYUV422.srcDevice            = (CUdeviceptr) src.data;
    499         stCopyYUV422.srcArray             = 0;
    500         stCopyYUV422.srcPitch             = src.step;
    501 
    502         stCopyYUV422.dstXInBytes          = 0;
    503         stCopyYUV422.dstY                 = 0;
    504         stCopyYUV422.dstMemoryType        = CU_MEMORYTYPE_DEVICE;
    505         stCopyYUV422.dstHost              = 0;
    506         stCopyYUV422.dstDevice            = (CUdeviceptr) dst.data;
    507         stCopyYUV422.dstArray             = 0;
    508         stCopyYUV422.dstPitch             = dst.step;
    509 
    510         stCopyYUV422.WidthInBytes         = frameSize.width * 2;
    511         stCopyYUV422.Height               = frameSize.height;
    512 
    513         // DMA Luma/Chroma
    514         cuSafeCall( cuMemcpy2D(&stCopyYUV422) );
    515     }
    516 
    517     // YV12/IYUV are both 4:2:0 planar formats (12bpc)
    518     // Luma, U, V chroma planar (12bpc), chroma is subsampled (w/2,h/2)
    519     void copyYV12orIYUVFrame(Size frameSize, const GpuMat& src, GpuMat& dst)
    520     {
    521         // Source is YV12/IYUV, this native format is converted to NV12 format by the video encoder
    522 
    523         // (1) luma copy setup
    524         CUDA_MEMCPY2D stCopyLuma;
    525         memset(&stCopyLuma, 0, sizeof(CUDA_MEMCPY2D));
    526 
    527         stCopyLuma.srcXInBytes          = 0;
    528         stCopyLuma.srcY                 = 0;
    529         stCopyLuma.srcMemoryType        = CU_MEMORYTYPE_DEVICE;
    530         stCopyLuma.srcHost              = 0;
    531         stCopyLuma.srcDevice            = (CUdeviceptr) src.data;
    532         stCopyLuma.srcArray             = 0;
    533         stCopyLuma.srcPitch             = src.step;
    534 
    535         stCopyLuma.dstXInBytes          = 0;
    536         stCopyLuma.dstY                 = 0;
    537         stCopyLuma.dstMemoryType        = CU_MEMORYTYPE_DEVICE;
    538         stCopyLuma.dstHost              = 0;
    539         stCopyLuma.dstDevice            = (CUdeviceptr) dst.data;
    540         stCopyLuma.dstArray             = 0;
    541         stCopyLuma.dstPitch             = dst.step;
    542 
    543         stCopyLuma.WidthInBytes         = frameSize.width;
    544         stCopyLuma.Height               = frameSize.height;
    545 
    546         // (2) chroma copy setup, U/V can be done together
    547         CUDA_MEMCPY2D stCopyChroma;
    548         memset(&stCopyChroma, 0, sizeof(CUDA_MEMCPY2D));
    549 
    550         stCopyChroma.srcXInBytes        = 0;
    551         stCopyChroma.srcY               = frameSize.height << 1; // U/V chroma offset
    552         stCopyChroma.srcMemoryType      = CU_MEMORYTYPE_DEVICE;
    553         stCopyChroma.srcHost            = 0;
    554         stCopyChroma.srcDevice          = (CUdeviceptr) src.data;
    555         stCopyChroma.srcArray           = 0;
    556         stCopyChroma.srcPitch           = src.step >> 1; // chroma is subsampled by 2 (but it has U/V are next to each other)
    557 
    558         stCopyChroma.dstXInBytes        = 0;
    559         stCopyChroma.dstY               = frameSize.height << 1; // chroma offset (srcY*srcPitch now points to the chroma planes)
    560         stCopyChroma.dstMemoryType      = CU_MEMORYTYPE_DEVICE;
    561         stCopyChroma.dstHost            = 0;
    562         stCopyChroma.dstDevice          = (CUdeviceptr) dst.data;
    563         stCopyChroma.dstArray           = 0;
    564         stCopyChroma.dstPitch           = dst.step >> 1;
    565 
    566         stCopyChroma.WidthInBytes       = frameSize.width >> 1;
    567         stCopyChroma.Height             = frameSize.height; // U/V are sent together
    568 
    569         // DMA Luma
    570         cuSafeCall( cuMemcpy2D(&stCopyLuma) );
    571 
    572         // DMA Chroma channels (UV side by side)
    573         cuSafeCall( cuMemcpy2D(&stCopyChroma) );
    574     }
    575 
    576     // NV12 is 4:2:0 format (12bpc)
    577     // Luma followed by U/V chroma interleaved (12bpc), chroma is subsampled (w/2,h/2)
    578     void copyNV12Frame(Size frameSize, const GpuMat& src, GpuMat& dst)
    579     {
    580         // Source is NV12 in pitch linear memory
    581         // Because we are assume input is NV12 (if we take input in the native format), the encoder handles NV12 as a native format in pitch linear memory
    582 
    583         // Luma/Chroma can be done in a single transfer
    584         CUDA_MEMCPY2D stCopyNV12;
    585         memset(&stCopyNV12, 0, sizeof(CUDA_MEMCPY2D));
    586 
    587         stCopyNV12.srcXInBytes          = 0;
    588         stCopyNV12.srcY                 = 0;
    589         stCopyNV12.srcMemoryType        = CU_MEMORYTYPE_DEVICE;
    590         stCopyNV12.srcHost              = 0;
    591         stCopyNV12.srcDevice            = (CUdeviceptr) src.data;
    592         stCopyNV12.srcArray             = 0;
    593         stCopyNV12.srcPitch             = src.step;
    594 
    595         stCopyNV12.dstXInBytes          = 0;
    596         stCopyNV12.dstY                 = 0;
    597         stCopyNV12.dstMemoryType        = CU_MEMORYTYPE_DEVICE;
    598         stCopyNV12.dstHost              = 0;
    599         stCopyNV12.dstDevice            = (CUdeviceptr) dst.data;
    600         stCopyNV12.dstArray             = 0;
    601         stCopyNV12.dstPitch             = dst.step;
    602 
    603         stCopyNV12.WidthInBytes         = frameSize.width;
    604         stCopyNV12.Height               = (frameSize.height * 3) >> 1;
    605 
    606         // DMA Luma/Chroma
    607         cuSafeCall( cuMemcpy2D(&stCopyNV12) );
    608     }
    609 
    610     void VideoWriterImpl::write(InputArray _frame, bool lastFrame)
    611     {
    612         GpuMat frame = _frame.getGpuMat();
    613 
    614         if (inputFormat_ == SF_BGR)
    615         {
    616             CV_Assert( frame.size() == frameSize_ );
    617             CV_Assert( frame.type() == CV_8UC1 || frame.type() == CV_8UC3 || frame.type() == CV_8UC4 );
    618         }
    619         else
    620         {
    621             CV_Assert( frame.size() == videoFrame_.size() );
    622             CV_Assert( frame.type() == videoFrame_.type() );
    623         }
    624 
    625         NVVE_EncodeFrameParams efparams;
    626         efparams.Width = frameSize_.width;
    627         efparams.Height = frameSize_.height;
    628         efparams.Pitch = static_cast<int>(videoFrame_.step);
    629         efparams.SurfFmt = surfaceFormat_;
    630         efparams.PictureStruc = FRAME_PICTURE;
    631         efparams.topfieldfirst =  0;
    632         efparams.repeatFirstField = 0;
    633         efparams.progressiveFrame = (surfaceFormat_ == NV12) ? 1 : 0;
    634         efparams.bLast = lastFrame;
    635         efparams.picBuf = 0; // Must be set to NULL in order to support device memory input
    636 
    637         // Don't forget we need to lock/unlock between memcopies
    638         cuSafeCall( cuvidCtxLock(cuCtxLock_, 0) );
    639 
    640         if (inputFormat_ == SF_BGR)
    641         {
    642             RGB_to_YV12(frame, videoFrame_);
    643         }
    644         else
    645         {
    646             switch (surfaceFormat_)
    647             {
    648             case UYVY: // UYVY (4:2:2)
    649             case YUY2: // YUY2 (4:2:2)
    650                 copyUYVYorYUY2Frame(frameSize_, frame, videoFrame_);
    651                 break;
    652 
    653             case YV12: // YV12 (4:2:0), Y V U
    654             case IYUV: // IYUV (4:2:0), Y U V
    655                 copyYV12orIYUVFrame(frameSize_, frame, videoFrame_);
    656                 break;
    657 
    658             case NV12: // NV12 (4:2:0)
    659                 copyNV12Frame(frameSize_, frame, videoFrame_);
    660                 break;
    661             }
    662         }
    663 
    664         cuSafeCall( cuvidCtxUnlock(cuCtxLock_, 0) );
    665 
    666         int err = NVEncodeFrame(encoder_, &efparams, 0, videoFrame_.data);
    667         CV_Assert( err == 0 );
    668     }
    669 
    670     unsigned char* NVENCAPI VideoWriterImpl::HandleAcquireBitStream(int* pBufferSize, void* pUserdata)
    671     {
    672         VideoWriterImpl* thiz = static_cast<VideoWriterImpl*>(pUserdata);
    673 
    674         return thiz->callback_->acquireBitStream(pBufferSize);
    675     }
    676 
    677     void NVENCAPI VideoWriterImpl::HandleReleaseBitStream(int nBytesInBuffer, unsigned char* cb, void* pUserdata)
    678     {
    679         VideoWriterImpl* thiz = static_cast<VideoWriterImpl*>(pUserdata);
    680 
    681         thiz->callback_->releaseBitStream(cb, nBytesInBuffer);
    682     }
    683 
    684     void NVENCAPI VideoWriterImpl::HandleOnBeginFrame(const NVVE_BeginFrameInfo* pbfi, void* pUserdata)
    685     {
    686         VideoWriterImpl* thiz = static_cast<VideoWriterImpl*>(pUserdata);
    687 
    688         thiz->callback_->onBeginFrame(pbfi->nFrameNumber, static_cast<EncoderCallBack::PicType>(pbfi->nPicType));
    689     }
    690 
    691     void NVENCAPI VideoWriterImpl::HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata)
    692     {
    693         VideoWriterImpl* thiz = static_cast<VideoWriterImpl*>(pUserdata);
    694 
    695         thiz->callback_->onEndFrame(pefi->nFrameNumber, static_cast<EncoderCallBack::PicType>(pefi->nPicType));
    696     }
    697 
    698     ///////////////////////////////////////////////////////////////////////////
    699     // FFMPEG
    700 
    701     class EncoderCallBackFFMPEG : public EncoderCallBack
    702     {
    703     public:
    704         EncoderCallBackFFMPEG(const String& fileName, Size frameSize, double fps);
    705         ~EncoderCallBackFFMPEG();
    706 
    707         unsigned char* acquireBitStream(int* bufferSize);
    708         void releaseBitStream(unsigned char* data, int size);
    709         void onBeginFrame(int frameNumber, PicType picType);
    710         void onEndFrame(int frameNumber, PicType picType);
    711 
    712     private:
    713         static bool init_MediaStream_FFMPEG();
    714 
    715         struct OutputMediaStream_FFMPEG* stream_;
    716         std::vector<uchar> buf_;
    717         bool isKeyFrame_;
    718 
    719         static Create_OutputMediaStream_FFMPEG_Plugin create_OutputMediaStream_FFMPEG_p;
    720         static Release_OutputMediaStream_FFMPEG_Plugin release_OutputMediaStream_FFMPEG_p;
    721         static Write_OutputMediaStream_FFMPEG_Plugin write_OutputMediaStream_FFMPEG_p;
    722     };
    723 
    724     Create_OutputMediaStream_FFMPEG_Plugin EncoderCallBackFFMPEG::create_OutputMediaStream_FFMPEG_p = 0;
    725     Release_OutputMediaStream_FFMPEG_Plugin EncoderCallBackFFMPEG::release_OutputMediaStream_FFMPEG_p = 0;
    726     Write_OutputMediaStream_FFMPEG_Plugin EncoderCallBackFFMPEG::write_OutputMediaStream_FFMPEG_p = 0;
    727 
    728     bool EncoderCallBackFFMPEG::init_MediaStream_FFMPEG()
    729     {
    730         static bool initialized = false;
    731 
    732         if (!initialized)
    733         {
    734             #if defined(WIN32) || defined(_WIN32)
    735                 const char* module_name = "opencv_ffmpeg"
    736                     CVAUX_STR(CV_VERSION_MAJOR) CVAUX_STR(CV_VERSION_MINOR) CVAUX_STR(CV_VERSION_REVISION)
    737                 #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)
    738                     "_64"
    739                 #endif
    740                     ".dll";
    741 
    742                 static HMODULE cvFFOpenCV = LoadLibrary(module_name);
    743 
    744                 if (cvFFOpenCV)
    745                 {
    746                     create_OutputMediaStream_FFMPEG_p =
    747                         (Create_OutputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "create_OutputMediaStream_FFMPEG");
    748                     release_OutputMediaStream_FFMPEG_p =
    749                         (Release_OutputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "release_OutputMediaStream_FFMPEG");
    750                     write_OutputMediaStream_FFMPEG_p =
    751                         (Write_OutputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "write_OutputMediaStream_FFMPEG");
    752 
    753                     initialized = create_OutputMediaStream_FFMPEG_p != 0 && release_OutputMediaStream_FFMPEG_p != 0 && write_OutputMediaStream_FFMPEG_p != 0;
    754                 }
    755             #elif defined(HAVE_FFMPEG)
    756                 create_OutputMediaStream_FFMPEG_p = create_OutputMediaStream_FFMPEG;
    757                 release_OutputMediaStream_FFMPEG_p = release_OutputMediaStream_FFMPEG;
    758                 write_OutputMediaStream_FFMPEG_p = write_OutputMediaStream_FFMPEG;
    759 
    760                 initialized = true;
    761             #endif
    762         }
    763 
    764         return initialized;
    765     }
    766 
    767     EncoderCallBackFFMPEG::EncoderCallBackFFMPEG(const String& fileName, Size frameSize, double fps) :
    768         stream_(0), isKeyFrame_(false)
    769     {
    770         int buf_size = std::max(frameSize.area() * 4, 1024 * 1024);
    771         buf_.resize(buf_size);
    772 
    773         CV_Assert( init_MediaStream_FFMPEG() );
    774 
    775         stream_ = create_OutputMediaStream_FFMPEG_p(fileName.c_str(), frameSize.width, frameSize.height, fps);
    776         CV_Assert( stream_ != 0 );
    777     }
    778 
    779     EncoderCallBackFFMPEG::~EncoderCallBackFFMPEG()
    780     {
    781         release_OutputMediaStream_FFMPEG_p(stream_);
    782     }
    783 
    784     unsigned char* EncoderCallBackFFMPEG::acquireBitStream(int* bufferSize)
    785     {
    786         *bufferSize = static_cast<int>(buf_.size());
    787         return &buf_[0];
    788     }
    789 
    790     void EncoderCallBackFFMPEG::releaseBitStream(unsigned char* data, int size)
    791     {
    792         write_OutputMediaStream_FFMPEG_p(stream_, data, size, isKeyFrame_);
    793     }
    794 
    795     void EncoderCallBackFFMPEG::onBeginFrame(int frameNumber, PicType picType)
    796     {
    797         (void) frameNumber;
    798         isKeyFrame_ = (picType == IFRAME);
    799     }
    800 
    801     void EncoderCallBackFFMPEG::onEndFrame(int frameNumber, PicType picType)
    802     {
    803         (void) frameNumber;
    804         (void) picType;
    805     }
    806 }
    807 
    808 ///////////////////////////////////////////////////////////////////////////
    809 // EncoderParams
    810 
    811 cv::cudacodec::EncoderParams::EncoderParams()
    812 {
    813     P_Interval = 3;
    814     IDR_Period = 15;
    815     DynamicGOP = 0;
    816     RCType = 1;
    817     AvgBitrate = 4000000;
    818     PeakBitrate = 10000000;
    819     QP_Level_Intra = 25;
    820     QP_Level_InterP = 28;
    821     QP_Level_InterB = 31;
    822     DeblockMode = 1;
    823     ProfileLevel = 65357;
    824     ForceIntra = 0;
    825     ForceIDR = 0;
    826     ClearStat = 0;
    827     DIMode = 1;
    828     Presets = 2;
    829     DisableCabac = 0;
    830     NaluFramingType = 0;
    831     DisableSPSPPS = 0;
    832 }
    833 
    834 cv::cudacodec::EncoderParams::EncoderParams(const String& configFile)
    835 {
    836     load(configFile);
    837 }
    838 
    839 void cv::cudacodec::EncoderParams::load(const String& configFile)
    840 {
    841     FileStorage fs(configFile, FileStorage::READ);
    842     CV_Assert( fs.isOpened() );
    843 
    844     read(fs["P_Interval"     ], P_Interval, 3);
    845     read(fs["IDR_Period"     ], IDR_Period, 15);
    846     read(fs["DynamicGOP"     ], DynamicGOP, 0);
    847     read(fs["RCType"         ], RCType, 1);
    848     read(fs["AvgBitrate"     ], AvgBitrate, 4000000);
    849     read(fs["PeakBitrate"    ], PeakBitrate, 10000000);
    850     read(fs["QP_Level_Intra" ], QP_Level_Intra, 25);
    851     read(fs["QP_Level_InterP"], QP_Level_InterP, 28);
    852     read(fs["QP_Level_InterB"], QP_Level_InterB, 31);
    853     read(fs["DeblockMode"    ], DeblockMode, 1);
    854     read(fs["ProfileLevel"   ], ProfileLevel, 65357);
    855     read(fs["ForceIntra"     ], ForceIntra, 0);
    856     read(fs["ForceIDR"       ], ForceIDR, 0);
    857     read(fs["ClearStat"      ], ClearStat, 0);
    858     read(fs["DIMode"         ], DIMode, 1);
    859     read(fs["Presets"        ], Presets, 2);
    860     read(fs["DisableCabac"   ], DisableCabac, 0);
    861     read(fs["NaluFramingType"], NaluFramingType, 0);
    862     read(fs["DisableSPSPPS"  ], DisableSPSPPS, 0);
    863 }
    864 
    865 void cv::cudacodec::EncoderParams::save(const String& configFile) const
    866 {
    867     FileStorage fs(configFile, FileStorage::WRITE);
    868     CV_Assert( fs.isOpened() );
    869 
    870     write(fs, "P_Interval"     , P_Interval);
    871     write(fs, "IDR_Period"     , IDR_Period);
    872     write(fs, "DynamicGOP"     , DynamicGOP);
    873     write(fs, "RCType"         , RCType);
    874     write(fs, "AvgBitrate"     , AvgBitrate);
    875     write(fs, "PeakBitrate"    , PeakBitrate);
    876     write(fs, "QP_Level_Intra" , QP_Level_Intra);
    877     write(fs, "QP_Level_InterP", QP_Level_InterP);
    878     write(fs, "QP_Level_InterB", QP_Level_InterB);
    879     write(fs, "DeblockMode"    , DeblockMode);
    880     write(fs, "ProfileLevel"   , ProfileLevel);
    881     write(fs, "ForceIntra"     , ForceIntra);
    882     write(fs, "ForceIDR"       , ForceIDR);
    883     write(fs, "ClearStat"      , ClearStat);
    884     write(fs, "DIMode"         , DIMode);
    885     write(fs, "Presets"        , Presets);
    886     write(fs, "DisableCabac"   , DisableCabac);
    887     write(fs, "NaluFramingType", NaluFramingType);
    888     write(fs, "DisableSPSPPS"  , DisableSPSPPS);
    889 }
    890 
    891 ///////////////////////////////////////////////////////////////////////////
    892 // createVideoWriter
    893 
    894 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const String& fileName, Size frameSize, double fps, SurfaceFormat format)
    895 {
    896     Ptr<EncoderCallBack> encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps));
    897     return createVideoWriter(encoderCallback, frameSize, fps, format);
    898 }
    899 
    900 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const String& fileName, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format)
    901 {
    902     Ptr<EncoderCallBack> encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps));
    903     return createVideoWriter(encoderCallback, frameSize, fps, params, format);
    904 }
    905 
    906 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>& encoderCallback, Size frameSize, double fps, SurfaceFormat format)
    907 {
    908     return makePtr<VideoWriterImpl>(encoderCallback, frameSize, fps, format);
    909 }
    910 
    911 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>& encoderCallback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format)
    912 {
    913     return makePtr<VideoWriterImpl>(encoderCallback, frameSize, fps, params, format);
    914 }
    915 
    916 #endif // !defined HAVE_CUDA || !defined WIN32
    917