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