#if !defined HAVE_CUDA || !defined WIN32\r
\r
cv::gpu::VideoWriter_GPU::VideoWriter_GPU() { throw_nogpu(); }\r
-cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string&, cv::Size, double) { throw_nogpu(); }\r
-cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string&, cv::Size, double, const EncoderParams&) { throw_nogpu(); }\r
-cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>&, cv::Size, double) { throw_nogpu(); }\r
-cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>&, cv::Size, double, const EncoderParams&) { throw_nogpu(); }\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string&, cv::Size, double, SurfaceFormat) { throw_nogpu(); }\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string&, cv::Size, double, const EncoderParams&, SurfaceFormat) { throw_nogpu(); }\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>&, cv::Size, double, SurfaceFormat) { throw_nogpu(); }\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>&, cv::Size, double, const EncoderParams&, SurfaceFormat) { throw_nogpu(); }\r
cv::gpu::VideoWriter_GPU::~VideoWriter_GPU() {}\r
-void cv::gpu::VideoWriter_GPU::open(const std::string&, cv::Size, double) { throw_nogpu(); }\r
-void cv::gpu::VideoWriter_GPU::open(const std::string&, cv::Size, double, const EncoderParams&) { throw_nogpu(); }\r
-void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>&, cv::Size, double) { throw_nogpu(); }\r
-void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>&, cv::Size, double, const EncoderParams&) { throw_nogpu(); }\r
+void cv::gpu::VideoWriter_GPU::open(const std::string&, cv::Size, double, SurfaceFormat) { throw_nogpu(); }\r
+void cv::gpu::VideoWriter_GPU::open(const std::string&, cv::Size, double, const EncoderParams&, SurfaceFormat) { throw_nogpu(); }\r
+void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>&, cv::Size, double, SurfaceFormat) { throw_nogpu(); }\r
+void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>&, cv::Size, double, const EncoderParams&, SurfaceFormat) { throw_nogpu(); }\r
bool cv::gpu::VideoWriter_GPU::isOpened() const { return false; }\r
void cv::gpu::VideoWriter_GPU::close() {}\r
void cv::gpu::VideoWriter_GPU::write(const cv::gpu::GpuMat&, bool) { throw_nogpu(); }\r
class cv::gpu::VideoWriter_GPU::Impl\r
{\r
public:\r
- Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, CodecType codec = H264);\r
- Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, const EncoderParams& params, CodecType codec = H264);\r
+ Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, SurfaceFormat format, CodecType codec = H264);\r
+ Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec = H264);\r
\r
void write(const cv::gpu::GpuMat& image, bool lastFrame);\r
\r
cv::Size frameSize_;\r
\r
CodecType codec_;\r
+ SurfaceFormat inputFormat_;\r
NVVE_SurfaceFormat surfaceFormat_;\r
\r
NVEncoderWrapper encoder_;\r
static void NVENCAPI HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata);\r
};\r
\r
-cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, CodecType codec) :\r
+cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, SurfaceFormat format, CodecType codec) :\r
callback_(callback),\r
frameSize_(frameSize),\r
codec_(codec),\r
- surfaceFormat_(YV12),\r
+ inputFormat_(format),\r
cuCtxLock_(0)\r
{\r
+ surfaceFormat_ = inputFormat_ == SF_BGR ? YV12 : static_cast<NVVE_SurfaceFormat>(inputFormat_);\r
+\r
initEncoder(fps);\r
\r
initGpuMemory();\r
createHWEncoder();\r
}\r
\r
-cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, const EncoderParams& params, CodecType codec) :\r
+cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec) :\r
callback_(callback),\r
frameSize_(frameSize),\r
codec_(codec),\r
- surfaceFormat_(YV12),\r
+ inputFormat_(format),\r
cuCtxLock_(0)\r
{\r
+ surfaceFormat_ = inputFormat_ == SF_BGR ? YV12 : static_cast<NVVE_SurfaceFormat>(inputFormat_);\r
+\r
initEncoder(fps);\r
\r
setEncodeParams(params);\r
}\r
}}}\r
\r
+namespace\r
+{\r
+ // UYVY/YUY2 are both 4:2:2 formats (16bpc)\r
+ // Luma, U, V are interleaved, chroma is subsampled (w/2,h)\r
+ void copyUYVYorYUY2Frame(cv::Size frameSize, const cv::gpu::GpuMat& src, cv::gpu::GpuMat& dst)\r
+ {\r
+ CUresult res;\r
+\r
+ // Source is YUVY/YUY2 4:2:2, the YUV data in a packed and interleaved\r
+\r
+ // YUV Copy setup\r
+ CUDA_MEMCPY2D stCopyYUV422;\r
+ memset((void*)&stCopyYUV422, 0, sizeof(stCopyYUV422));\r
+ stCopyYUV422.srcXInBytes = 0;\r
+ stCopyYUV422.srcY = 0;\r
+ stCopyYUV422.srcMemoryType = CU_MEMORYTYPE_DEVICE;\r
+ stCopyYUV422.srcHost = 0;\r
+ stCopyYUV422.srcDevice = (CUdeviceptr) src.data;\r
+ stCopyYUV422.srcArray = 0;\r
+ stCopyYUV422.srcPitch = src.step;\r
+\r
+ stCopyYUV422.dstXInBytes = 0;\r
+ stCopyYUV422.dstY = 0;\r
+ stCopyYUV422.dstMemoryType = CU_MEMORYTYPE_DEVICE;\r
+ stCopyYUV422.dstHost = 0;\r
+ stCopyYUV422.dstDevice = (CUdeviceptr) dst.data;\r
+ stCopyYUV422.dstArray = 0;\r
+ stCopyYUV422.dstPitch = dst.step;\r
+\r
+ stCopyYUV422.WidthInBytes = frameSize.width * 2;\r
+ stCopyYUV422.Height = frameSize.height;\r
+\r
+ // DMA Luma/Chroma\r
+ res = cuMemcpy2D(&stCopyYUV422);\r
+ CV_Assert( res == CUDA_SUCCESS );\r
+ }\r
+\r
+ // YV12/IYUV are both 4:2:0 planar formats (12bpc)\r
+ // Luma, U, V chroma planar (12bpc), chroma is subsampled (w/2,h/2)\r
+ void copyYV12orIYUVFrame(cv::Size frameSize, const cv::gpu::GpuMat& src, cv::gpu::GpuMat& dst)\r
+ {\r
+ CUresult res;\r
+\r
+ // Source is YV12/IYUV, this native format is converted to NV12 format by the video encoder\r
+\r
+ // (1) luma copy setup\r
+ CUDA_MEMCPY2D stCopyLuma;\r
+ memset((void*)&stCopyLuma, 0, sizeof(stCopyLuma));\r
+ stCopyLuma.srcXInBytes = 0;\r
+ stCopyLuma.srcY = 0;\r
+ stCopyLuma.srcMemoryType = CU_MEMORYTYPE_DEVICE;\r
+ stCopyLuma.srcHost = 0;\r
+ stCopyLuma.srcDevice = (CUdeviceptr) src.data;\r
+ stCopyLuma.srcArray = 0;\r
+ stCopyLuma.srcPitch = src.step;\r
+\r
+ stCopyLuma.dstXInBytes = 0;\r
+ stCopyLuma.dstY = 0;\r
+ stCopyLuma.dstMemoryType = CU_MEMORYTYPE_DEVICE;\r
+ stCopyLuma.dstHost = 0;\r
+ stCopyLuma.dstDevice = (CUdeviceptr) dst.data;\r
+ stCopyLuma.dstArray = 0;\r
+ stCopyLuma.dstPitch = dst.step;\r
+\r
+ stCopyLuma.WidthInBytes = frameSize.width;\r
+ stCopyLuma.Height = frameSize.height;\r
+\r
+ // (2) chroma copy setup, U/V can be done together\r
+ CUDA_MEMCPY2D stCopyChroma;\r
+ memset((void*)&stCopyChroma, 0, sizeof(stCopyChroma));\r
+ stCopyChroma.srcXInBytes = 0;\r
+ stCopyChroma.srcY = frameSize.height << 1; // U/V chroma offset\r
+ stCopyChroma.srcMemoryType = CU_MEMORYTYPE_DEVICE;\r
+ stCopyChroma.srcHost = 0;\r
+ stCopyChroma.srcDevice = (CUdeviceptr) src.data;\r
+ stCopyChroma.srcArray = 0;\r
+ stCopyChroma.srcPitch = src.step >> 1; // chroma is subsampled by 2 (but it has U/V are next to each other)\r
+\r
+ stCopyChroma.dstXInBytes = 0;\r
+ stCopyChroma.dstY = frameSize.height << 1; // chroma offset (srcY*srcPitch now points to the chroma planes)\r
+ stCopyChroma.dstMemoryType = CU_MEMORYTYPE_DEVICE;\r
+ stCopyChroma.dstHost = 0;\r
+ stCopyChroma.dstDevice = (CUdeviceptr) dst.data;\r
+ stCopyChroma.dstArray = 0;\r
+ stCopyChroma.dstPitch = dst.step >> 1;\r
+\r
+ stCopyChroma.WidthInBytes = frameSize.width >> 1;\r
+ stCopyChroma.Height = frameSize.height; // U/V are sent together\r
+\r
+ // DMA Luma\r
+ res = cuMemcpy2D(&stCopyLuma);\r
+ CV_Assert( res == CUDA_SUCCESS );\r
+\r
+ // DMA Chroma channels (UV side by side)\r
+ res = cuMemcpy2D(&stCopyChroma);\r
+ CV_Assert( res == CUDA_SUCCESS );\r
+ }\r
+\r
+ // NV12 is 4:2:0 format (12bpc)\r
+ // Luma followed by U/V chroma interleaved (12bpc), chroma is subsampled (w/2,h/2)\r
+ void copyNV12Frame(cv::Size frameSize, const cv::gpu::GpuMat& src, cv::gpu::GpuMat& dst)\r
+ {\r
+ CUresult res;\r
+\r
+ // Source is NV12 in pitch linear memory\r
+ // 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\r
+\r
+ // Luma/Chroma can be done in a single transfer\r
+ CUDA_MEMCPY2D stCopyNV12;\r
+ memset((void*)&stCopyNV12, 0, sizeof(stCopyNV12));\r
+ stCopyNV12.srcXInBytes = 0;\r
+ stCopyNV12.srcY = 0;\r
+ stCopyNV12.srcMemoryType = CU_MEMORYTYPE_DEVICE;\r
+ stCopyNV12.srcHost = 0;\r
+ stCopyNV12.srcDevice = (CUdeviceptr) src.data;\r
+ stCopyNV12.srcArray = 0;\r
+ stCopyNV12.srcPitch = src.step;\r
+\r
+ stCopyNV12.dstXInBytes = 0;\r
+ stCopyNV12.dstY = 0;\r
+ stCopyNV12.dstMemoryType = CU_MEMORYTYPE_DEVICE;\r
+ stCopyNV12.dstHost = 0;\r
+ stCopyNV12.dstDevice = (CUdeviceptr) dst.data;\r
+ stCopyNV12.dstArray = 0;\r
+ stCopyNV12.dstPitch = dst.step;\r
+\r
+ stCopyNV12.WidthInBytes = frameSize.width;\r
+ stCopyNV12.Height =(frameSize.height * 3) >> 1;\r
+\r
+ // DMA Luma/Chroma\r
+ res = cuMemcpy2D(&stCopyNV12);\r
+ CV_Assert( res == CUDA_SUCCESS );\r
+ }\r
+}\r
+\r
void cv::gpu::VideoWriter_GPU::Impl::write(const cv::gpu::GpuMat& frame, bool lastFrame)\r
{\r
- CV_Assert( frame.size() == frameSize_ );\r
- CV_Assert( frame.type() == CV_8UC1 || frame.type() == CV_8UC3 || frame.type() == CV_8UC4 );\r
+ if (inputFormat_ == SF_BGR)\r
+ {\r
+ CV_Assert( frame.size() == frameSize_ );\r
+ CV_Assert( frame.type() == CV_8UC1 || frame.type() == CV_8UC3 || frame.type() == CV_8UC4 );\r
+ }\r
+ else\r
+ {\r
+ CV_Assert( frame.size() == videoFrame_.size() );\r
+ CV_Assert( frame.type() == videoFrame_.type() );\r
+ }\r
\r
NVVE_EncodeFrameParams efparams;\r
efparams.Width = frameSize_.width;\r
CUresult res = cuvidCtxLock(cuCtxLock_, 0);\r
CV_Assert( res == CUDA_SUCCESS );\r
\r
- if (surfaceFormat_ == YV12)\r
+ if (inputFormat_ == SF_BGR)\r
cv::gpu::device::video_encoding::YV12_gpu(frame, frame.channels(), videoFrame_);\r
+ else\r
+ {\r
+ switch (surfaceFormat_)\r
+ {\r
+ case UYVY: // UYVY (4:2:2)\r
+ case YUY2: // YUY2 (4:2:2)\r
+ copyUYVYorYUY2Frame(frameSize_, frame, videoFrame_);\r
+ break;\r
+\r
+ case YV12: // YV12 (4:2:0), Y V U\r
+ case IYUV: // IYUV (4:2:0), Y U V\r
+ copyYV12orIYUVFrame(frameSize_, frame, videoFrame_);\r
+ break;\r
+\r
+ case NV12: // NV12 (4:2:0)\r
+ copyNV12Frame(frameSize_, frame, videoFrame_);\r
+ break;\r
+ }\r
+ }\r
\r
res = cuvidCtxUnlock(cuCtxLock_, 0);\r
CV_Assert( res == CUDA_SUCCESS );\r
\r
struct OutputMediaStream_FFMPEG* stream_;\r
std::vector<uchar> buf_;\r
+ bool isKeyFrame_;\r
};\r
\r
namespace\r
}\r
\r
EncoderCallBackFFMPEG::EncoderCallBackFFMPEG(const std::string& fileName, cv::Size frameSize, double fps) :\r
- stream_(0)\r
+ stream_(0), isKeyFrame_(false)\r
{\r
int buf_size = std::max(frameSize.area() * 4, 1024 * 1024);\r
buf_.resize(buf_size);\r
\r
void EncoderCallBackFFMPEG::releaseBitStream(unsigned char* data, int size)\r
{\r
- write_OutputMediaStream_FFMPEG_p(stream_, data, size);\r
+ write_OutputMediaStream_FFMPEG_p(stream_, data, size, isKeyFrame_);\r
}\r
\r
void EncoderCallBackFFMPEG::onBeginFrame(int frameNumber, PicType picType)\r
{\r
+ isKeyFrame_ = picType == IFRAME;\r
}\r
\r
void EncoderCallBackFFMPEG::onEndFrame(int frameNumber, PicType picType)\r
{\r
}\r
\r
-cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps)\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps, SurfaceFormat format)\r
{\r
- open(fileName, frameSize, fps);\r
+ open(fileName, frameSize, fps, format);\r
}\r
\r
-cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params)\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format)\r
{\r
- open(fileName, frameSize, fps, params);\r
+ open(fileName, frameSize, fps, params, format);\r
}\r
\r
-cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps)\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, SurfaceFormat format)\r
{\r
- open(encoderCallback, frameSize, fps);\r
+ open(encoderCallback, frameSize, fps, format);\r
}\r
\r
-cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params)\r
+cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format)\r
{\r
- open(encoderCallback, frameSize, fps, params);\r
+ open(encoderCallback, frameSize, fps, params, format);\r
}\r
\r
cv::gpu::VideoWriter_GPU::~VideoWriter_GPU()\r
close();\r
}\r
\r
-void cv::gpu::VideoWriter_GPU::open(const std::string& fileName, cv::Size frameSize, double fps)\r
+void cv::gpu::VideoWriter_GPU::open(const std::string& fileName, cv::Size frameSize, double fps, SurfaceFormat format)\r
{\r
close();\r
cv::Ptr<EncoderCallBack> encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps));\r
- open(encoderCallback, frameSize, fps);\r
+ open(encoderCallback, frameSize, fps, format);\r
}\r
\r
-void cv::gpu::VideoWriter_GPU::open(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params)\r
+void cv::gpu::VideoWriter_GPU::open(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format)\r
{\r
close();\r
cv::Ptr<EncoderCallBack> encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps));\r
- open(encoderCallback, frameSize, fps, params);\r
+ open(encoderCallback, frameSize, fps, params, format);\r
}\r
\r
-void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps)\r
+void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, SurfaceFormat format)\r
{\r
close();\r
- impl_.reset(new Impl(encoderCallback, frameSize, fps));\r
+ impl_.reset(new Impl(encoderCallback, frameSize, fps, format));\r
}\r
\r
-void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params)\r
+void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format)\r
{\r
close();\r
- impl_.reset(new Impl(encoderCallback, frameSize, fps, params));\r
+ impl_.reset(new Impl(encoderCallback, frameSize, fps, params, format));\r
}\r
\r
bool cv::gpu::VideoWriter_GPU::isOpened() const\r