• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
EncoderParams()52 cv::cudacodec::EncoderParams::EncoderParams() { throw_no_cuda(); }
EncoderParams(const String &)53 cv::cudacodec::EncoderParams::EncoderParams(const String&) { throw_no_cuda(); }
load(const String &)54 void cv::cudacodec::EncoderParams::load(const String&) { throw_no_cuda(); }
save(const String &) const55 void cv::cudacodec::EncoderParams::save(const String&) const { throw_no_cuda(); }
56 
createVideoWriter(const String &,Size,double,SurfaceFormat)57 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const String&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
createVideoWriter(const String &,Size,double,const EncoderParams &,SurfaceFormat)58 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const String&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
59 
createVideoWriter(const Ptr<EncoderCallBack> &,Size,double,SurfaceFormat)60 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
createVideoWriter(const Ptr<EncoderCallBack> &,Size,double,const EncoderParams &,SurfaceFormat)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:
NVEncoderWrapper()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 
~NVEncoderWrapper()88         ~NVEncoderWrapper()
89         {
90             if (encoder_)
91                 NVDestroyEncoder(encoder_);
92         }
93 
operator NVEncoder() const94         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 
VideoWriterImpl(const Ptr<EncoderCallBack> & callback,Size frameSize,double fps,SurfaceFormat format,CodecType codec)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 
VideoWriterImpl(const Ptr<EncoderCallBack> & callback,Size frameSize,double fps,const EncoderParams & params,SurfaceFormat format,CodecType codec)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 
initEncoder(double fps)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 
setEncodeParams(const EncoderParams & params)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 
getEncoderParams() const321     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 
initGpuMemory()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 
initCallBacks()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 
createHWEncoder()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)
copyUYVYorYUY2Frame(Size frameSize,const GpuMat & src,GpuMat & dst)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)
copyYV12orIYUVFrame(Size frameSize,const GpuMat & src,GpuMat & dst)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)
copyNV12Frame(Size frameSize,const GpuMat & src,GpuMat & dst)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 
write(InputArray _frame,bool lastFrame)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 
HandleAcquireBitStream(int * pBufferSize,void * pUserdata)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 
HandleReleaseBitStream(int nBytesInBuffer,unsigned char * cb,void * pUserdata)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 
HandleOnBeginFrame(const NVVE_BeginFrameInfo * pbfi,void * pUserdata)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 
HandleOnEndFrame(const NVVE_EndFrameInfo * pefi,void * pUserdata)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 
init_MediaStream_FFMPEG()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 
EncoderCallBackFFMPEG(const String & fileName,Size frameSize,double fps)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 
~EncoderCallBackFFMPEG()779     EncoderCallBackFFMPEG::~EncoderCallBackFFMPEG()
780     {
781         release_OutputMediaStream_FFMPEG_p(stream_);
782     }
783 
acquireBitStream(int * bufferSize)784     unsigned char* EncoderCallBackFFMPEG::acquireBitStream(int* bufferSize)
785     {
786         *bufferSize = static_cast<int>(buf_.size());
787         return &buf_[0];
788     }
789 
releaseBitStream(unsigned char * data,int size)790     void EncoderCallBackFFMPEG::releaseBitStream(unsigned char* data, int size)
791     {
792         write_OutputMediaStream_FFMPEG_p(stream_, data, size, isKeyFrame_);
793     }
794 
onBeginFrame(int frameNumber,PicType picType)795     void EncoderCallBackFFMPEG::onBeginFrame(int frameNumber, PicType picType)
796     {
797         (void) frameNumber;
798         isKeyFrame_ = (picType == IFRAME);
799     }
800 
onEndFrame(int frameNumber,PicType picType)801     void EncoderCallBackFFMPEG::onEndFrame(int frameNumber, PicType picType)
802     {
803         (void) frameNumber;
804         (void) picType;
805     }
806 }
807 
808 ///////////////////////////////////////////////////////////////////////////
809 // EncoderParams
810 
EncoderParams()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 
EncoderParams(const String & configFile)834 cv::cudacodec::EncoderParams::EncoderParams(const String& configFile)
835 {
836     load(configFile);
837 }
838 
load(const String & configFile)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 
save(const String & configFile) const865 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 
createVideoWriter(const String & fileName,Size frameSize,double fps,SurfaceFormat format)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 
createVideoWriter(const String & fileName,Size frameSize,double fps,const EncoderParams & params,SurfaceFormat format)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 
createVideoWriter(const Ptr<EncoderCallBack> & encoderCallback,Size frameSize,double fps,SurfaceFormat format)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 
createVideoWriter(const Ptr<EncoderCallBack> & encoderCallback,Size frameSize,double fps,const EncoderParams & params,SurfaceFormat format)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