refactored VideoWriter class (convert it to abstract interface)

This commit is contained in:
Vladislav Vinogradov 2013-04-22 14:04:27 +04:00
parent 7a07f1a9e7
commit e9a74c17f8
7 changed files with 769 additions and 891 deletions

View File

@ -5,80 +5,25 @@ Video Encoding
gpu::VideoWriter_GPU gpucodec::VideoWriter
--------------------- ---------------------
Video writer class. Video writer interface.
.. ocv:class:: gpu::VideoWriter_GPU .. ocv:class:: gpucodec::VideoWriter
The class uses H264 video codec. The implementation uses H264 video codec.
.. note:: Currently only Windows platform is supported. .. note:: Currently only Windows platform is supported.
gpu::VideoWriter_GPU::VideoWriter_GPU gpucodec::VideoWriter::write
------------------------------------- ----------------------------
Constructors.
.. ocv:function:: gpu::VideoWriter_GPU::VideoWriter_GPU()
.. ocv:function:: gpu::VideoWriter_GPU::VideoWriter_GPU(const String& fileName, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR)
.. ocv:function:: gpu::VideoWriter_GPU::VideoWriter_GPU(const String& fileName, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR)
.. ocv:function:: gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR)
.. ocv:function:: gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR)
:param fileName: Name of the output video file. Only AVI file format is supported.
:param frameSize: Size of the input video frames.
:param fps: Framerate of the created video stream.
:param params: Encoder parameters. See :ocv:struct:`gpu::VideoWriter_GPU::EncoderParams` .
:param format: Surface format of input frames ( ``SF_UYVY`` , ``SF_YUY2`` , ``SF_YV12`` , ``SF_NV12`` , ``SF_IYUV`` , ``SF_BGR`` or ``SF_GRAY``). BGR or gray frames will be converted to YV12 format before encoding, frames with other formats will be used as is.
:param encoderCallback: Callbacks for video encoder. See :ocv:class:`gpu::VideoWriter_GPU::EncoderCallBack` . Use it if you want to work with raw video stream.
The constructors initialize video writer. FFMPEG is used to write videos. User can implement own multiplexing with :ocv:class:`gpu::VideoWriter_GPU::EncoderCallBack` .
gpu::VideoWriter_GPU::open
--------------------------
Initializes or reinitializes video writer.
.. ocv:function:: void gpu::VideoWriter_GPU::open(const String& fileName, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR)
.. ocv:function:: void gpu::VideoWriter_GPU::open(const String& fileName, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR)
.. ocv:function:: void gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR)
.. ocv:function:: void gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR)
The method opens video writer. Parameters are the same as in the constructor :ocv:func:`gpu::VideoWriter_GPU::VideoWriter_GPU` . The method throws :ocv:class:`Exception` if error occurs.
gpu::VideoWriter_GPU::isOpened
------------------------------
Returns true if video writer has been successfully initialized.
.. ocv:function:: bool gpu::VideoWriter_GPU::isOpened() const
gpu::VideoWriter_GPU::close
---------------------------
Releases the video writer.
.. ocv:function:: void gpu::VideoWriter_GPU::close()
gpu::VideoWriter_GPU::write
---------------------------
Writes the next video frame. Writes the next video frame.
.. ocv:function:: void gpu::VideoWriter_GPU::write(const cv::gpu::GpuMat& image, bool lastFrame = false) .. ocv:function:: void gpucodec::VideoWriter::write(InputArray frame, bool lastFrame = false) = 0
:param image: The written frame. :param frame: The written frame.
:param lastFrame: Indicates that it is end of stream. The parameter can be ignored. :param lastFrame: Indicates that it is end of stream. The parameter can be ignored.
@ -86,9 +31,34 @@ The method write the specified image to video file. The image must have the same
gpu::VideoWriter_GPU::EncoderParams gpucodec::createVideoWriter
----------------------------------- ---------------------------
.. ocv:struct:: gpu::VideoWriter_GPU::EncoderParams Creates video writer.
.. ocv:function:: Ptr<gpucodec::VideoWriter> gpucodec::createVideoWriter(const String& fileName, Size frameSize, double fps, SurfaceFormat format = SF_BGR)
.. ocv:function:: Ptr<gpucodec::VideoWriter> gpucodec::createVideoWriter(const String& fileName, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR)
.. ocv:function:: Ptr<gpucodec::VideoWriter> gpucodec::createVideoWriter(const Ptr<EncoderCallBack>& encoderCallback, Size frameSize, double fps, SurfaceFormat format = SF_BGR)
.. ocv:function:: Ptr<gpucodec::VideoWriter> gpucodec::createVideoWriter(const Ptr<EncoderCallBack>& encoderCallback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR)
:param fileName: Name of the output video file. Only AVI file format is supported.
:param frameSize: Size of the input video frames.
:param fps: Framerate of the created video stream.
:param params: Encoder parameters. See :ocv:struct:`gpucodec::EncoderParams` .
:param format: Surface format of input frames ( ``SF_UYVY`` , ``SF_YUY2`` , ``SF_YV12`` , ``SF_NV12`` , ``SF_IYUV`` , ``SF_BGR`` or ``SF_GRAY``). BGR or gray frames will be converted to YV12 format before encoding, frames with other formats will be used as is.
:param encoderCallback: Callbacks for video encoder. See :ocv:class:`gpucodec::EncoderCallBack` . Use it if you want to work with raw video stream.
The constructors initialize video writer. FFMPEG is used to write videos. User can implement own multiplexing with :ocv:class:`gpucodec::EncoderCallBack` .
gpucodec::EncoderParams
-----------------------
.. ocv:struct:: gpucodec::EncoderParams
Different parameters for CUDA video encoder. :: Different parameters for CUDA video encoder. ::
@ -123,12 +93,12 @@ Different parameters for CUDA video encoder. ::
gpu::VideoWriter_GPU::EncoderParams::EncoderParams gpucodec::EncoderParams::EncoderParams
-------------------------------------------------- --------------------------------------
Constructors. Constructors.
.. ocv:function:: gpu::VideoWriter_GPU::EncoderParams::EncoderParams() .. ocv:function:: gpucodec::EncoderParams::EncoderParams()
.. ocv:function:: gpu::VideoWriter_GPU::EncoderParams::EncoderParams(const String& configFile) .. ocv:function:: gpucodec::EncoderParams::EncoderParams(const String& configFile)
:param configFile: Config file name. :param configFile: Config file name.
@ -136,29 +106,29 @@ Creates default parameters or reads parameters from config file.
gpu::VideoWriter_GPU::EncoderParams::load gpucodec::EncoderParams::load
----------------------------------------- -----------------------------
Reads parameters from config file. Reads parameters from config file.
.. ocv:function:: void gpu::VideoWriter_GPU::EncoderParams::load(const String& configFile) .. ocv:function:: void gpucodec::EncoderParams::load(const String& configFile)
:param configFile: Config file name. :param configFile: Config file name.
gpu::VideoWriter_GPU::EncoderParams::save gpucodec::EncoderParams::save
----------------------------------------- -----------------------------
Saves parameters to config file. Saves parameters to config file.
.. ocv:function:: void gpu::VideoWriter_GPU::EncoderParams::save(const String& configFile) const .. ocv:function:: void gpucodec::EncoderParams::save(const String& configFile) const
:param configFile: Config file name. :param configFile: Config file name.
gpu::VideoWriter_GPU::EncoderCallBack gpucodec::EncoderCallBack
------------------------------------- -------------------------
.. ocv:class:: gpu::VideoWriter_GPU::EncoderCallBack .. ocv:class:: gpucodec::EncoderCallBack
Callbacks for CUDA video encoder. :: Callbacks for CUDA video encoder. ::
@ -182,38 +152,38 @@ Callbacks for CUDA video encoder. ::
gpu::VideoWriter_GPU::EncoderCallBack::acquireBitStream gpucodec::EncoderCallBack::acquireBitStream
------------------------------------------------------- -------------------------------------------
Callback function to signal the start of bitstream that is to be encoded. Callback function to signal the start of bitstream that is to be encoded.
.. ocv:function:: virtual uchar* gpu::VideoWriter_GPU::EncoderCallBack::acquireBitStream(int* bufferSize) = 0 .. ocv:function:: virtual uchar* gpucodec::EncoderCallBack::acquireBitStream(int* bufferSize) = 0
Callback must allocate buffer for CUDA encoder and return pointer to it and it's size. Callback must allocate buffer for CUDA encoder and return pointer to it and it's size.
gpu::VideoWriter_GPU::EncoderCallBack::releaseBitStream gpucodec::EncoderCallBack::releaseBitStream
------------------------------------------------------- -------------------------------------------
Callback function to signal that the encoded bitstream is ready to be written to file. Callback function to signal that the encoded bitstream is ready to be written to file.
.. ocv:function:: virtual void gpu::VideoWriter_GPU::EncoderCallBack::releaseBitStream(unsigned char* data, int size) = 0 .. ocv:function:: virtual void gpucodec::EncoderCallBack::releaseBitStream(unsigned char* data, int size) = 0
gpu::VideoWriter_GPU::EncoderCallBack::onBeginFrame gpucodec::EncoderCallBack::onBeginFrame
--------------------------------------------------- ---------------------------------------
Callback function to signal that the encoding operation on the frame has started. Callback function to signal that the encoding operation on the frame has started.
.. ocv:function:: virtual void gpu::VideoWriter_GPU::EncoderCallBack::onBeginFrame(int frameNumber, PicType picType) = 0 .. ocv:function:: virtual void gpucodec::EncoderCallBack::onBeginFrame(int frameNumber, PicType picType) = 0
:param picType: Specify frame type (I-Frame, P-Frame or B-Frame). :param picType: Specify frame type (I-Frame, P-Frame or B-Frame).
gpu::VideoWriter_GPU::EncoderCallBack::onEndFrame gpucodec::EncoderCallBack::onEndFrame
------------------------------------------------- -------------------------------------
Callback function signals that the encoding operation on the frame has finished. Callback function signals that the encoding operation on the frame has finished.
.. ocv:function:: virtual void gpu::VideoWriter_GPU::EncoderCallBack::onEndFrame(int frameNumber, PicType picType) = 0 .. ocv:function:: virtual void gpucodec::EncoderCallBack::onEndFrame(int frameNumber, PicType picType) = 0
:param picType: Specify frame type (I-Frame, P-Frame or B-Frame). :param picType: Specify frame type (I-Frame, P-Frame or B-Frame).

View File

@ -12,6 +12,7 @@
// //
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners. // Third party copyrights are property of their respective owners.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
@ -51,19 +52,12 @@
#include "opencv2/core/gpu.hpp" #include "opencv2/core/gpu.hpp"
namespace cv { namespace gpu { namespace cv { namespace gpucodec {
////////////////////////////////// Video Encoding ////////////////////////////////// ////////////////////////////////// Video Encoding //////////////////////////////////
// Works only under Windows // Works only under Windows.
// Supports olny H264 video codec and AVI files // Supports olny H264 video codec and AVI files.
class CV_EXPORTS VideoWriter_GPU
{
public:
struct EncoderParams;
// Callbacks for video encoder, use it if you want to work with raw video stream
class EncoderCallBack;
enum SurfaceFormat enum SurfaceFormat
{ {
@ -76,24 +70,6 @@ public:
SF_GRAY = SF_BGR SF_GRAY = SF_BGR
}; };
VideoWriter_GPU();
VideoWriter_GPU(const String& fileName, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR);
VideoWriter_GPU(const String& fileName, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR);
VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR);
VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR);
~VideoWriter_GPU();
// all methods throws cv::Exception if error occurs
void open(const String& fileName, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR);
void open(const String& fileName, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR);
void open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR);
void open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR);
bool isOpened() const;
void close();
void write(const cv::gpu::GpuMat& image, bool lastFrame = false);
struct CV_EXPORTS EncoderParams struct CV_EXPORTS EncoderParams
{ {
int P_Interval; // NVVE_P_INTERVAL, int P_Interval; // NVVE_P_INTERVAL,
@ -123,8 +99,6 @@ public:
void save(const String& configFile) const; void save(const String& configFile) const;
}; };
EncoderParams getParams() const;
class CV_EXPORTS EncoderCallBack class CV_EXPORTS EncoderCallBack
{ {
public: public:
@ -137,26 +111,43 @@ public:
virtual ~EncoderCallBack() {} virtual ~EncoderCallBack() {}
// callback function to signal the start of bitstream that is to be encoded //! callback function to signal the start of bitstream that is to be encoded
// must return pointer to buffer //! callback must allocate host buffer for CUDA encoder and return pointer to it and it's size
virtual uchar* acquireBitStream(int* bufferSize) = 0; virtual uchar* acquireBitStream(int* bufferSize) = 0;
// callback function to signal that the encoded bitstream is ready to be written to file //! callback function to signal that the encoded bitstream is ready to be written to file
virtual void releaseBitStream(unsigned char* data, int size) = 0; virtual void releaseBitStream(unsigned char* data, int size) = 0;
// callback function to signal that the encoding operation on the frame has started //! callback function to signal that the encoding operation on the frame has started
virtual void onBeginFrame(int frameNumber, PicType picType) = 0; virtual void onBeginFrame(int frameNumber, PicType picType) = 0;
// callback function signals that the encoding operation on the frame has finished //! callback function signals that the encoding operation on the frame has finished
virtual void onEndFrame(int frameNumber, PicType picType) = 0; virtual void onEndFrame(int frameNumber, PicType picType) = 0;
}; };
class Impl; class CV_EXPORTS VideoWriter
{
public:
virtual ~VideoWriter() {}
private: //! writes the next frame from GPU memory
cv::Ptr<Impl> impl_; virtual void write(InputArray frame, bool lastFrame = false) = 0;
virtual EncoderParams getEncoderParams() const = 0;
}; };
//! create VideoWriter for specified output file (only AVI file format is supported)
CV_EXPORTS Ptr<VideoWriter> createVideoWriter(const String& fileName, Size frameSize, double fps, SurfaceFormat format = SF_BGR);
CV_EXPORTS Ptr<VideoWriter> createVideoWriter(const String& fileName, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR);
//! create VideoWriter for user-defined callbacks
CV_EXPORTS Ptr<VideoWriter> createVideoWriter(const Ptr<EncoderCallBack>& encoderCallback, Size frameSize, double fps, SurfaceFormat format = SF_BGR);
CV_EXPORTS Ptr<VideoWriter> createVideoWriter(const Ptr<EncoderCallBack>& encoderCallback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR);
}} // namespace cv { namespace gpucodec {
namespace cv { namespace gpu {
////////////////////////////////// Video Decoding ////////////////////////////////////////// ////////////////////////////////// Video Decoding //////////////////////////////////////////
namespace detail namespace detail
@ -257,7 +248,6 @@ private:
namespace cv { namespace cv {
template <> CV_EXPORTS void Ptr<cv::gpu::VideoWriter_GPU::Impl>::delete_obj();
template <> CV_EXPORTS void Ptr<cv::gpu::VideoReader_GPU::Impl>::delete_obj(); template <> CV_EXPORTS void Ptr<cv::gpu::VideoReader_GPU::Impl>::delete_obj();
} }

View File

@ -119,7 +119,7 @@ PERF_TEST_P(FileName, VideoWriter, Values("gpu/video/768x576.avi", "gpu/video/19
if (PERF_RUN_GPU()) if (PERF_RUN_GPU())
{ {
cv::gpu::VideoWriter_GPU d_writer; cv::Ptr<cv::gpucodec::VideoWriter> d_writer;
cv::gpu::GpuMat d_frame; cv::gpu::GpuMat d_frame;
@ -130,11 +130,11 @@ PERF_TEST_P(FileName, VideoWriter, Values("gpu/video/768x576.avi", "gpu/video/19
d_frame.upload(frame); d_frame.upload(frame);
if (!d_writer.isOpened()) if (d_writer.empty())
d_writer.open(outputFile, frame.size(), FPS); d_writer = cv::gpucodec::createVideoWriter(outputFile, frame.size(), FPS);
startTimer(); next(); startTimer(); next();
d_writer.write(d_frame); d_writer->write(d_frame);
stopTimer(); stopTimer();
} }
} }

View File

@ -12,6 +12,7 @@
// //
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners. // Third party copyrights are property of their respective owners.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,

View File

@ -12,6 +12,7 @@
// //
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners. // Third party copyrights are property of their respective owners.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
@ -42,36 +43,32 @@
#include "precomp.hpp" #include "precomp.hpp"
using namespace cv;
using namespace cv::gpu;
using namespace cv::gpucodec;
#if !defined(HAVE_NVCUVID) || !defined(WIN32) #if !defined(HAVE_NVCUVID) || !defined(WIN32)
class cv::gpu::VideoWriter_GPU::Impl cv::gpucodec::EncoderParams::EncoderParams() { throw_no_cuda(); }
{ cv::gpucodec::EncoderParams::EncoderParams(const String&) { throw_no_cuda(); }
}; void cv::gpucodec::EncoderParams::load(const String&) { throw_no_cuda(); }
void cv::gpucodec::EncoderParams::save(const String&) const { throw_no_cuda(); }
cv::gpu::VideoWriter_GPU::VideoWriter_GPU() { throw_no_cuda(); } Ptr<VideoWriter> cv::gpucodec::createVideoWriter(const String&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const String&, cv::Size, double, SurfaceFormat) { throw_no_cuda(); } Ptr<VideoWriter> cv::gpucodec::createVideoWriter(const String&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const String&, cv::Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); }
cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>&, cv::Size, double, SurfaceFormat) { throw_no_cuda(); }
cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>&, cv::Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); }
cv::gpu::VideoWriter_GPU::~VideoWriter_GPU() {}
void cv::gpu::VideoWriter_GPU::open(const String&, cv::Size, double, SurfaceFormat) { throw_no_cuda(); }
void cv::gpu::VideoWriter_GPU::open(const String&, cv::Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); }
void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>&, cv::Size, double, SurfaceFormat) { throw_no_cuda(); }
void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>&, cv::Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); }
bool cv::gpu::VideoWriter_GPU::isOpened() const { return false; }
void cv::gpu::VideoWriter_GPU::close() {}
void cv::gpu::VideoWriter_GPU::write(const cv::gpu::GpuMat&, bool) { throw_no_cuda(); }
cv::gpu::VideoWriter_GPU::EncoderParams cv::gpu::VideoWriter_GPU::getParams() const { EncoderParams params; throw_no_cuda(); return params; }
cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams() { throw_no_cuda(); } Ptr<VideoWriter> cv::gpucodec::createVideoWriter(const Ptr<EncoderCallBack>&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams(const String&) { throw_no_cuda(); } Ptr<VideoWriter> cv::gpucodec::createVideoWriter(const Ptr<EncoderCallBack>&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
void cv::gpu::VideoWriter_GPU::EncoderParams::load(const String&) { throw_no_cuda(); }
void cv::gpu::VideoWriter_GPU::EncoderParams::save(const String&) const { throw_no_cuda(); }
#else // !defined HAVE_CUDA || !defined WIN32 #else // !defined HAVE_CUDA || !defined WIN32
namespace cv { namespace gpu { namespace cudev
{
void RGB_to_YV12(const PtrStepSzb src, int cn, PtrStepSzb dst, cudaStream_t stream = 0);
}}}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// VideoWriter_GPU::Impl // VideoWriterImpl
namespace namespace
{ {
@ -84,7 +81,7 @@ namespace
err = NVGetHWEncodeCaps(); err = NVGetHWEncodeCaps();
if (err) if (err)
CV_Error(cv::Error::GpuNotSupported, "No CUDA capability present"); CV_Error(Error::GpuNotSupported, "No CUDA capability present");
// Create the Encoder API Interface // Create the Encoder API Interface
err = NVCreateEncoder(&encoder_); err = NVCreateEncoder(&encoder_);
@ -113,30 +110,26 @@ namespace
MPEG4, // not supported yet MPEG4, // not supported yet
H264 H264
}; };
}
class cv::gpu::VideoWriter_GPU::Impl class VideoWriterImpl : public VideoWriter
{ {
public: public:
Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, SurfaceFormat format, CodecType codec = H264); VideoWriterImpl(const Ptr<EncoderCallBack>& callback, Size frameSize, double fps, SurfaceFormat format, CodecType codec = H264);
Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec = H264); VideoWriterImpl(const Ptr<EncoderCallBack>& callback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec = H264);
void write(const cv::gpu::GpuMat& image, bool lastFrame); void write(InputArray frame, bool lastFrame = false);
EncoderParams getParams() const; EncoderParams getEncoderParams() const;
private: private:
Impl(const Impl&);
Impl& operator=(const Impl&);
void initEncoder(double fps); void initEncoder(double fps);
void setEncodeParams(const EncoderParams& params); void setEncodeParams(const EncoderParams& params);
void initGpuMemory(); void initGpuMemory();
void initCallBacks(); void initCallBacks();
void createHWEncoder(); void createHWEncoder();
cv::Ptr<EncoderCallBack> callback_; Ptr<EncoderCallBack> callback_;
cv::Size frameSize_; Size frameSize_;
CodecType codec_; CodecType codec_;
SurfaceFormat inputFormat_; SurfaceFormat inputFormat_;
@ -144,7 +137,7 @@ private:
NVEncoderWrapper encoder_; NVEncoderWrapper encoder_;
cv::gpu::GpuMat videoFrame_; GpuMat videoFrame_;
CUvideoctxlock cuCtxLock_; CUvideoctxlock cuCtxLock_;
// CallBacks // CallBacks
@ -155,14 +148,14 @@ private:
static void NVENCAPI HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata); static void NVENCAPI HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata);
}; };
cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, SurfaceFormat format, CodecType codec) : VideoWriterImpl::VideoWriterImpl(const Ptr<EncoderCallBack>& callback, Size frameSize, double fps, SurfaceFormat format, CodecType codec) :
callback_(callback), callback_(callback),
frameSize_(frameSize), frameSize_(frameSize),
codec_(codec), codec_(codec),
inputFormat_(format), inputFormat_(format),
cuCtxLock_(0) cuCtxLock_(0)
{ {
surfaceFormat_ = inputFormat_ == SF_BGR ? YV12 : static_cast<NVVE_SurfaceFormat>(inputFormat_); surfaceFormat_ = (inputFormat_ == SF_BGR ? YV12 : static_cast<NVVE_SurfaceFormat>(inputFormat_));
initEncoder(fps); initEncoder(fps);
@ -173,14 +166,14 @@ cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr<EncoderCallBack>& callback, c
createHWEncoder(); createHWEncoder();
} }
cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr<EncoderCallBack>& callback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec) : VideoWriterImpl::VideoWriterImpl(const Ptr<EncoderCallBack>& callback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec) :
callback_(callback), callback_(callback),
frameSize_(frameSize), frameSize_(frameSize),
codec_(codec), codec_(codec),
inputFormat_(format), inputFormat_(format),
cuCtxLock_(0) cuCtxLock_(0)
{ {
surfaceFormat_ = inputFormat_ == SF_BGR ? YV12 : static_cast<NVVE_SurfaceFormat>(inputFormat_); surfaceFormat_ = (inputFormat_ == SF_BGR ? YV12 : static_cast<NVVE_SurfaceFormat>(inputFormat_));
initEncoder(fps); initEncoder(fps);
@ -193,7 +186,7 @@ cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr<EncoderCallBack>& callback, c
createHWEncoder(); createHWEncoder();
} }
void cv::gpu::VideoWriter_GPU::Impl::initEncoder(double fps) void VideoWriterImpl::initEncoder(double fps)
{ {
int err; int err;
@ -205,7 +198,7 @@ void cv::gpu::VideoWriter_GPU::Impl::initEncoder(double fps)
}; };
err = NVSetCodec(encoder_, codecs_id[codec_]); err = NVSetCodec(encoder_, codecs_id[codec_]);
if (err) if (err)
CV_Error(cv::Error::StsNotImplemented, "Codec format is not supported"); CV_Error(Error::StsNotImplemented, "Codec format is not supported");
// Set default params // Set default params
@ -239,12 +232,12 @@ void cv::gpu::VideoWriter_GPU::Impl::initEncoder(double fps)
// Select device for encoding // Select device for encoding
int gpuID = cv::gpu::getDevice(); int gpuID = getDevice();
err = NVSetParamValue(encoder_, NVVE_FORCE_GPU_SELECTION, &gpuID); err = NVSetParamValue(encoder_, NVVE_FORCE_GPU_SELECTION, &gpuID);
CV_Assert( err == 0 ); CV_Assert( err == 0 );
} }
void cv::gpu::VideoWriter_GPU::Impl::setEncodeParams(const EncoderParams& params) void VideoWriterImpl::setEncodeParams(const EncoderParams& params)
{ {
int err; int err;
@ -328,7 +321,7 @@ void cv::gpu::VideoWriter_GPU::Impl::setEncodeParams(const EncoderParams& params
CV_Assert( err == 0 ); CV_Assert( err == 0 );
} }
cv::gpu::VideoWriter_GPU::EncoderParams cv::gpu::VideoWriter_GPU::Impl::getParams() const EncoderParams VideoWriterImpl::getEncoderParams() const
{ {
int err; int err;
@ -429,13 +422,12 @@ cv::gpu::VideoWriter_GPU::EncoderParams cv::gpu::VideoWriter_GPU::Impl::getParam
return params; return params;
} }
void cv::gpu::VideoWriter_GPU::Impl::initGpuMemory() void VideoWriterImpl::initGpuMemory()
{ {
int err; int err;
CUresult cuRes;
// initialize context // initialize context
cv::gpu::GpuMat temp(1, 1, CV_8U); GpuMat temp(1, 1, CV_8U);
temp.release(); temp.release();
static const int bpp[] = static const int bpp[] =
@ -448,8 +440,7 @@ void cv::gpu::VideoWriter_GPU::Impl::initGpuMemory()
}; };
CUcontext cuContext; CUcontext cuContext;
cuRes = cuCtxGetCurrent(&cuContext); cuSafeCall( cuCtxGetCurrent(&cuContext) );
CV_Assert( cuRes == CUDA_SUCCESS );
// Allocate the CUDA memory Pitched Surface // Allocate the CUDA memory Pitched Surface
if (surfaceFormat_ == UYVY || surfaceFormat_ == YUY2) if (surfaceFormat_ == UYVY || surfaceFormat_ == YUY2)
@ -458,8 +449,7 @@ void cv::gpu::VideoWriter_GPU::Impl::initGpuMemory()
videoFrame_.create((frameSize_.height * bpp[surfaceFormat_]) / 8, frameSize_.width, CV_8UC1); videoFrame_.create((frameSize_.height * bpp[surfaceFormat_]) / 8, frameSize_.width, CV_8UC1);
// Create the Video Context Lock (used for synchronization) // Create the Video Context Lock (used for synchronization)
cuRes = cuvidCtxLockCreate(&cuCtxLock_, cuContext); cuSafeCall( cuvidCtxLockCreate(&cuCtxLock_, cuContext) );
CV_Assert( cuRes == CUDA_SUCCESS );
// If we are using GPU Device Memory with NVCUVENC, it is necessary to create a // If we are using GPU Device Memory with NVCUVENC, it is necessary to create a
// CUDA Context with a Context Lock cuvidCtxLock. The Context Lock needs to be passed to NVCUVENC // CUDA Context with a Context Lock cuvidCtxLock. The Context Lock needs to be passed to NVCUVENC
@ -472,7 +462,7 @@ void cv::gpu::VideoWriter_GPU::Impl::initGpuMemory()
CV_Assert( err == 0 ); CV_Assert( err == 0 );
} }
void cv::gpu::VideoWriter_GPU::Impl::initCallBacks() void VideoWriterImpl::initCallBacks()
{ {
NVVE_CallbackParams cb; NVVE_CallbackParams cb;
memset(&cb, 0, sizeof(NVVE_CallbackParams)); memset(&cb, 0, sizeof(NVVE_CallbackParams));
@ -485,7 +475,7 @@ void cv::gpu::VideoWriter_GPU::Impl::initCallBacks()
NVRegisterCB(encoder_, cb, this); NVRegisterCB(encoder_, cb, this);
} }
void cv::gpu::VideoWriter_GPU::Impl::createHWEncoder() void VideoWriterImpl::createHWEncoder()
{ {
int err; int err;
@ -494,19 +484,16 @@ void cv::gpu::VideoWriter_GPU::Impl::createHWEncoder()
CV_Assert( err == 0 ); CV_Assert( err == 0 );
} }
namespace
{
// UYVY/YUY2 are both 4:2:2 formats (16bpc) // UYVY/YUY2 are both 4:2:2 formats (16bpc)
// Luma, U, V are interleaved, chroma is subsampled (w/2,h) // Luma, U, V are interleaved, chroma is subsampled (w/2,h)
void copyUYVYorYUY2Frame(cv::Size frameSize, const cv::gpu::GpuMat& src, cv::gpu::GpuMat& dst) void copyUYVYorYUY2Frame(Size frameSize, const GpuMat& src, GpuMat& dst)
{ {
CUresult res;
// Source is YUVY/YUY2 4:2:2, the YUV data in a packed and interleaved // Source is YUVY/YUY2 4:2:2, the YUV data in a packed and interleaved
// YUV Copy setup // YUV Copy setup
CUDA_MEMCPY2D stCopyYUV422; CUDA_MEMCPY2D stCopyYUV422;
memset((void*)&stCopyYUV422, 0, sizeof(stCopyYUV422)); memset(&stCopyYUV422, 0, sizeof(CUDA_MEMCPY2D));
stCopyYUV422.srcXInBytes = 0; stCopyYUV422.srcXInBytes = 0;
stCopyYUV422.srcY = 0; stCopyYUV422.srcY = 0;
stCopyYUV422.srcMemoryType = CU_MEMORYTYPE_DEVICE; stCopyYUV422.srcMemoryType = CU_MEMORYTYPE_DEVICE;
@ -527,21 +514,19 @@ namespace
stCopyYUV422.Height = frameSize.height; stCopyYUV422.Height = frameSize.height;
// DMA Luma/Chroma // DMA Luma/Chroma
res = cuMemcpy2D(&stCopyYUV422); cuSafeCall( cuMemcpy2D(&stCopyYUV422) );
CV_Assert( res == CUDA_SUCCESS );
} }
// YV12/IYUV are both 4:2:0 planar formats (12bpc) // YV12/IYUV are both 4:2:0 planar formats (12bpc)
// Luma, U, V chroma planar (12bpc), chroma is subsampled (w/2,h/2) // Luma, U, V chroma planar (12bpc), chroma is subsampled (w/2,h/2)
void copyYV12orIYUVFrame(cv::Size frameSize, const cv::gpu::GpuMat& src, cv::gpu::GpuMat& dst) void copyYV12orIYUVFrame(Size frameSize, const GpuMat& src, GpuMat& dst)
{ {
CUresult res;
// Source is YV12/IYUV, this native format is converted to NV12 format by the video encoder // Source is YV12/IYUV, this native format is converted to NV12 format by the video encoder
// (1) luma copy setup // (1) luma copy setup
CUDA_MEMCPY2D stCopyLuma; CUDA_MEMCPY2D stCopyLuma;
memset((void*)&stCopyLuma, 0, sizeof(stCopyLuma)); memset(&stCopyLuma, 0, sizeof(CUDA_MEMCPY2D));
stCopyLuma.srcXInBytes = 0; stCopyLuma.srcXInBytes = 0;
stCopyLuma.srcY = 0; stCopyLuma.srcY = 0;
stCopyLuma.srcMemoryType = CU_MEMORYTYPE_DEVICE; stCopyLuma.srcMemoryType = CU_MEMORYTYPE_DEVICE;
@ -563,7 +548,8 @@ namespace
// (2) chroma copy setup, U/V can be done together // (2) chroma copy setup, U/V can be done together
CUDA_MEMCPY2D stCopyChroma; CUDA_MEMCPY2D stCopyChroma;
memset((void*)&stCopyChroma, 0, sizeof(stCopyChroma)); memset(&stCopyChroma, 0, sizeof(CUDA_MEMCPY2D));
stCopyChroma.srcXInBytes = 0; stCopyChroma.srcXInBytes = 0;
stCopyChroma.srcY = frameSize.height << 1; // U/V chroma offset stCopyChroma.srcY = frameSize.height << 1; // U/V chroma offset
stCopyChroma.srcMemoryType = CU_MEMORYTYPE_DEVICE; stCopyChroma.srcMemoryType = CU_MEMORYTYPE_DEVICE;
@ -584,26 +570,23 @@ namespace
stCopyChroma.Height = frameSize.height; // U/V are sent together stCopyChroma.Height = frameSize.height; // U/V are sent together
// DMA Luma // DMA Luma
res = cuMemcpy2D(&stCopyLuma); cuSafeCall( cuMemcpy2D(&stCopyLuma) );
CV_Assert( res == CUDA_SUCCESS );
// DMA Chroma channels (UV side by side) // DMA Chroma channels (UV side by side)
res = cuMemcpy2D(&stCopyChroma); cuSafeCall( cuMemcpy2D(&stCopyChroma) );
CV_Assert( res == CUDA_SUCCESS );
} }
// NV12 is 4:2:0 format (12bpc) // NV12 is 4:2:0 format (12bpc)
// Luma followed by U/V chroma interleaved (12bpc), chroma is subsampled (w/2,h/2) // Luma followed by U/V chroma interleaved (12bpc), chroma is subsampled (w/2,h/2)
void copyNV12Frame(cv::Size frameSize, const cv::gpu::GpuMat& src, cv::gpu::GpuMat& dst) void copyNV12Frame(Size frameSize, const GpuMat& src, GpuMat& dst)
{ {
CUresult res;
// Source is NV12 in pitch linear memory // Source is NV12 in pitch linear memory
// 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 // 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
// Luma/Chroma can be done in a single transfer // Luma/Chroma can be done in a single transfer
CUDA_MEMCPY2D stCopyNV12; CUDA_MEMCPY2D stCopyNV12;
memset((void*)&stCopyNV12, 0, sizeof(stCopyNV12)); memset(&stCopyNV12, 0, sizeof(CUDA_MEMCPY2D));
stCopyNV12.srcXInBytes = 0; stCopyNV12.srcXInBytes = 0;
stCopyNV12.srcY = 0; stCopyNV12.srcY = 0;
stCopyNV12.srcMemoryType = CU_MEMORYTYPE_DEVICE; stCopyNV12.srcMemoryType = CU_MEMORYTYPE_DEVICE;
@ -624,18 +607,13 @@ namespace
stCopyNV12.Height = (frameSize.height * 3) >> 1; stCopyNV12.Height = (frameSize.height * 3) >> 1;
// DMA Luma/Chroma // DMA Luma/Chroma
res = cuMemcpy2D(&stCopyNV12); cuSafeCall( cuMemcpy2D(&stCopyNV12) );
CV_Assert( res == CUDA_SUCCESS );
}
} }
namespace cv { namespace gpu { namespace cudev void VideoWriterImpl::write(InputArray _frame, bool lastFrame)
{ {
void RGB_to_YV12(const PtrStepSzb src, int cn, PtrStepSzb dst, cudaStream_t stream = 0); GpuMat frame = _frame.getGpuMat();
}}}
void cv::gpu::VideoWriter_GPU::Impl::write(const cv::gpu::GpuMat& frame, bool lastFrame)
{
if (inputFormat_ == SF_BGR) if (inputFormat_ == SF_BGR)
{ {
CV_Assert( frame.size() == frameSize_ ); CV_Assert( frame.size() == frameSize_ );
@ -660,11 +638,12 @@ void cv::gpu::VideoWriter_GPU::Impl::write(const cv::gpu::GpuMat& frame, bool la
efparams.picBuf = 0; // Must be set to NULL in order to support device memory input efparams.picBuf = 0; // Must be set to NULL in order to support device memory input
// Don't forget we need to lock/unlock between memcopies // Don't forget we need to lock/unlock between memcopies
CUresult res = cuvidCtxLock(cuCtxLock_, 0); cuSafeCall( cuvidCtxLock(cuCtxLock_, 0) );
CV_Assert( res == CUDA_SUCCESS );
if (inputFormat_ == SF_BGR) if (inputFormat_ == SF_BGR)
cv::gpu::cudev::RGB_to_YV12(frame, frame.channels(), videoFrame_); {
cudev::RGB_to_YV12(frame, frame.channels(), videoFrame_);
}
else else
{ {
switch (surfaceFormat_) switch (surfaceFormat_)
@ -685,37 +664,36 @@ void cv::gpu::VideoWriter_GPU::Impl::write(const cv::gpu::GpuMat& frame, bool la
} }
} }
res = cuvidCtxUnlock(cuCtxLock_, 0); cuSafeCall( cuvidCtxUnlock(cuCtxLock_, 0) );
CV_Assert( res == CUDA_SUCCESS );
int err = NVEncodeFrame(encoder_, &efparams, 0, videoFrame_.data); int err = NVEncodeFrame(encoder_, &efparams, 0, videoFrame_.data);
CV_Assert( err == 0 ); CV_Assert( err == 0 );
} }
unsigned char* NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleAcquireBitStream(int* pBufferSize, void* pUserdata) unsigned char* NVENCAPI VideoWriterImpl::HandleAcquireBitStream(int* pBufferSize, void* pUserdata)
{ {
Impl* thiz = static_cast<Impl*>(pUserdata); VideoWriterImpl* thiz = static_cast<VideoWriterImpl*>(pUserdata);
return thiz->callback_->acquireBitStream(pBufferSize); return thiz->callback_->acquireBitStream(pBufferSize);
} }
void NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleReleaseBitStream(int nBytesInBuffer, unsigned char* cb, void* pUserdata) void NVENCAPI VideoWriterImpl::HandleReleaseBitStream(int nBytesInBuffer, unsigned char* cb, void* pUserdata)
{ {
Impl* thiz = static_cast<Impl*>(pUserdata); VideoWriterImpl* thiz = static_cast<VideoWriterImpl*>(pUserdata);
thiz->callback_->releaseBitStream(cb, nBytesInBuffer); thiz->callback_->releaseBitStream(cb, nBytesInBuffer);
} }
void NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleOnBeginFrame(const NVVE_BeginFrameInfo* pbfi, void* pUserdata) void NVENCAPI VideoWriterImpl::HandleOnBeginFrame(const NVVE_BeginFrameInfo* pbfi, void* pUserdata)
{ {
Impl* thiz = static_cast<Impl*>(pUserdata); VideoWriterImpl* thiz = static_cast<VideoWriterImpl*>(pUserdata);
thiz->callback_->onBeginFrame(pbfi->nFrameNumber, static_cast<EncoderCallBack::PicType>(pbfi->nPicType)); thiz->callback_->onBeginFrame(pbfi->nFrameNumber, static_cast<EncoderCallBack::PicType>(pbfi->nPicType));
} }
void NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata) void NVENCAPI VideoWriterImpl::HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata)
{ {
Impl* thiz = static_cast<Impl*>(pUserdata); VideoWriterImpl* thiz = static_cast<VideoWriterImpl*>(pUserdata);
thiz->callback_->onEndFrame(pefi->nFrameNumber, static_cast<EncoderCallBack::PicType>(pefi->nPicType)); thiz->callback_->onEndFrame(pefi->nFrameNumber, static_cast<EncoderCallBack::PicType>(pefi->nPicType));
} }
@ -723,10 +701,10 @@ void NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleOnEndFrame(const NVVE_EndFra
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// FFMPEG // FFMPEG
class EncoderCallBackFFMPEG : public cv::gpu::VideoWriter_GPU::EncoderCallBack class EncoderCallBackFFMPEG : public EncoderCallBack
{ {
public: public:
EncoderCallBackFFMPEG(const cv::String& fileName, cv::Size frameSize, double fps); EncoderCallBackFFMPEG(const String& fileName, Size frameSize, double fps);
~EncoderCallBackFFMPEG(); ~EncoderCallBackFFMPEG();
unsigned char* acquireBitStream(int* bufferSize); unsigned char* acquireBitStream(int* bufferSize);
@ -735,27 +713,28 @@ public:
void onEndFrame(int frameNumber, PicType picType); void onEndFrame(int frameNumber, PicType picType);
private: private:
EncoderCallBackFFMPEG(const EncoderCallBackFFMPEG&); static bool init_MediaStream_FFMPEG();
EncoderCallBackFFMPEG& operator=(const EncoderCallBackFFMPEG&);
struct OutputMediaStream_FFMPEG* stream_; struct OutputMediaStream_FFMPEG* stream_;
std::vector<uchar> buf_; std::vector<uchar> buf_;
bool isKeyFrame_; bool isKeyFrame_;
static Create_OutputMediaStream_FFMPEG_Plugin create_OutputMediaStream_FFMPEG_p;
static Release_OutputMediaStream_FFMPEG_Plugin release_OutputMediaStream_FFMPEG_p;
static Write_OutputMediaStream_FFMPEG_Plugin write_OutputMediaStream_FFMPEG_p;
}; };
namespace Create_OutputMediaStream_FFMPEG_Plugin EncoderCallBackFFMPEG::create_OutputMediaStream_FFMPEG_p = 0;
{ Release_OutputMediaStream_FFMPEG_Plugin EncoderCallBackFFMPEG::release_OutputMediaStream_FFMPEG_p = 0;
Create_OutputMediaStream_FFMPEG_Plugin create_OutputMediaStream_FFMPEG_p = 0; Write_OutputMediaStream_FFMPEG_Plugin EncoderCallBackFFMPEG::write_OutputMediaStream_FFMPEG_p = 0;
Release_OutputMediaStream_FFMPEG_Plugin release_OutputMediaStream_FFMPEG_p = 0;
Write_OutputMediaStream_FFMPEG_Plugin write_OutputMediaStream_FFMPEG_p = 0;
bool init_MediaStream_FFMPEG() bool EncoderCallBackFFMPEG::init_MediaStream_FFMPEG()
{ {
static bool initialized = 0; static bool initialized = false;
if (!initialized) if (!initialized)
{ {
#if defined WIN32 || defined _WIN32 #if defined(WIN32) || defined(_WIN32)
const char* module_name = "opencv_ffmpeg" const char* module_name = "opencv_ffmpeg"
CVAUX_STR(CV_VERSION_EPOCH) CVAUX_STR(CV_VERSION_MAJOR) CVAUX_STR(CV_VERSION_MINOR) CVAUX_STR(CV_VERSION_EPOCH) CVAUX_STR(CV_VERSION_MAJOR) CVAUX_STR(CV_VERSION_MINOR)
#if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__) #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)
@ -776,7 +755,7 @@ namespace
initialized = create_OutputMediaStream_FFMPEG_p != 0 && release_OutputMediaStream_FFMPEG_p != 0 && write_OutputMediaStream_FFMPEG_p != 0; initialized = create_OutputMediaStream_FFMPEG_p != 0 && release_OutputMediaStream_FFMPEG_p != 0 && write_OutputMediaStream_FFMPEG_p != 0;
} }
#elif defined HAVE_FFMPEG #elif defined(HAVE_FFMPEG)
create_OutputMediaStream_FFMPEG_p = create_OutputMediaStream_FFMPEG; create_OutputMediaStream_FFMPEG_p = create_OutputMediaStream_FFMPEG;
release_OutputMediaStream_FFMPEG_p = release_OutputMediaStream_FFMPEG; release_OutputMediaStream_FFMPEG_p = release_OutputMediaStream_FFMPEG;
write_OutputMediaStream_FFMPEG_p = write_OutputMediaStream_FFMPEG; write_OutputMediaStream_FFMPEG_p = write_OutputMediaStream_FFMPEG;
@ -787,9 +766,8 @@ namespace
return initialized; return initialized;
} }
}
EncoderCallBackFFMPEG::EncoderCallBackFFMPEG(const cv::String& fileName, cv::Size frameSize, double fps) : EncoderCallBackFFMPEG::EncoderCallBackFFMPEG(const String& fileName, Size frameSize, double fps) :
stream_(0), isKeyFrame_(false) stream_(0), isKeyFrame_(false)
{ {
int buf_size = std::max(frameSize.area() * 4, 1024 * 1024); int buf_size = std::max(frameSize.area() * 4, 1024 * 1024);
@ -820,7 +798,7 @@ void EncoderCallBackFFMPEG::releaseBitStream(unsigned char* data, int size)
void EncoderCallBackFFMPEG::onBeginFrame(int frameNumber, PicType picType) void EncoderCallBackFFMPEG::onBeginFrame(int frameNumber, PicType picType)
{ {
(void) frameNumber; (void) frameNumber;
isKeyFrame_ = picType == IFRAME; isKeyFrame_ = (picType == IFRAME);
} }
void EncoderCallBackFFMPEG::onEndFrame(int frameNumber, PicType picType) void EncoderCallBackFFMPEG::onEndFrame(int frameNumber, PicType picType)
@ -828,93 +806,12 @@ void EncoderCallBackFFMPEG::onEndFrame(int frameNumber, PicType picType)
(void) frameNumber; (void) frameNumber;
(void) picType; (void) picType;
} }
///////////////////////////////////////////////////////////////////////////
// VideoWriter_GPU
cv::gpu::VideoWriter_GPU::VideoWriter_GPU()
{
}
cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const String& fileName, cv::Size frameSize, double fps, SurfaceFormat format)
{
open(fileName, frameSize, fps, format);
}
cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const String& fileName, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format)
{
open(fileName, frameSize, fps, params, format);
}
cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, SurfaceFormat format)
{
open(encoderCallback, frameSize, fps, format);
}
cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format)
{
open(encoderCallback, frameSize, fps, params, format);
}
cv::gpu::VideoWriter_GPU::~VideoWriter_GPU()
{
close();
}
void cv::gpu::VideoWriter_GPU::open(const String& fileName, cv::Size frameSize, double fps, SurfaceFormat format)
{
close();
cv::Ptr<EncoderCallBack> encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps));
open(encoderCallback, frameSize, fps, format);
}
void cv::gpu::VideoWriter_GPU::open(const String& fileName, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format)
{
close();
cv::Ptr<EncoderCallBack> encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps));
open(encoderCallback, frameSize, fps, params, format);
}
void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, SurfaceFormat format)
{
close();
impl_ = new Impl(encoderCallback, frameSize, fps, format);
}
void cv::gpu::VideoWriter_GPU::open(const cv::Ptr<EncoderCallBack>& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format)
{
close();
impl_ = new Impl(encoderCallback, frameSize, fps, params, format);
}
bool cv::gpu::VideoWriter_GPU::isOpened() const
{
return !impl_.empty();
}
void cv::gpu::VideoWriter_GPU::close()
{
impl_.release();
}
void cv::gpu::VideoWriter_GPU::write(const cv::gpu::GpuMat& image, bool lastFrame)
{
CV_Assert( isOpened() );
impl_->write(image, lastFrame);
}
cv::gpu::VideoWriter_GPU::EncoderParams cv::gpu::VideoWriter_GPU::getParams() const
{
CV_Assert( isOpened() );
return impl_->getParams();
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// VideoWriter_GPU::EncoderParams // EncoderParams
cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams() cv::gpucodec::EncoderParams::EncoderParams()
{ {
P_Interval = 3; P_Interval = 3;
IDR_Period = 15; IDR_Period = 15;
@ -937,66 +834,86 @@ cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams()
DisableSPSPPS = 0; DisableSPSPPS = 0;
} }
cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams(const String& configFile) cv::gpucodec::EncoderParams::EncoderParams(const String& configFile)
{ {
load(configFile); load(configFile);
} }
void cv::gpu::VideoWriter_GPU::EncoderParams::load(const String& configFile) void cv::gpucodec::EncoderParams::load(const String& configFile)
{ {
cv::FileStorage fs(configFile, cv::FileStorage::READ); FileStorage fs(configFile, FileStorage::READ);
CV_Assert( fs.isOpened() ); CV_Assert( fs.isOpened() );
cv::read(fs["P_Interval" ], P_Interval, 3); read(fs["P_Interval" ], P_Interval, 3);
cv::read(fs["IDR_Period" ], IDR_Period, 15); read(fs["IDR_Period" ], IDR_Period, 15);
cv::read(fs["DynamicGOP" ], DynamicGOP, 0); read(fs["DynamicGOP" ], DynamicGOP, 0);
cv::read(fs["RCType" ], RCType, 1); read(fs["RCType" ], RCType, 1);
cv::read(fs["AvgBitrate" ], AvgBitrate, 4000000); read(fs["AvgBitrate" ], AvgBitrate, 4000000);
cv::read(fs["PeakBitrate" ], PeakBitrate, 10000000); read(fs["PeakBitrate" ], PeakBitrate, 10000000);
cv::read(fs["QP_Level_Intra" ], QP_Level_Intra, 25); read(fs["QP_Level_Intra" ], QP_Level_Intra, 25);
cv::read(fs["QP_Level_InterP"], QP_Level_InterP, 28); read(fs["QP_Level_InterP"], QP_Level_InterP, 28);
cv::read(fs["QP_Level_InterB"], QP_Level_InterB, 31); read(fs["QP_Level_InterB"], QP_Level_InterB, 31);
cv::read(fs["DeblockMode" ], DeblockMode, 1); read(fs["DeblockMode" ], DeblockMode, 1);
cv::read(fs["ProfileLevel" ], ProfileLevel, 65357); read(fs["ProfileLevel" ], ProfileLevel, 65357);
cv::read(fs["ForceIntra" ], ForceIntra, 0); read(fs["ForceIntra" ], ForceIntra, 0);
cv::read(fs["ForceIDR" ], ForceIDR, 0); read(fs["ForceIDR" ], ForceIDR, 0);
cv::read(fs["ClearStat" ], ClearStat, 0); read(fs["ClearStat" ], ClearStat, 0);
cv::read(fs["DIMode" ], DIMode, 1); read(fs["DIMode" ], DIMode, 1);
cv::read(fs["Presets" ], Presets, 2); read(fs["Presets" ], Presets, 2);
cv::read(fs["DisableCabac" ], DisableCabac, 0); read(fs["DisableCabac" ], DisableCabac, 0);
cv::read(fs["NaluFramingType"], NaluFramingType, 0); read(fs["NaluFramingType"], NaluFramingType, 0);
cv::read(fs["DisableSPSPPS" ], DisableSPSPPS, 0); read(fs["DisableSPSPPS" ], DisableSPSPPS, 0);
} }
void cv::gpu::VideoWriter_GPU::EncoderParams::save(const String& configFile) const void cv::gpucodec::EncoderParams::save(const String& configFile) const
{ {
cv::FileStorage fs(configFile, cv::FileStorage::WRITE); FileStorage fs(configFile, FileStorage::WRITE);
CV_Assert( fs.isOpened() ); CV_Assert( fs.isOpened() );
cv::write(fs, "P_Interval" , P_Interval); write(fs, "P_Interval" , P_Interval);
cv::write(fs, "IDR_Period" , IDR_Period); write(fs, "IDR_Period" , IDR_Period);
cv::write(fs, "DynamicGOP" , DynamicGOP); write(fs, "DynamicGOP" , DynamicGOP);
cv::write(fs, "RCType" , RCType); write(fs, "RCType" , RCType);
cv::write(fs, "AvgBitrate" , AvgBitrate); write(fs, "AvgBitrate" , AvgBitrate);
cv::write(fs, "PeakBitrate" , PeakBitrate); write(fs, "PeakBitrate" , PeakBitrate);
cv::write(fs, "QP_Level_Intra" , QP_Level_Intra); write(fs, "QP_Level_Intra" , QP_Level_Intra);
cv::write(fs, "QP_Level_InterP", QP_Level_InterP); write(fs, "QP_Level_InterP", QP_Level_InterP);
cv::write(fs, "QP_Level_InterB", QP_Level_InterB); write(fs, "QP_Level_InterB", QP_Level_InterB);
cv::write(fs, "DeblockMode" , DeblockMode); write(fs, "DeblockMode" , DeblockMode);
cv::write(fs, "ProfileLevel" , ProfileLevel); write(fs, "ProfileLevel" , ProfileLevel);
cv::write(fs, "ForceIntra" , ForceIntra); write(fs, "ForceIntra" , ForceIntra);
cv::write(fs, "ForceIDR" , ForceIDR); write(fs, "ForceIDR" , ForceIDR);
cv::write(fs, "ClearStat" , ClearStat); write(fs, "ClearStat" , ClearStat);
cv::write(fs, "DIMode" , DIMode); write(fs, "DIMode" , DIMode);
cv::write(fs, "Presets" , Presets); write(fs, "Presets" , Presets);
cv::write(fs, "DisableCabac" , DisableCabac); write(fs, "DisableCabac" , DisableCabac);
cv::write(fs, "NaluFramingType", NaluFramingType); write(fs, "NaluFramingType", NaluFramingType);
cv::write(fs, "DisableSPSPPS" , DisableSPSPPS); write(fs, "DisableSPSPPS" , DisableSPSPPS);
}
///////////////////////////////////////////////////////////////////////////
// createVideoWriter
Ptr<VideoWriter> cv::gpucodec::createVideoWriter(const String& fileName, Size frameSize, double fps, SurfaceFormat format)
{
Ptr<EncoderCallBack> encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps));
return createVideoWriter(encoderCallback, frameSize, fps, format);
}
Ptr<VideoWriter> cv::gpucodec::createVideoWriter(const String& fileName, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format)
{
Ptr<EncoderCallBack> encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps));
return createVideoWriter(encoderCallback, frameSize, fps, params, format);
}
Ptr<VideoWriter> cv::gpucodec::createVideoWriter(const Ptr<EncoderCallBack>& encoderCallback, Size frameSize, double fps, SurfaceFormat format)
{
return new VideoWriterImpl(encoderCallback, frameSize, fps, format);
}
Ptr<VideoWriter> cv::gpucodec::createVideoWriter(const Ptr<EncoderCallBack>& encoderCallback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format)
{
return new VideoWriterImpl(encoderCallback, frameSize, fps, params, format);
} }
#endif // !defined HAVE_CUDA || !defined WIN32 #endif // !defined HAVE_CUDA || !defined WIN32
template <> void cv::Ptr<cv::gpu::VideoWriter_GPU::Impl>::delete_obj()
{
if (obj) delete obj;
}

View File

@ -89,7 +89,7 @@ GPU_TEST_P(Video, Writer)
cv::VideoCapture reader(inputFile); cv::VideoCapture reader(inputFile);
ASSERT_TRUE(reader.isOpened()); ASSERT_TRUE(reader.isOpened());
cv::gpu::VideoWriter_GPU d_writer; cv::Ptr<cv::gpucodec::VideoWriter> d_writer;
cv::Mat frame; cv::Mat frame;
cv::gpu::GpuMat d_frame; cv::gpu::GpuMat d_frame;
@ -101,14 +101,14 @@ GPU_TEST_P(Video, Writer)
d_frame.upload(frame); d_frame.upload(frame);
if (!d_writer.isOpened()) if (d_writer.empty())
d_writer.open(outputFile, frame.size(), FPS); d_writer = cv::gpucodec::createVideoWriter(outputFile, frame.size(), FPS);
d_writer.write(d_frame); d_writer->write(d_frame);
} }
reader.release(); reader.release();
d_writer.close(); d_writer.release();
reader.open(outputFile); reader.open(outputFile);
ASSERT_TRUE(reader.isOpened()); ASSERT_TRUE(reader.isOpened());

View File

@ -33,7 +33,7 @@ int main(int argc, const char* argv[])
cv::gpu::printShortCudaDeviceInfo(cv::gpu::getDevice()); cv::gpu::printShortCudaDeviceInfo(cv::gpu::getDevice());
cv::VideoWriter writer; cv::VideoWriter writer;
cv::gpu::VideoWriter_GPU d_writer; cv::Ptr<cv::gpucodec::VideoWriter> d_writer;
cv::Mat frame; cv::Mat frame;
cv::gpu::GpuMat d_frame; cv::gpu::GpuMat d_frame;
@ -64,11 +64,11 @@ int main(int argc, const char* argv[])
return -1; return -1;
} }
if (!d_writer.isOpened()) if (d_writer.empty())
{ {
std::cout << "Open GPU Writer" << std::endl; std::cout << "Open GPU Writer" << std::endl;
d_writer.open("output_gpu.avi", frame.size(), FPS); d_writer = cv::gpucodec::createVideoWriter("output_gpu.avi", frame.size(), FPS);
} }
d_frame.upload(frame); d_frame.upload(frame);
@ -81,7 +81,7 @@ int main(int argc, const char* argv[])
cpu_times.push_back(tm.getTimeMilli()); cpu_times.push_back(tm.getTimeMilli());
tm.reset(); tm.start(); tm.reset(); tm.start();
d_writer.write(d_frame); d_writer->write(d_frame);
tm.stop(); tm.stop();
gpu_times.push_back(tm.getTimeMilli()); gpu_times.push_back(tm.getTimeMilli());
} }