diff --git a/modules/gpucodec/doc/videodec.rst b/modules/gpucodec/doc/videodec.rst index 342203223..e2da30559 100644 --- a/modules/gpucodec/doc/videodec.rst +++ b/modules/gpucodec/doc/videodec.rst @@ -5,20 +5,37 @@ Video Decoding -gpu::VideoReader_GPU --------------------- -Video reader class. +gpucodec::VideoReader +--------------------- +Video reader interface. -.. ocv:class:: gpu::VideoReader_GPU +.. ocv:class:: gpucodec::VideoReader -gpu::VideoReader_GPU::Codec ---------------------------- +gpucodec::VideoReader::nextFrame +-------------------------------- +Grabs, decodes and returns the next video frame. -Video codecs supported by :ocv:class:`gpu::VideoReader_GPU` . +.. ocv:function:: bool gpucodec::VideoReader::nextFrame(OutputArray frame) -.. ocv:enum:: gpu::VideoReader_GPU::Codec +If no frames has been grabbed (there are no more frames in video file), the methods return ``false`` . The method throws :ocv:class:`Exception` if error occurs. + + + +gpucodec::VideoReader::format +----------------------------- +Returns information about video file format. + +.. ocv:function:: FormatInfo gpucodec::VideoReader::format() const + + + +gpucodec::Codec +--------------- +Video codecs supported by :ocv:class:`gpucodec::VideoReader` . + +.. ocv:enum:: gpucodec::Codec .. ocv:emember:: MPEG1 = 0 .. ocv:emember:: MPEG2 @@ -50,12 +67,12 @@ Video codecs supported by :ocv:class:`gpu::VideoReader_GPU` . UYVY (4:2:2) -gpu::VideoReader_GPU::ChromaFormat ----------------------------------- -Chroma formats supported by :ocv:class:`gpu::VideoReader_GPU` . +gpucodec::ChromaFormat +---------------------- +Chroma formats supported by :ocv:class:`gpucodec::VideoReader` . -.. ocv:enum:: gpu::VideoReader_GPU::ChromaFormat +.. ocv:enum:: gpucodec::ChromaFormat .. ocv:emember:: Monochrome = 0 .. ocv:emember:: YUV420 @@ -63,9 +80,10 @@ Chroma formats supported by :ocv:class:`gpu::VideoReader_GPU` . .. ocv:emember:: YUV444 -gpu::VideoReader_GPU::FormatInfo --------------------------------- -.. ocv:struct:: gpu::VideoReader_GPU::FormatInfo + +gpucodec::FormatInfo +-------------------- +.. ocv:struct:: gpucodec::FormatInfo Struct providing information about video file format. :: @@ -78,157 +96,58 @@ Struct providing information about video file format. :: }; -gpu::VideoReader_GPU::VideoReader_GPU -------------------------------------- -Constructors. -.. ocv:function:: gpu::VideoReader_GPU::VideoReader_GPU() -.. ocv:function:: gpu::VideoReader_GPU::VideoReader_GPU(const String& filename) -.. ocv:function:: gpu::VideoReader_GPU::VideoReader_GPU(const cv::Ptr& source) +gpucodec::createVideoReader +--------------------------- +Creates video reader. + +.. ocv:function:: Ptr gpucodec::createVideoReader(const String& filename) +.. ocv:function:: Ptr gpucodec::createVideoReader(const Ptr& source) :param filename: Name of the input video file. - :param source: Video file parser implemented by user. + :param source: RAW video source implemented by user. -The constructors initialize video reader. FFMPEG is used to read videos. User can implement own demultiplexing with :ocv:class:`gpu::VideoReader_GPU::VideoSource` . +FFMPEG is used to read videos. User can implement own demultiplexing with :ocv:class:`gpucodec::RawVideoSource` . -gpu::VideoReader_GPU::open --------------------------- -Initializes or reinitializes video reader. - -.. ocv:function:: void gpu::VideoReader_GPU::open(const String& filename) -.. ocv:function:: void gpu::VideoReader_GPU::open(const cv::Ptr& source) - -The method opens video reader. Parameters are the same as in the constructor :ocv:func:`gpu::VideoReader_GPU::VideoReader_GPU` . The method throws :ocv:class:`Exception` if error occurs. - - - -gpu::VideoReader_GPU::isOpened ------------------------------- -Returns true if video reader has been successfully initialized. - -.. ocv:function:: bool gpu::VideoReader_GPU::isOpened() const - - - -gpu::VideoReader_GPU::close ---------------------------- -Releases the video reader. - -.. ocv:function:: void gpu::VideoReader_GPU::close() - - - -gpu::VideoReader_GPU::read --------------------------- -Grabs, decodes and returns the next video frame. - -.. ocv:function:: bool gpu::VideoReader_GPU::read(GpuMat& image) - -If no frames has been grabbed (there are no more frames in video file), the methods return ``false`` . The method throws :ocv:class:`Exception` if error occurs. - - - -gpu::VideoReader_GPU::format ----------------------------- -Returns information about video file format. - -.. ocv:function:: FormatInfo gpu::VideoReader_GPU::format() const - -The method throws :ocv:class:`Exception` if video reader wasn't initialized. - - - -gpu::VideoReader_GPU::dumpFormat --------------------------------- -Dump information about video file format to specified stream. - -.. ocv:function:: void gpu::VideoReader_GPU::dumpFormat(std::ostream& st) - - :param st: Output stream. - -The method throws :ocv:class:`Exception` if video reader wasn't initialized. - - - -gpu::VideoReader_GPU::VideoSource ------------------------------------ -.. ocv:class:: gpu::VideoReader_GPU::VideoSource +gpucodec::RawVideoSource +------------------------ +.. ocv:class:: gpucodec::RawVideoSource Interface for video demultiplexing. :: - class VideoSource + class RawVideoSource { public: - VideoSource(); - virtual ~VideoSource() {} + virtual ~RawVideoSource() {} + + virtual bool getNextPacket(unsigned char** data, int* size, bool* endOfFile) = 0; virtual FormatInfo format() const = 0; - virtual void start() = 0; - virtual void stop() = 0; - virtual bool isStarted() const = 0; - virtual bool hasError() const = 0; - - protected: - bool parseVideoData(const unsigned char* data, size_t size, bool endOfStream = false); }; User can implement own demultiplexing by implementing this interface. -gpu::VideoReader_GPU::VideoSource::format ------------------------------------------ -Returns information about video file format. - -.. ocv:function:: virtual FormatInfo gpu::VideoReader_GPU::VideoSource::format() const = 0 - - - -gpu::VideoReader_GPU::VideoSource::start ----------------------------------------- -Starts processing. - -.. ocv:function:: virtual void gpu::VideoReader_GPU::VideoSource::start() = 0 - -Implementation must create own thread with video processing and call periodic :ocv:func:`gpu::VideoReader_GPU::VideoSource::parseVideoData` . - - - -gpu::VideoReader_GPU::VideoSource::stop +gpucodec::RawVideoSource::getNextPacket --------------------------------------- -Stops processing. +Returns next packet with RAW video frame. -.. ocv:function:: virtual void gpu::VideoReader_GPU::VideoSource::stop() = 0 +.. ocv:function:: bool gpucodec::VideoSource::getNextPacket(unsigned char** data, int* size, bool* endOfFile) = 0 - - -gpu::VideoReader_GPU::VideoSource::isStarted --------------------------------------------- -Returns ``true`` if processing was successfully started. - -.. ocv:function:: virtual bool gpu::VideoReader_GPU::VideoSource::isStarted() const = 0 - - - -gpu::VideoReader_GPU::VideoSource::hasError -------------------------------------------- -Returns ``true`` if error occured during processing. - -.. ocv:function:: virtual bool gpu::VideoReader_GPU::VideoSource::hasError() const = 0 - - - -gpu::VideoReader_GPU::VideoSource::parseVideoData -------------------------------------------------- -Parse next video frame. Implementation must call this method after new frame was grabbed. - -.. ocv:function:: bool gpu::VideoReader_GPU::VideoSource::parseVideoData(const uchar* data, size_t size, bool endOfStream = false) - - :param data: Pointer to frame data. Can be ``NULL`` if ``endOfStream`` if ``true`` . + :param data: Pointer to frame data. :param size: Size in bytes of current frame. :param endOfStream: Indicates that it is end of stream. + + + +gpucodec::RawVideoSource::format +-------------------------------- +Returns information about video file format. + +.. ocv:function:: virtual FormatInfo gpucodec::RawVideoSource::format() const = 0 diff --git a/modules/gpucodec/doc/videoenc.rst b/modules/gpucodec/doc/videoenc.rst index ec26e27ef..739ec0d70 100644 --- a/modules/gpucodec/doc/videoenc.rst +++ b/modules/gpucodec/doc/videoenc.rst @@ -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. -gpu::VideoWriter_GPU::VideoWriter_GPU -------------------------------------- -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, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR) -.. ocv:function:: gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr& 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, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR) -.. ocv:function:: void gpu::VideoWriter_GPU::open(const cv::Ptr& 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 ---------------------------- +gpucodec::VideoWriter::write +---------------------------- 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. @@ -86,9 +31,34 @@ The method write the specified image to video file. The image must have the same -gpu::VideoWriter_GPU::EncoderParams ------------------------------------ -.. ocv:struct:: gpu::VideoWriter_GPU::EncoderParams +gpucodec::createVideoWriter +--------------------------- +Creates video writer. + +.. ocv:function:: Ptr gpucodec::createVideoWriter(const String& fileName, Size frameSize, double fps, SurfaceFormat format = SF_BGR) +.. ocv:function:: Ptr gpucodec::createVideoWriter(const String& fileName, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR) +.. ocv:function:: Ptr gpucodec::createVideoWriter(const Ptr& encoderCallback, Size frameSize, double fps, SurfaceFormat format = SF_BGR) +.. ocv:function:: Ptr gpucodec::createVideoWriter(const Ptr& 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. :: @@ -123,12 +93,12 @@ Different parameters for CUDA video encoder. :: -gpu::VideoWriter_GPU::EncoderParams::EncoderParams --------------------------------------------------- +gpucodec::EncoderParams::EncoderParams +-------------------------------------- Constructors. -.. ocv:function:: gpu::VideoWriter_GPU::EncoderParams::EncoderParams() -.. ocv:function:: gpu::VideoWriter_GPU::EncoderParams::EncoderParams(const String& configFile) +.. ocv:function:: gpucodec::EncoderParams::EncoderParams() +.. ocv:function:: gpucodec::EncoderParams::EncoderParams(const String& configFile) :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. -.. 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. -gpu::VideoWriter_GPU::EncoderParams::save ------------------------------------------ +gpucodec::EncoderParams::save +----------------------------- 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. -gpu::VideoWriter_GPU::EncoderCallBack -------------------------------------- -.. ocv:class:: gpu::VideoWriter_GPU::EncoderCallBack +gpucodec::EncoderCallBack +------------------------- +.. ocv:class:: gpucodec::EncoderCallBack 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. -.. 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. -gpu::VideoWriter_GPU::EncoderCallBack::releaseBitStream -------------------------------------------------------- +gpucodec::EncoderCallBack::releaseBitStream +------------------------------------------- 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. -.. 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). -gpu::VideoWriter_GPU::EncoderCallBack::onEndFrame -------------------------------------------------- +gpucodec::EncoderCallBack::onEndFrame +------------------------------------- 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). diff --git a/modules/gpucodec/include/opencv2/gpucodec.hpp b/modules/gpucodec/include/opencv2/gpucodec.hpp index af68c3841..f2e298fd7 100644 --- a/modules/gpucodec/include/opencv2/gpucodec.hpp +++ b/modules/gpucodec/include/opencv2/gpucodec.hpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -47,219 +48,159 @@ # error gpucodec.hpp header must be compiled as C++ #endif -#include - #include "opencv2/core/gpu.hpp" -namespace cv { namespace gpu { +namespace cv { namespace gpucodec { ////////////////////////////////// Video Encoding ////////////////////////////////// -// Works only under Windows -// Supports olny H264 video codec and AVI files -class CV_EXPORTS VideoWriter_GPU +// Works only under Windows. +// Supports olny H264 video codec and AVI files. + +enum SurfaceFormat +{ + SF_UYVY = 0, + SF_YUY2, + SF_YV12, + SF_NV12, + SF_IYUV, + SF_BGR, + SF_GRAY = SF_BGR +}; + +struct CV_EXPORTS EncoderParams +{ + int P_Interval; // NVVE_P_INTERVAL, + int IDR_Period; // NVVE_IDR_PERIOD, + int DynamicGOP; // NVVE_DYNAMIC_GOP, + int RCType; // NVVE_RC_TYPE, + int AvgBitrate; // NVVE_AVG_BITRATE, + int PeakBitrate; // NVVE_PEAK_BITRATE, + int QP_Level_Intra; // NVVE_QP_LEVEL_INTRA, + int QP_Level_InterP; // NVVE_QP_LEVEL_INTER_P, + int QP_Level_InterB; // NVVE_QP_LEVEL_INTER_B, + int DeblockMode; // NVVE_DEBLOCK_MODE, + int ProfileLevel; // NVVE_PROFILE_LEVEL, + int ForceIntra; // NVVE_FORCE_INTRA, + int ForceIDR; // NVVE_FORCE_IDR, + int ClearStat; // NVVE_CLEAR_STAT, + int DIMode; // NVVE_SET_DEINTERLACE, + int Presets; // NVVE_PRESETS, + int DisableCabac; // NVVE_DISABLE_CABAC, + int NaluFramingType; // NVVE_CONFIGURE_NALU_FRAMING_TYPE + int DisableSPSPPS; // NVVE_DISABLE_SPS_PPS + + EncoderParams(); + explicit EncoderParams(const String& configFile); + + void load(const String& configFile); + void save(const String& configFile) const; +}; + +class CV_EXPORTS EncoderCallBack { public: - struct EncoderParams; - - // Callbacks for video encoder, use it if you want to work with raw video stream - class EncoderCallBack; - - enum SurfaceFormat + enum PicType { - SF_UYVY = 0, - SF_YUY2, - SF_YV12, - SF_NV12, - SF_IYUV, - SF_BGR, - SF_GRAY = SF_BGR + IFRAME = 1, + PFRAME = 2, + BFRAME = 3 }; - 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, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR); - VideoWriter_GPU(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR); - ~VideoWriter_GPU(); + virtual ~EncoderCallBack() {} - // 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, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR); - void open(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR); + //! callback function to signal the start of bitstream that is to be encoded + //! callback must allocate host buffer for CUDA encoder and return pointer to it and it's size + virtual uchar* acquireBitStream(int* bufferSize) = 0; - bool isOpened() const; - void close(); + //! callback function to signal that the encoded bitstream is ready to be written to file + virtual void releaseBitStream(unsigned char* data, int size) = 0; - void write(const cv::gpu::GpuMat& image, bool lastFrame = false); + //! callback function to signal that the encoding operation on the frame has started + virtual void onBeginFrame(int frameNumber, PicType picType) = 0; - struct CV_EXPORTS EncoderParams - { - int P_Interval; // NVVE_P_INTERVAL, - int IDR_Period; // NVVE_IDR_PERIOD, - int DynamicGOP; // NVVE_DYNAMIC_GOP, - int RCType; // NVVE_RC_TYPE, - int AvgBitrate; // NVVE_AVG_BITRATE, - int PeakBitrate; // NVVE_PEAK_BITRATE, - int QP_Level_Intra; // NVVE_QP_LEVEL_INTRA, - int QP_Level_InterP; // NVVE_QP_LEVEL_INTER_P, - int QP_Level_InterB; // NVVE_QP_LEVEL_INTER_B, - int DeblockMode; // NVVE_DEBLOCK_MODE, - int ProfileLevel; // NVVE_PROFILE_LEVEL, - int ForceIntra; // NVVE_FORCE_INTRA, - int ForceIDR; // NVVE_FORCE_IDR, - int ClearStat; // NVVE_CLEAR_STAT, - int DIMode; // NVVE_SET_DEINTERLACE, - int Presets; // NVVE_PRESETS, - int DisableCabac; // NVVE_DISABLE_CABAC, - int NaluFramingType; // NVVE_CONFIGURE_NALU_FRAMING_TYPE - int DisableSPSPPS; // NVVE_DISABLE_SPS_PPS - - EncoderParams(); - explicit EncoderParams(const String& configFile); - - void load(const String& configFile); - void save(const String& configFile) const; - }; - - EncoderParams getParams() const; - - class CV_EXPORTS EncoderCallBack - { - public: - enum PicType - { - IFRAME = 1, - PFRAME = 2, - BFRAME = 3 - }; - - virtual ~EncoderCallBack() {} - - // callback function to signal the start of bitstream that is to be encoded - // must return pointer to buffer - virtual uchar* acquireBitStream(int* bufferSize) = 0; - - // callback function to signal that the encoded bitstream is ready to be written to file - virtual void releaseBitStream(unsigned char* data, int size) = 0; - - // callback function to signal that the encoding operation on the frame has started - virtual void onBeginFrame(int frameNumber, PicType picType) = 0; - - // callback function signals that the encoding operation on the frame has finished - virtual void onEndFrame(int frameNumber, PicType picType) = 0; - }; - - class Impl; - -private: - cv::Ptr impl_; + //! callback function signals that the encoding operation on the frame has finished + virtual void onEndFrame(int frameNumber, PicType picType) = 0; }; +class CV_EXPORTS VideoWriter +{ +public: + virtual ~VideoWriter() {} + + //! writes the next frame from GPU memory + 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 createVideoWriter(const String& fileName, Size frameSize, double fps, SurfaceFormat format = SF_BGR); +CV_EXPORTS Ptr createVideoWriter(const String& fileName, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR); + +//! create VideoWriter for user-defined callbacks +CV_EXPORTS Ptr createVideoWriter(const Ptr& encoderCallback, Size frameSize, double fps, SurfaceFormat format = SF_BGR); +CV_EXPORTS Ptr createVideoWriter(const Ptr& encoderCallback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR); + ////////////////////////////////// Video Decoding ////////////////////////////////////////// -namespace detail +enum Codec { - class FrameQueue; - class VideoParser; -} + MPEG1 = 0, + MPEG2, + MPEG4, + VC1, + H264, + JPEG, + H264_SVC, + H264_MVC, -class CV_EXPORTS VideoReader_GPU -{ -public: - enum Codec - { - MPEG1 = 0, - MPEG2, - MPEG4, - VC1, - H264, - JPEG, - H264_SVC, - H264_MVC, - - Uncompressed_YUV420 = (('I'<<24)|('Y'<<16)|('U'<<8)|('V')), // Y,U,V (4:2:0) - Uncompressed_YV12 = (('Y'<<24)|('V'<<16)|('1'<<8)|('2')), // Y,V,U (4:2:0) - Uncompressed_NV12 = (('N'<<24)|('V'<<16)|('1'<<8)|('2')), // Y,UV (4:2:0) - Uncompressed_YUYV = (('Y'<<24)|('U'<<16)|('Y'<<8)|('V')), // YUYV/YUY2 (4:2:2) - Uncompressed_UYVY = (('U'<<24)|('Y'<<16)|('V'<<8)|('Y')), // UYVY (4:2:2) - }; - - enum ChromaFormat - { - Monochrome=0, - YUV420, - YUV422, - YUV444, - }; - - struct FormatInfo - { - Codec codec; - ChromaFormat chromaFormat; - int width; - int height; - }; - - class VideoSource; - - VideoReader_GPU(); - explicit VideoReader_GPU(const String& filename); - explicit VideoReader_GPU(const cv::Ptr& source); - - ~VideoReader_GPU(); - - void open(const String& filename); - void open(const cv::Ptr& source); - bool isOpened() const; - - void close(); - - bool read(GpuMat& image); - - FormatInfo format() const; - void dumpFormat(std::ostream& st); - - class CV_EXPORTS VideoSource - { - public: - VideoSource() : frameQueue_(0), videoParser_(0) {} - virtual ~VideoSource() {} - - virtual FormatInfo format() const = 0; - virtual void start() = 0; - virtual void stop() = 0; - virtual bool isStarted() const = 0; - virtual bool hasError() const = 0; - - void setFrameQueue(detail::FrameQueue* frameQueue) { frameQueue_ = frameQueue; } - void setVideoParser(detail::VideoParser* videoParser) { videoParser_ = videoParser; } - - protected: - bool parseVideoData(const uchar* data, size_t size, bool endOfStream = false); - - private: - VideoSource(const VideoSource&); - VideoSource& operator =(const VideoSource&); - - detail::FrameQueue* frameQueue_; - detail::VideoParser* videoParser_; - }; - - class Impl; - -private: - cv::Ptr impl_; + Uncompressed_YUV420 = (('I'<<24)|('Y'<<16)|('U'<<8)|('V')), // Y,U,V (4:2:0) + Uncompressed_YV12 = (('Y'<<24)|('V'<<16)|('1'<<8)|('2')), // Y,V,U (4:2:0) + Uncompressed_NV12 = (('N'<<24)|('V'<<16)|('1'<<8)|('2')), // Y,UV (4:2:0) + Uncompressed_YUYV = (('Y'<<24)|('U'<<16)|('Y'<<8)|('V')), // YUYV/YUY2 (4:2:2) + Uncompressed_UYVY = (('U'<<24)|('Y'<<16)|('V'<<8)|('Y')) // UYVY (4:2:2) }; -}} // namespace cv { namespace gpu { +enum ChromaFormat +{ + Monochrome = 0, + YUV420, + YUV422, + YUV444 +}; -namespace cv { +struct FormatInfo +{ + Codec codec; + ChromaFormat chromaFormat; + int width; + int height; +}; -template <> CV_EXPORTS void Ptr::delete_obj(); -template <> CV_EXPORTS void Ptr::delete_obj(); +class CV_EXPORTS VideoReader +{ +public: + virtual ~VideoReader() {} -} + virtual bool nextFrame(OutputArray frame) = 0; + + virtual FormatInfo format() const = 0; +}; + +class CV_EXPORTS RawVideoSource +{ +public: + virtual ~RawVideoSource() {} + + virtual bool getNextPacket(unsigned char** data, int* size, bool* endOfFile) = 0; + + virtual FormatInfo format() const = 0; +}; + +CV_EXPORTS Ptr createVideoReader(const String& filename); +CV_EXPORTS Ptr createVideoReader(const Ptr& source); + +}} // namespace cv { namespace gpucodec { #endif /* __OPENCV_GPUCODEC_HPP__ */ diff --git a/modules/gpucodec/perf/perf_video.cpp b/modules/gpucodec/perf/perf_video.cpp index 8f5e1700e..f389605d0 100644 --- a/modules/gpucodec/perf/perf_video.cpp +++ b/modules/gpucodec/perf/perf_video.cpp @@ -74,12 +74,11 @@ PERF_TEST_P(FileName, VideoReader, Values("gpu/video/768x576.avi", "gpu/video/19 if (PERF_RUN_GPU()) { - cv::gpu::VideoReader_GPU d_reader(inputFile); - ASSERT_TRUE( d_reader.isOpened() ); + cv::Ptr d_reader = cv::gpucodec::createVideoReader(inputFile); cv::gpu::GpuMat frame; - TEST_CYCLE_N(10) d_reader.read(frame); + TEST_CYCLE_N(10) d_reader->nextFrame(frame); GPU_SANITY_CHECK(frame); } @@ -119,7 +118,7 @@ PERF_TEST_P(FileName, VideoWriter, Values("gpu/video/768x576.avi", "gpu/video/19 if (PERF_RUN_GPU()) { - cv::gpu::VideoWriter_GPU d_writer; + cv::Ptr d_writer; cv::gpu::GpuMat d_frame; @@ -130,11 +129,11 @@ PERF_TEST_P(FileName, VideoWriter, Values("gpu/video/768x576.avi", "gpu/video/19 d_frame.upload(frame); - if (!d_writer.isOpened()) - d_writer.open(outputFile, frame.size(), FPS); + if (d_writer.empty()) + d_writer = cv::gpucodec::createVideoWriter(outputFile, frame.size(), FPS); startTimer(); next(); - d_writer.write(d_frame); + d_writer->write(d_frame); stopTimer(); } } diff --git a/modules/gpucodec/src/cuda/nv12_to_rgb.cu b/modules/gpucodec/src/cuda/nv12_to_rgb.cu index 536ba2715..1de916e5a 100644 --- a/modules/gpucodec/src/cuda/nv12_to_rgb.cu +++ b/modules/gpucodec/src/cuda/nv12_to_rgb.cu @@ -51,12 +51,7 @@ namespace cv { namespace gpu { namespace cudev { - __constant__ float constHueColorSpaceMat[9]; - - void loadHueCSC(float hueCSC[9]) - { - cudaSafeCall( cudaMemcpyToSymbol(constHueColorSpaceMat, hueCSC, 9 * sizeof(float)) ); - } + __constant__ float constHueColorSpaceMat[9] = {1.1644f, 0.0f, 1.596f, 1.1644f, -0.3918f, -0.813f, 1.1644f, 2.0172f, 0.0f}; __device__ void YUV2RGB(const uint* yuvi, float* red, float* green, float* blue) { diff --git a/modules/gpucodec/src/cuvid_video_source.cpp b/modules/gpucodec/src/cuvid_video_source.cpp index 73d6d2426..477951e93 100644 --- a/modules/gpucodec/src/cuvid_video_source.cpp +++ b/modules/gpucodec/src/cuvid_video_source.cpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -44,7 +45,11 @@ #ifdef HAVE_NVCUVID -cv::gpu::detail::CuvidVideoSource::CuvidVideoSource(const String& fname) +using namespace cv; +using namespace cv::gpucodec; +using namespace cv::gpucodec::detail; + +cv::gpucodec::detail::CuvidVideoSource::CuvidVideoSource(const String& fname) { CUVIDSOURCEPARAMS params; std::memset(¶ms, 0, sizeof(CUVIDSOURCEPARAMS)); @@ -55,51 +60,51 @@ cv::gpu::detail::CuvidVideoSource::CuvidVideoSource(const String& fname) params.pfnAudioDataHandler = 0; // now create the actual source - CUresult res = cuvidCreateVideoSource(&videoSource_, fname.c_str(), ¶ms); - if (res == CUDA_ERROR_INVALID_SOURCE) - throw std::runtime_error("Unsupported video source"); - cuSafeCall( res ); + CUresult cuRes = cuvidCreateVideoSource(&videoSource_, fname.c_str(), ¶ms); + if (cuRes == CUDA_ERROR_INVALID_SOURCE) + throw std::runtime_error(""); + cuSafeCall( cuRes ); CUVIDEOFORMAT vidfmt; cuSafeCall( cuvidGetSourceVideoFormat(videoSource_, &vidfmt, 0) ); - format_.codec = static_cast(vidfmt.codec); - format_.chromaFormat = static_cast(vidfmt.chroma_format); + format_.codec = static_cast(vidfmt.codec); + format_.chromaFormat = static_cast(vidfmt.chroma_format); format_.width = vidfmt.coded_width; format_.height = vidfmt.coded_height; } -cv::gpu::detail::CuvidVideoSource::~CuvidVideoSource() +cv::gpucodec::detail::CuvidVideoSource::~CuvidVideoSource() { cuvidDestroyVideoSource(videoSource_); } -cv::gpu::VideoReader_GPU::FormatInfo cv::gpu::detail::CuvidVideoSource::format() const +FormatInfo cv::gpucodec::detail::CuvidVideoSource::format() const { return format_; } -void cv::gpu::detail::CuvidVideoSource::start() +void cv::gpucodec::detail::CuvidVideoSource::start() { cuSafeCall( cuvidSetVideoSourceState(videoSource_, cudaVideoState_Started) ); } -void cv::gpu::detail::CuvidVideoSource::stop() +void cv::gpucodec::detail::CuvidVideoSource::stop() { cuSafeCall( cuvidSetVideoSourceState(videoSource_, cudaVideoState_Stopped) ); } -bool cv::gpu::detail::CuvidVideoSource::isStarted() const +bool cv::gpucodec::detail::CuvidVideoSource::isStarted() const { return (cuvidGetVideoSourceState(videoSource_) == cudaVideoState_Started); } -bool cv::gpu::detail::CuvidVideoSource::hasError() const +bool cv::gpucodec::detail::CuvidVideoSource::hasError() const { return (cuvidGetVideoSourceState(videoSource_) == cudaVideoState_Error); } -int CUDAAPI cv::gpu::detail::CuvidVideoSource::HandleVideoData(void* userData, CUVIDSOURCEDATAPACKET* packet) +int CUDAAPI cv::gpucodec::detail::CuvidVideoSource::HandleVideoData(void* userData, CUVIDSOURCEDATAPACKET* packet) { CuvidVideoSource* thiz = static_cast(userData); diff --git a/modules/gpucodec/src/cuvid_video_source.h b/modules/gpucodec/src/cuvid_video_source.hpp similarity index 88% rename from modules/gpucodec/src/cuvid_video_source.h rename to modules/gpucodec/src/cuvid_video_source.hpp index a4a0e8521..c2f0e2f57 100644 --- a/modules/gpucodec/src/cuvid_video_source.h +++ b/modules/gpucodec/src/cuvid_video_source.hpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -40,25 +41,25 @@ // //M*/ -#ifndef __CUVUD_VIDEO_SOURCE_H__ -#define __CUVUD_VIDEO_SOURCE_H__ - -#include "opencv2/core/private.gpu.hpp" -#include "opencv2/gpucodec.hpp" -#include "thread.h" +#ifndef __CUVID_VIDEO_SOURCE_HPP__ +#define __CUVID_VIDEO_SOURCE_HPP__ #include -namespace cv { namespace gpu { namespace detail +#include "opencv2/core/private.gpu.hpp" +#include "opencv2/gpucodec.hpp" +#include "video_source.hpp" + +namespace cv { namespace gpucodec { namespace detail { -class CuvidVideoSource : public VideoReader_GPU::VideoSource +class CuvidVideoSource : public VideoSource { public: explicit CuvidVideoSource(const String& fname); ~CuvidVideoSource(); - VideoReader_GPU::FormatInfo format() const; + FormatInfo format() const; void start(); void stop(); bool isStarted() const; @@ -78,9 +79,9 @@ private: static int CUDAAPI HandleVideoData(void* pUserData, CUVIDSOURCEDATAPACKET* pPacket); CUvideosource videoSource_; - VideoReader_GPU::FormatInfo format_; + FormatInfo format_; }; }}} -#endif // __CUVUD_VIDEO_SOURCE_H__ +#endif // __CUVID_VIDEO_SOURCE_HPP__ diff --git a/modules/gpucodec/src/ffmpeg_video_source.cpp b/modules/gpucodec/src/ffmpeg_video_source.cpp index 6ba09284d..b5a73875b 100644 --- a/modules/gpucodec/src/ffmpeg_video_source.cpp +++ b/modules/gpucodec/src/ffmpeg_video_source.cpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -48,6 +49,10 @@ #include "../src/cap_ffmpeg_impl.hpp" #endif +using namespace cv; +using namespace cv::gpucodec; +using namespace cv::gpucodec::detail; + namespace { Create_InputMediaStream_FFMPEG_Plugin create_InputMediaStream_FFMPEG_p = 0; @@ -94,7 +99,7 @@ namespace } } -cv::gpu::detail::FFmpegVideoSource::FFmpegVideoSource(const String& fname) : +cv::gpucodec::detail::FFmpegVideoSource::FFmpegVideoSource(const String& fname) : stream_(0) { CV_Assert( init_MediaStream_FFMPEG() ); @@ -106,75 +111,33 @@ cv::gpu::detail::FFmpegVideoSource::FFmpegVideoSource(const String& fname) : stream_ = create_InputMediaStream_FFMPEG_p(fname.c_str(), &codec, &chroma_format, &width, &height); if (!stream_) - CV_Error(cv::Error::StsUnsupportedFormat, "Unsupported video source"); + CV_Error(Error::StsUnsupportedFormat, "Unsupported video source"); - format_.codec = static_cast(codec); - format_.chromaFormat = static_cast(chroma_format); + format_.codec = static_cast(codec); + format_.chromaFormat = static_cast(chroma_format); format_.width = width; format_.height = height; } -cv::gpu::VideoReader_GPU::FormatInfo cv::gpu::detail::FFmpegVideoSource::format() const +cv::gpucodec::detail::FFmpegVideoSource::~FFmpegVideoSource() +{ + if (stream_) + release_InputMediaStream_FFMPEG_p(stream_); +} + +FormatInfo cv::gpucodec::detail::FFmpegVideoSource::format() const { return format_; } -void cv::gpu::detail::FFmpegVideoSource::start() +bool cv::gpucodec::detail::FFmpegVideoSource::getNextPacket(unsigned char** data, int* size, bool* bEndOfFile) { - stop_ = false; - hasError_ = false; - thread_ = new Thread(readLoop, this); -} + int endOfFile; -void cv::gpu::detail::FFmpegVideoSource::stop() -{ - stop_ = true; - thread_->wait(); - thread_.release(); -} + int res = read_InputMediaStream_FFMPEG_p(stream_, data, size, &endOfFile); -bool cv::gpu::detail::FFmpegVideoSource::isStarted() const -{ - return !stop_; -} - -bool cv::gpu::detail::FFmpegVideoSource::hasError() const -{ - return hasError_; -} - -void cv::gpu::detail::FFmpegVideoSource::readLoop(void* userData) -{ - FFmpegVideoSource* thiz = static_cast(userData); - - for (;;) - { - unsigned char* data; - int size; - int endOfFile; - - if (!read_InputMediaStream_FFMPEG_p(thiz->stream_, &data, &size, &endOfFile)) - { - thiz->hasError_ = !endOfFile; - break; - } - - if (!thiz->parseVideoData(data, size)) - { - thiz->hasError_ = true; - break; - } - - if (thiz->stop_) - break; - } - - thiz->parseVideoData(0, 0, true); -} - -template <> void cv::Ptr::delete_obj() -{ - if (obj) release_InputMediaStream_FFMPEG_p(obj); + *bEndOfFile = (endOfFile != 0); + return res != 0; } #endif // HAVE_CUDA diff --git a/modules/gpucodec/src/ffmpeg_video_source.h b/modules/gpucodec/src/ffmpeg_video_source.hpp similarity index 75% rename from modules/gpucodec/src/ffmpeg_video_source.h rename to modules/gpucodec/src/ffmpeg_video_source.hpp index d097785d7..6ea59ddac 100644 --- a/modules/gpucodec/src/ffmpeg_video_source.h +++ b/modules/gpucodec/src/ffmpeg_video_source.hpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -40,43 +41,31 @@ // //M*/ -#ifndef __FFMPEG_VIDEO_SOURCE_H__ -#define __FFMPEG_VIDEO_SOURCE_H__ +#ifndef __FFMPEG_VIDEO_SOURCE_HPP__ +#define __FFMPEG_VIDEO_SOURCE_HPP__ #include "opencv2/gpucodec.hpp" -#include "thread.h" struct InputMediaStream_FFMPEG; -namespace cv { namespace gpu { namespace detail { +namespace cv { namespace gpucodec { namespace detail { -class FFmpegVideoSource : public VideoReader_GPU::VideoSource +class FFmpegVideoSource : public RawVideoSource { public: FFmpegVideoSource(const String& fname); + ~FFmpegVideoSource(); - VideoReader_GPU::FormatInfo format() const; - void start(); - void stop(); - bool isStarted() const; - bool hasError() const; + bool getNextPacket(unsigned char** data, int* size, bool* endOfFile); + + FormatInfo format() const; private: - VideoReader_GPU::FormatInfo format_; + FormatInfo format_; - cv::Ptr stream_; - - cv::Ptr thread_; - volatile bool stop_; - volatile bool hasError_; - - static void readLoop(void* userData); + InputMediaStream_FFMPEG* stream_; }; }}} -namespace cv { - template <> void Ptr::delete_obj(); -} - -#endif // __FFMPEG_VIDEO_SOURCE_H__ +#endif // __FFMPEG_VIDEO_SOURCE_HPP__ diff --git a/modules/gpucodec/src/frame_queue.cpp b/modules/gpucodec/src/frame_queue.cpp index 2c5045500..f9141d84f 100644 --- a/modules/gpucodec/src/frame_queue.cpp +++ b/modules/gpucodec/src/frame_queue.cpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -44,16 +45,16 @@ #ifdef HAVE_NVCUVID -cv::gpu::detail::FrameQueue::FrameQueue() : +cv::gpucodec::detail::FrameQueue::FrameQueue() : endOfDecode_(0), framesInQueue_(0), readPosition_(0) { std::memset(displayQueue_, 0, sizeof(displayQueue_)); - std::memset((void*)isFrameInUse_, 0, sizeof(isFrameInUse_)); + std::memset((void*) isFrameInUse_, 0, sizeof(isFrameInUse_)); } -bool cv::gpu::detail::FrameQueue::waitUntilFrameAvailable(int pictureIndex) +bool cv::gpucodec::detail::FrameQueue::waitUntilFrameAvailable(int pictureIndex) { while (isInUse(pictureIndex)) { @@ -67,7 +68,7 @@ bool cv::gpu::detail::FrameQueue::waitUntilFrameAvailable(int pictureIndex) return true; } -void cv::gpu::detail::FrameQueue::enqueue(const CUVIDPARSERDISPINFO* picParams) +void cv::gpucodec::detail::FrameQueue::enqueue(const CUVIDPARSERDISPINFO* picParams) { // Mark the frame as 'in-use' so we don't re-use it for decoding until it is no longer needed // for display @@ -98,7 +99,7 @@ void cv::gpu::detail::FrameQueue::enqueue(const CUVIDPARSERDISPINFO* picParams) } while (!isEndOfDecode()); } -bool cv::gpu::detail::FrameQueue::dequeue(CUVIDPARSERDISPINFO& displayInfo) +bool cv::gpucodec::detail::FrameQueue::dequeue(CUVIDPARSERDISPINFO& displayInfo) { AutoLock autoLock(mtx_); diff --git a/modules/gpucodec/src/frame_queue.h b/modules/gpucodec/src/frame_queue.hpp similarity index 93% rename from modules/gpucodec/src/frame_queue.h rename to modules/gpucodec/src/frame_queue.hpp index d9a4433b3..c3b427b74 100644 --- a/modules/gpucodec/src/frame_queue.h +++ b/modules/gpucodec/src/frame_queue.hpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -40,15 +41,15 @@ // //M*/ -#ifndef __FRAME_QUEUE_H__ -#define __FRAME_QUEUE_H__ +#ifndef __FRAME_QUEUE_HPP__ +#define __FRAME_QUEUE_HPP__ #include "opencv2/core/utility.hpp" #include "opencv2/core/private.gpu.hpp" #include -namespace cv { namespace gpu { namespace detail +namespace cv { namespace gpucodec { namespace detail { class FrameQueue @@ -94,4 +95,4 @@ private: }}} -#endif // __FRAME_QUEUE_H__ +#endif // __FRAME_QUEUE_HPP__ diff --git a/modules/gpucodec/src/precomp.hpp b/modules/gpucodec/src/precomp.hpp index c8580c9fe..7cef1b7a9 100644 --- a/modules/gpucodec/src/precomp.hpp +++ b/modules/gpucodec/src/precomp.hpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -66,12 +67,13 @@ #include #endif - #include "thread.h" - #include "ffmpeg_video_source.h" - #include "cuvid_video_source.h" - #include "frame_queue.h" - #include "video_decoder.h" - #include "video_parser.h" + #include "thread.hpp" + #include "video_source.hpp" + #include "ffmpeg_video_source.hpp" + #include "cuvid_video_source.hpp" + #include "frame_queue.hpp" + #include "video_decoder.hpp" + #include "video_parser.hpp" #include "../src/cap_ffmpeg_api.hpp" #endif diff --git a/modules/gpucodec/src/thread.cpp b/modules/gpucodec/src/thread.cpp index db9f3de39..b936d8e21 100644 --- a/modules/gpucodec/src/thread.cpp +++ b/modules/gpucodec/src/thread.cpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -44,7 +45,7 @@ #ifdef HAVE_NVCUVID -using namespace cv::gpu::detail; +using namespace cv::gpucodec::detail; #ifdef WIN32 @@ -66,7 +67,7 @@ namespace } } -class cv::gpu::detail::Thread::Impl +class cv::gpucodec::detail::Thread::Impl { public: Impl(Thread::Func func, void* userData) @@ -119,7 +120,7 @@ namespace } } -class cv::gpu::detail::Thread::Impl +class cv::gpucodec::detail::Thread::Impl { public: Impl(Thread::Func func, void* userData) @@ -147,17 +148,17 @@ private: #endif -cv::gpu::detail::Thread::Thread(Func func, void* userData) : +cv::gpucodec::detail::Thread::Thread(Func func, void* userData) : impl_(new Impl(func, userData)) { } -void cv::gpu::detail::Thread::wait() +void cv::gpucodec::detail::Thread::wait() { impl_->wait(); } -void cv::gpu::detail::Thread::sleep(int ms) +void cv::gpucodec::detail::Thread::sleep(int ms) { #ifdef WIN32 ::Sleep(ms); @@ -166,7 +167,7 @@ void cv::gpu::detail::Thread::sleep(int ms) #endif } -template <> void cv::Ptr::delete_obj() +template <> void cv::Ptr::delete_obj() { if (obj) delete obj; } diff --git a/modules/gpucodec/src/thread.h b/modules/gpucodec/src/thread.hpp similarity index 87% rename from modules/gpucodec/src/thread.h rename to modules/gpucodec/src/thread.hpp index 1489f5830..ccda5b5c7 100644 --- a/modules/gpucodec/src/thread.h +++ b/modules/gpucodec/src/thread.hpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -40,12 +41,12 @@ // //M*/ -#ifndef __THREAD_WRAPPERS_H__ -#define __THREAD_WRAPPERS_H__ +#ifndef __THREAD_WRAPPERS_HPP__ +#define __THREAD_WRAPPERS_HPP__ #include "opencv2/core.hpp" -namespace cv { namespace gpu { namespace detail { +namespace cv { namespace gpucodec { namespace detail { class Thread { @@ -67,7 +68,7 @@ private: }}} namespace cv { - template <> void Ptr::delete_obj(); + template <> void Ptr::delete_obj(); } -#endif // __THREAD_WRAPPERS_H__ +#endif // __THREAD_WRAPPERS_HPP__ diff --git a/modules/gpucodec/src/video_decoder.cpp b/modules/gpucodec/src/video_decoder.cpp index 7e28e872b..d734ef363 100644 --- a/modules/gpucodec/src/video_decoder.cpp +++ b/modules/gpucodec/src/video_decoder.cpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -44,7 +45,7 @@ #ifdef HAVE_NVCUVID -void cv::gpu::detail::VideoDecoder::create(const VideoReader_GPU::FormatInfo& videoFormat) +void cv::gpucodec::detail::VideoDecoder::create(const FormatInfo& videoFormat) { release(); @@ -103,7 +104,7 @@ void cv::gpu::detail::VideoDecoder::create(const VideoReader_GPU::FormatInfo& vi cuSafeCall( cuvidCreateDecoder(&decoder_, &createInfo_) ); } -void cv::gpu::detail::VideoDecoder::release() +void cv::gpucodec::detail::VideoDecoder::release() { if (decoder_) { diff --git a/modules/gpucodec/src/video_decoder.h b/modules/gpucodec/src/video_decoder.hpp similarity index 85% rename from modules/gpucodec/src/video_decoder.h rename to modules/gpucodec/src/video_decoder.hpp index 7a36335cc..05a92f266 100644 --- a/modules/gpucodec/src/video_decoder.h +++ b/modules/gpucodec/src/video_decoder.hpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -40,21 +41,21 @@ // //M*/ -#ifndef __VIDEO_DECODER_H__ -#define __VIDEO_DECODER_H__ +#ifndef __VIDEO_DECODER_HPP__ +#define __VIDEO_DECODER_HPP__ + +#include #include "opencv2/core/private.gpu.hpp" #include "opencv2/gpucodec.hpp" -#include - -namespace cv { namespace gpu { namespace detail +namespace cv { namespace gpucodec { namespace detail { class VideoDecoder { public: - VideoDecoder(const VideoReader_GPU::FormatInfo& videoFormat, CUvideoctxlock lock) : lock_(lock), decoder_(0) + VideoDecoder(const FormatInfo& videoFormat, CUvideoctxlock lock) : lock_(lock), decoder_(0) { create(videoFormat); } @@ -64,7 +65,7 @@ public: release(); } - void create(const VideoReader_GPU::FormatInfo& videoFormat); + void create(const FormatInfo& videoFormat); void release(); // Get the code-type currently used. @@ -84,17 +85,17 @@ public: return cuvidDecodePicture(decoder_, picParams) == CUDA_SUCCESS; } - cv::gpu::GpuMat mapFrame(int picIdx, CUVIDPROCPARAMS& videoProcParams) + gpu::GpuMat mapFrame(int picIdx, CUVIDPROCPARAMS& videoProcParams) { CUdeviceptr ptr; unsigned int pitch; cuSafeCall( cuvidMapVideoFrame(decoder_, picIdx, &ptr, &pitch, &videoProcParams) ); - return GpuMat(targetHeight() * 3 / 2, targetWidth(), CV_8UC1, (void*) ptr, pitch); + return gpu::GpuMat(targetHeight() * 3 / 2, targetWidth(), CV_8UC1, (void*) ptr, pitch); } - void unmapFrame(cv::gpu::GpuMat& frame) + void unmapFrame(gpu::GpuMat& frame) { cuSafeCall( cuvidUnmapVideoFrame(decoder_, (CUdeviceptr) frame.data) ); frame.release(); @@ -108,4 +109,4 @@ private: }}} -#endif // __VIDEO_DECODER_H__ +#endif // __VIDEO_DECODER_HPP__ diff --git a/modules/gpucodec/src/video_parser.cpp b/modules/gpucodec/src/video_parser.cpp index 620f85fe8..66aab62ad 100644 --- a/modules/gpucodec/src/video_parser.cpp +++ b/modules/gpucodec/src/video_parser.cpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -44,11 +45,11 @@ #ifdef HAVE_NVCUVID -cv::gpu::detail::VideoParser::VideoParser(VideoDecoder* videoDecoder, FrameQueue* frameQueue) : +cv::gpucodec::detail::VideoParser::VideoParser(VideoDecoder* videoDecoder, FrameQueue* frameQueue) : videoDecoder_(videoDecoder), frameQueue_(frameQueue), unparsedPackets_(0), hasError_(false) { CUVIDPARSERPARAMS params; - memset(¶ms, 0, sizeof(CUVIDPARSERPARAMS)); + std::memset(¶ms, 0, sizeof(CUVIDPARSERPARAMS)); params.CodecType = videoDecoder->codec(); params.ulMaxNumDecodeSurfaces = videoDecoder->maxDecodeSurfaces(); @@ -61,7 +62,7 @@ cv::gpu::detail::VideoParser::VideoParser(VideoDecoder* videoDecoder, FrameQueue cuSafeCall( cuvidCreateVideoParser(&parser_, ¶ms) ); } -bool cv::gpu::detail::VideoParser::parseVideoData(const unsigned char* data, size_t size, bool endOfStream) +bool cv::gpucodec::detail::VideoParser::parseVideoData(const unsigned char* data, size_t size, bool endOfStream) { CUVIDSOURCEDATAPACKET packet; std::memset(&packet, 0, sizeof(CUVIDSOURCEDATAPACKET)); @@ -95,7 +96,7 @@ bool cv::gpu::detail::VideoParser::parseVideoData(const unsigned char* data, siz return !frameQueue_->isEndOfDecode(); } -int CUDAAPI cv::gpu::detail::VideoParser::HandleVideoSequence(void* userData, CUVIDEOFORMAT* format) +int CUDAAPI cv::gpucodec::detail::VideoParser::HandleVideoSequence(void* userData, CUVIDEOFORMAT* format) { VideoParser* thiz = static_cast(userData); @@ -106,10 +107,10 @@ int CUDAAPI cv::gpu::detail::VideoParser::HandleVideoSequence(void* userData, CU format->coded_height != thiz->videoDecoder_->frameHeight() || format->chroma_format != thiz->videoDecoder_->chromaFormat()) { - VideoReader_GPU::FormatInfo newFormat; + FormatInfo newFormat; - newFormat.codec = static_cast(format->codec); - newFormat.chromaFormat = static_cast(format->chroma_format); + newFormat.codec = static_cast(format->codec); + newFormat.chromaFormat = static_cast(format->chroma_format); newFormat.width = format->coded_width; newFormat.height = format->coded_height; @@ -127,7 +128,7 @@ int CUDAAPI cv::gpu::detail::VideoParser::HandleVideoSequence(void* userData, CU return true; } -int CUDAAPI cv::gpu::detail::VideoParser::HandlePictureDecode(void* userData, CUVIDPICPARAMS* picParams) +int CUDAAPI cv::gpucodec::detail::VideoParser::HandlePictureDecode(void* userData, CUVIDPICPARAMS* picParams) { VideoParser* thiz = static_cast(userData); @@ -147,7 +148,7 @@ int CUDAAPI cv::gpu::detail::VideoParser::HandlePictureDecode(void* userData, CU return true; } -int CUDAAPI cv::gpu::detail::VideoParser::HandlePictureDisplay(void* userData, CUVIDPARSERDISPINFO* picParams) +int CUDAAPI cv::gpucodec::detail::VideoParser::HandlePictureDisplay(void* userData, CUVIDPARSERDISPINFO* picParams) { VideoParser* thiz = static_cast(userData); diff --git a/modules/gpucodec/src/video_parser.h b/modules/gpucodec/src/video_parser.hpp similarity index 92% rename from modules/gpucodec/src/video_parser.h rename to modules/gpucodec/src/video_parser.hpp index e11b7eff6..b4dddb389 100644 --- a/modules/gpucodec/src/video_parser.h +++ b/modules/gpucodec/src/video_parser.hpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -40,17 +41,17 @@ // //M*/ -#ifndef __VIDEO_PARSER_H__ -#define __VIDEO_PARSER_H__ - -#include "opencv2/core/private.gpu.hpp" -#include "opencv2/gpucodec.hpp" -#include "frame_queue.h" -#include "video_decoder.h" +#ifndef __VIDEO_PARSER_HPP__ +#define __VIDEO_PARSER_HPP__ #include -namespace cv { namespace gpu { namespace detail +#include "opencv2/core/private.gpu.hpp" +#include "opencv2/gpucodec.hpp" +#include "frame_queue.hpp" +#include "video_decoder.hpp" + +namespace cv { namespace gpucodec { namespace detail { class VideoParser @@ -91,4 +92,4 @@ private: }}} -#endif // __VIDEO_PARSER_H__ +#endif // __VIDEO_PARSER_HPP__ diff --git a/modules/gpucodec/src/video_reader.cpp b/modules/gpucodec/src/video_reader.cpp index dbb4bbcf2..67e9cd107 100644 --- a/modules/gpucodec/src/video_reader.cpp +++ b/modules/gpucodec/src/video_reader.cpp @@ -42,88 +42,77 @@ #include "precomp.hpp" +using namespace cv; +using namespace cv::gpu; +using namespace cv::gpucodec; + #ifndef HAVE_NVCUVID -class cv::gpu::VideoReader_GPU::Impl -{ -}; - -cv::gpu::VideoReader_GPU::VideoReader_GPU() { throw_no_cuda(); } -cv::gpu::VideoReader_GPU::VideoReader_GPU(const String&) { throw_no_cuda(); } -cv::gpu::VideoReader_GPU::VideoReader_GPU(const cv::Ptr&) { throw_no_cuda(); } -cv::gpu::VideoReader_GPU::~VideoReader_GPU() { } -void cv::gpu::VideoReader_GPU::open(const String&) { throw_no_cuda(); } -void cv::gpu::VideoReader_GPU::open(const cv::Ptr&) { throw_no_cuda(); } -bool cv::gpu::VideoReader_GPU::isOpened() const { return false; } -void cv::gpu::VideoReader_GPU::close() { } -bool cv::gpu::VideoReader_GPU::read(GpuMat&) { throw_no_cuda(); return false; } -cv::gpu::VideoReader_GPU::FormatInfo cv::gpu::VideoReader_GPU::format() const { throw_no_cuda(); FormatInfo format_ = {MPEG1,Monochrome,0,0}; return format_; } -bool cv::gpu::VideoReader_GPU::VideoSource::parseVideoData(const unsigned char*, size_t, bool) { throw_no_cuda(); return false; } -void cv::gpu::VideoReader_GPU::dumpFormat(std::ostream&) { throw_no_cuda(); } +Ptr cv::gpucodec::createVideoReader(const String&) { throw_no_cuda(); return Ptr(); } +Ptr cv::gpucodec::createVideoReader(const Ptr&) { throw_no_cuda(); return Ptr(); } #else // HAVE_NVCUVID -class cv::gpu::VideoReader_GPU::Impl -{ -public: - explicit Impl(const cv::Ptr& source); - ~Impl(); - - bool grab(cv::gpu::GpuMat& frame); - - cv::gpu::VideoReader_GPU::FormatInfo format() const { return videoSource_->format(); } - -private: - cv::Ptr videoSource_; - - cv::Ptr frameQueue_; - cv::Ptr videoDecoder_; - cv::Ptr videoParser_; - - CUvideoctxlock lock_; - - std::deque< std::pair > frames_; -}; - -cv::gpu::VideoReader_GPU::Impl::Impl(const cv::Ptr& source) : - videoSource_(source), - lock_(0) -{ - // init context - GpuMat temp(1, 1, CV_8UC1); - temp.release(); - - DeviceInfo devInfo; - CV_Assert( devInfo.supports(FEATURE_SET_COMPUTE_11) ); - - CUcontext ctx; - cuSafeCall( cuCtxGetCurrent(&ctx) ); - cuSafeCall( cuvidCtxLockCreate(&lock_, ctx) ); - - frameQueue_ = new detail::FrameQueue; - videoDecoder_ = new detail::VideoDecoder(videoSource_->format(), lock_); - videoParser_ = new detail::VideoParser(videoDecoder_, frameQueue_); - - videoSource_->setFrameQueue(frameQueue_); - videoSource_->setVideoParser(videoParser_); - - videoSource_->start(); -} - -cv::gpu::VideoReader_GPU::Impl::~Impl() -{ - frameQueue_->endDecode(); - videoSource_->stop(); -} - namespace cv { namespace gpu { namespace cudev { - void loadHueCSC(float hueCSC[9]); void NV12_to_RGB(const PtrStepb decodedFrame, PtrStepSz interopFrame, cudaStream_t stream = 0); }}} namespace { + class VideoReaderImpl : public VideoReader + { + public: + explicit VideoReaderImpl(const Ptr& source); + ~VideoReaderImpl(); + + bool nextFrame(OutputArray frame); + + FormatInfo format() const; + + private: + Ptr videoSource_; + + Ptr frameQueue_; + Ptr videoDecoder_; + Ptr videoParser_; + + CUvideoctxlock lock_; + + std::deque< std::pair > frames_; + }; + + FormatInfo VideoReaderImpl::format() const + { + return videoSource_->format(); + } + + VideoReaderImpl::VideoReaderImpl(const Ptr& source) : + videoSource_(source), + lock_(0) + { + // init context + GpuMat temp(1, 1, CV_8UC1); + temp.release(); + + CUcontext ctx; + cuSafeCall( cuCtxGetCurrent(&ctx) ); + cuSafeCall( cuvidCtxLockCreate(&lock_, ctx) ); + + frameQueue_ = new detail::FrameQueue; + videoDecoder_ = new detail::VideoDecoder(videoSource_->format(), lock_); + videoParser_ = new detail::VideoParser(videoDecoder_, frameQueue_); + + videoSource_->setVideoParser(videoParser_); + videoSource_->start(); + } + + VideoReaderImpl::~VideoReaderImpl() + { + frameQueue_->endDecode(); + videoSource_->stop(); + } + class VideoCtxAutoLock { public: @@ -134,259 +123,114 @@ namespace CUvideoctxlock m_lock; }; - enum ColorSpace - { - ITU601 = 1, - ITU709 = 2 - }; - - void setColorSpaceMatrix(ColorSpace CSC, float hueCSC[9], float hue) - { - float hueSin = std::sin(hue); - float hueCos = std::cos(hue); - - if (CSC == ITU601) - { - //CCIR 601 - hueCSC[0] = 1.1644f; - hueCSC[1] = hueSin * 1.5960f; - hueCSC[2] = hueCos * 1.5960f; - hueCSC[3] = 1.1644f; - hueCSC[4] = (hueCos * -0.3918f) - (hueSin * 0.8130f); - hueCSC[5] = (hueSin * 0.3918f) - (hueCos * 0.8130f); - hueCSC[6] = 1.1644f; - hueCSC[7] = hueCos * 2.0172f; - hueCSC[8] = hueSin * -2.0172f; - } - else if (CSC == ITU709) - { - //CCIR 709 - hueCSC[0] = 1.0f; - hueCSC[1] = hueSin * 1.57480f; - hueCSC[2] = hueCos * 1.57480f; - hueCSC[3] = 1.0; - hueCSC[4] = (hueCos * -0.18732f) - (hueSin * 0.46812f); - hueCSC[5] = (hueSin * 0.18732f) - (hueCos * 0.46812f); - hueCSC[6] = 1.0f; - hueCSC[7] = hueCos * 1.85560f; - hueCSC[8] = hueSin * -1.85560f; - } - } - - void cudaPostProcessFrame(const cv::gpu::GpuMat& decodedFrame, cv::gpu::GpuMat& interopFrame, int width, int height) + void cudaPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height) { using namespace cv::gpu::cudev; - static bool updateCSC = true; - static float hueColorSpaceMat[9]; - - // Upload the Color Space Conversion Matrices - if (updateCSC) - { - const ColorSpace colorSpace = ITU601; - const float hue = 0.0f; - - // CCIR 601/709 - setColorSpaceMatrix(colorSpace, hueColorSpaceMat, hue); - - updateCSC = false; - } - // Final Stage: NV12toARGB color space conversion - interopFrame.create(height, width, CV_8UC4); + _outFrame.create(height, width, CV_8UC4); + GpuMat outFrame = _outFrame.getGpuMat(); - loadHueCSC(hueColorSpaceMat); - - NV12_to_RGB(decodedFrame, interopFrame); + NV12_to_RGB(decodedFrame, outFrame); } -} -bool cv::gpu::VideoReader_GPU::Impl::grab(GpuMat& frame) -{ - if (videoSource_->hasError() || videoParser_->hasError()) - CV_Error(cv::Error::StsUnsupportedFormat, "Unsupported video source"); - - if (!videoSource_->isStarted() || frameQueue_->isEndOfDecode()) - return false; - - if (frames_.empty()) + bool VideoReaderImpl::nextFrame(OutputArray frame) { - CUVIDPARSERDISPINFO displayInfo; + if (videoSource_->hasError() || videoParser_->hasError()) + CV_Error(Error::StsUnsupportedFormat, "Unsupported video source"); - for (;;) + if (!videoSource_->isStarted() || frameQueue_->isEndOfDecode()) + return false; + + if (frames_.empty()) { - if (frameQueue_->dequeue(displayInfo)) - break; + CUVIDPARSERDISPINFO displayInfo; - if (videoSource_->hasError() || videoParser_->hasError()) - CV_Error(cv::Error::StsUnsupportedFormat, "Unsupported video source"); + for (;;) + { + if (frameQueue_->dequeue(displayInfo)) + break; - if (frameQueue_->isEndOfDecode()) - return false; + if (videoSource_->hasError() || videoParser_->hasError()) + CV_Error(Error::StsUnsupportedFormat, "Unsupported video source"); - // Wait a bit - detail::Thread::sleep(1); + if (frameQueue_->isEndOfDecode()) + return false; + + // Wait a bit + detail::Thread::sleep(1); + } + + bool isProgressive = displayInfo.progressive_frame != 0; + const int num_fields = isProgressive ? 1 : 2 + displayInfo.repeat_first_field; + + for (int active_field = 0; active_field < num_fields; ++active_field) + { + CUVIDPROCPARAMS videoProcParams; + std::memset(&videoProcParams, 0, sizeof(CUVIDPROCPARAMS)); + + videoProcParams.progressive_frame = displayInfo.progressive_frame; + videoProcParams.second_field = active_field; + videoProcParams.top_field_first = displayInfo.top_field_first; + videoProcParams.unpaired_field = (num_fields == 1); + + frames_.push_back(std::make_pair(displayInfo, videoProcParams)); + } } - bool isProgressive = displayInfo.progressive_frame != 0; - const int num_fields = isProgressive ? 1 : 2 + displayInfo.repeat_first_field; + if (frames_.empty()) + return false; + + std::pair frameInfo = frames_.front(); + frames_.pop_front(); - for (int active_field = 0; active_field < num_fields; ++active_field) { - CUVIDPROCPARAMS videoProcParams; - std::memset(&videoProcParams, 0, sizeof(CUVIDPROCPARAMS)); + VideoCtxAutoLock autoLock(lock_); - videoProcParams.progressive_frame = displayInfo.progressive_frame; - videoProcParams.second_field = active_field; - videoProcParams.top_field_first = displayInfo.top_field_first; - videoProcParams.unpaired_field = (num_fields == 1); + // map decoded video frame to CUDA surface + GpuMat decodedFrame = videoDecoder_->mapFrame(frameInfo.first.picture_index, frameInfo.second); - frames_.push_back(std::make_pair(displayInfo, videoProcParams)); + // perform post processing on the CUDA surface (performs colors space conversion and post processing) + // comment this out if we inclue the line of code seen above + cudaPostProcessFrame(decodedFrame, frame, videoDecoder_->targetWidth(), videoDecoder_->targetHeight()); + + // unmap video frame + // unmapFrame() synchronizes with the VideoDecode API (ensures the frame has finished decoding) + videoDecoder_->unmapFrame(decodedFrame); } + + // release the frame, so it can be re-used in decoder + if (frames_.empty()) + frameQueue_->releaseFrame(frameInfo.first); + + return true; } - - if (frames_.empty()) - return false; - - std::pair frameInfo = frames_.front(); - frames_.pop_front(); - - { - VideoCtxAutoLock autoLock(lock_); - - // map decoded video frame to CUDA surface - cv::gpu::GpuMat decodedFrame = videoDecoder_->mapFrame(frameInfo.first.picture_index, frameInfo.second); - - // perform post processing on the CUDA surface (performs colors space conversion and post processing) - // comment this out if we inclue the line of code seen above - cudaPostProcessFrame(decodedFrame, frame, videoDecoder_->targetWidth(), videoDecoder_->targetHeight()); - - // unmap video frame - // unmapFrame() synchronizes with the VideoDecode API (ensures the frame has finished decoding) - videoDecoder_->unmapFrame(decodedFrame); - } - - // release the frame, so it can be re-used in decoder - if (frames_.empty()) - frameQueue_->releaseFrame(frameInfo.first); - - return true; } -//////////////////////////////////////////////////////////////////////////// - -cv::gpu::VideoReader_GPU::VideoReader_GPU() -{ -} - -cv::gpu::VideoReader_GPU::VideoReader_GPU(const String& filename) -{ - open(filename); -} - -cv::gpu::VideoReader_GPU::VideoReader_GPU(const cv::Ptr& source) -{ - open(source); -} - -cv::gpu::VideoReader_GPU::~VideoReader_GPU() -{ - close(); -} - -void cv::gpu::VideoReader_GPU::open(const String& filename) +Ptr cv::gpucodec::createVideoReader(const String& filename) { CV_Assert( !filename.empty() ); -#ifndef __APPLE__ + Ptr videoSource; + try { - cv::Ptr source(new detail::CuvidVideoSource(filename)); - open(source); + videoSource = new detail::CuvidVideoSource(filename); } - catch (const std::runtime_error&) -#endif + catch (...) { - cv::Ptr source(new cv::gpu::detail::FFmpegVideoSource(filename)); - open(source); - } -} - -void cv::gpu::VideoReader_GPU::open(const cv::Ptr& source) -{ - CV_Assert( !source.empty() ); - close(); - impl_ = new Impl(source); -} - -bool cv::gpu::VideoReader_GPU::isOpened() const -{ - return !impl_.empty(); -} - -void cv::gpu::VideoReader_GPU::close() -{ - impl_.release(); -} - -bool cv::gpu::VideoReader_GPU::read(GpuMat& image) -{ - if (!isOpened()) - return false; - - if (!impl_->grab(image)) - { - close(); - return false; + Ptr source(new detail::FFmpegVideoSource(filename)); + videoSource = new detail::RawVideoSourceWrapper(source); } - return true; + return new VideoReaderImpl(videoSource); } -cv::gpu::VideoReader_GPU::FormatInfo cv::gpu::VideoReader_GPU::format() const +Ptr cv::gpucodec::createVideoReader(const Ptr& source) { - CV_Assert( isOpened() ); - return impl_->format(); -} - -bool cv::gpu::VideoReader_GPU::VideoSource::parseVideoData(const unsigned char* data, size_t size, bool endOfStream) -{ - return videoParser_->parseVideoData(data, size, endOfStream); -} - -void cv::gpu::VideoReader_GPU::dumpFormat(std::ostream& st) -{ - static const char* codecs[] = - { - "MPEG1", - "MPEG2", - "MPEG4", - "VC1", - "H264", - "JPEG", - "H264_SVC", - "H264_MVC" - }; - - static const char* chromas[] = - { - "Monochrome", - "YUV420", - "YUV422", - "YUV444" - }; - - FormatInfo _format = this->format(); - - st << "Frame Size : " << _format.width << "x" << _format.height << std::endl; - st << "Codec : " << (_format.codec <= H264_MVC ? codecs[_format.codec] : "Uncompressed YUV") << std::endl; - st << "Chroma Format : " << chromas[_format.chromaFormat] << std::endl; + Ptr videoSource(new detail::RawVideoSourceWrapper(source)); + return new VideoReaderImpl(videoSource); } #endif // HAVE_NVCUVID - -template <> void cv::Ptr::delete_obj() -{ - if (obj) delete obj; -} diff --git a/modules/gpucodec/src/video_source.cpp b/modules/gpucodec/src/video_source.cpp new file mode 100644 index 000000000..ce6a1bd8c --- /dev/null +++ b/modules/gpucodec/src/video_source.cpp @@ -0,0 +1,121 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, 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. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" + +#ifdef HAVE_NVCUVID + +using namespace cv; +using namespace cv::gpucodec; +using namespace cv::gpucodec::detail; + +bool cv::gpucodec::detail::VideoSource::parseVideoData(const unsigned char* data, size_t size, bool endOfStream) +{ + return videoParser_->parseVideoData(data, size, endOfStream); +} + +cv::gpucodec::detail::RawVideoSourceWrapper::RawVideoSourceWrapper(const Ptr& source) : + source_(source) +{ + CV_Assert( !source_.empty() ); +} + +cv::gpucodec::FormatInfo cv::gpucodec::detail::RawVideoSourceWrapper::format() const +{ + return source_->format(); +} + +void cv::gpucodec::detail::RawVideoSourceWrapper::start() +{ + stop_ = false; + hasError_ = false; + thread_ = new Thread(readLoop, this); +} + +void cv::gpucodec::detail::RawVideoSourceWrapper::stop() +{ + stop_ = true; + thread_->wait(); + thread_.release(); +} + +bool cv::gpucodec::detail::RawVideoSourceWrapper::isStarted() const +{ + return !stop_; +} + +bool cv::gpucodec::detail::RawVideoSourceWrapper::hasError() const +{ + return hasError_; +} + +void cv::gpucodec::detail::RawVideoSourceWrapper::readLoop(void* userData) +{ + RawVideoSourceWrapper* thiz = static_cast(userData); + + for (;;) + { + unsigned char* data; + int size; + bool endOfFile; + + if (!thiz->source_->getNextPacket(&data, &size, &endOfFile)) + { + thiz->hasError_ = !endOfFile; + break; + } + + if (!thiz->parseVideoData(data, size)) + { + thiz->hasError_ = true; + break; + } + + if (thiz->stop_) + break; + } + + thiz->parseVideoData(0, 0, true); +} + +#endif // HAVE_NVCUVID diff --git a/modules/gpucodec/src/video_source.hpp b/modules/gpucodec/src/video_source.hpp new file mode 100644 index 000000000..b4d930ee0 --- /dev/null +++ b/modules/gpucodec/src/video_source.hpp @@ -0,0 +1,99 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, 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. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __GPUCODEC_VIDEO_SOURCE_H__ +#define __GPUCODEC_VIDEO_SOURCE_H__ + +#include "opencv2/core/private.gpu.hpp" +#include "opencv2/gpucodec.hpp" +#include "thread.hpp" + +namespace cv { namespace gpucodec { namespace detail +{ + +class VideoParser; + +class VideoSource +{ +public: + virtual ~VideoSource() {} + + virtual FormatInfo format() const = 0; + virtual void start() = 0; + virtual void stop() = 0; + virtual bool isStarted() const = 0; + virtual bool hasError() const = 0; + + void setVideoParser(detail::VideoParser* videoParser) { videoParser_ = videoParser; } + +protected: + bool parseVideoData(const uchar* data, size_t size, bool endOfStream = false); + +private: + detail::VideoParser* videoParser_; +}; + +class RawVideoSourceWrapper : public VideoSource +{ +public: + RawVideoSourceWrapper(const Ptr& source); + + FormatInfo format() const; + void start(); + void stop(); + bool isStarted() const; + bool hasError() const; + +private: + Ptr source_; + + Ptr thread_; + volatile bool stop_; + volatile bool hasError_; + + static void readLoop(void* userData); +}; + +}}} + +#endif // __GPUCODEC_VIDEO_SOURCE_H__ diff --git a/modules/gpucodec/src/video_writer.cpp b/modules/gpucodec/src/video_writer.cpp index 94100c0b8..6ffb7c12d 100644 --- a/modules/gpucodec/src/video_writer.cpp +++ b/modules/gpucodec/src/video_writer.cpp @@ -7,11 +7,12 @@ // copy or use the software. // // -// License Agreement +// License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, 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. // // Redistribution and use in source and binary forms, with or without modification, @@ -42,36 +43,32 @@ #include "precomp.hpp" +using namespace cv; +using namespace cv::gpu; +using namespace cv::gpucodec; + #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(); } -cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const String&, cv::Size, double, SurfaceFormat) { throw_no_cuda(); } -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&, cv::Size, double, SurfaceFormat) { throw_no_cuda(); } -cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr&, 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&, cv::Size, double, SurfaceFormat) { throw_no_cuda(); } -void cv::gpu::VideoWriter_GPU::open(const cv::Ptr&, 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; } +Ptr cv::gpucodec::createVideoWriter(const String&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr(); } +Ptr cv::gpucodec::createVideoWriter(const String&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr(); } -cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams() { throw_no_cuda(); } -cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams(const String&) { throw_no_cuda(); } -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(); } +Ptr cv::gpucodec::createVideoWriter(const Ptr&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr(); } +Ptr cv::gpucodec::createVideoWriter(const Ptr&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr(); } #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 { @@ -84,7 +81,7 @@ namespace err = NVGetHWEncodeCaps(); if (err) - CV_Error(cv::Error::GpuNotSupported, "No CUDA capability present"); + CV_Error(Error::GpuNotSupported, "No CUDA capability present"); // Create the Encoder API Interface err = NVCreateEncoder(&encoder_); @@ -108,405 +105,395 @@ namespace enum CodecType { - MPEG1, //not supported yet - MPEG2, //not supported yet - MPEG4, //not supported yet + MPEG1, // not supported yet + MPEG2, // not supported yet + MPEG4, // not supported yet H264 }; -} -class cv::gpu::VideoWriter_GPU::Impl -{ -public: - Impl(const cv::Ptr& callback, cv::Size frameSize, double fps, SurfaceFormat format, CodecType codec = H264); - Impl(const cv::Ptr& callback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec = H264); - - void write(const cv::gpu::GpuMat& image, bool lastFrame); - - EncoderParams getParams() const; - -private: - Impl(const Impl&); - Impl& operator=(const Impl&); - - void initEncoder(double fps); - void setEncodeParams(const EncoderParams& params); - void initGpuMemory(); - void initCallBacks(); - void createHWEncoder(); - - cv::Ptr callback_; - cv::Size frameSize_; - - CodecType codec_; - SurfaceFormat inputFormat_; - NVVE_SurfaceFormat surfaceFormat_; - - NVEncoderWrapper encoder_; - - cv::gpu::GpuMat videoFrame_; - CUvideoctxlock cuCtxLock_; - - // CallBacks - - static unsigned char* NVENCAPI HandleAcquireBitStream(int* pBufferSize, void* pUserdata); - static void NVENCAPI HandleReleaseBitStream(int nBytesInBuffer, unsigned char* cb, void* pUserdata); - static void NVENCAPI HandleOnBeginFrame(const NVVE_BeginFrameInfo* pbfi, void* pUserdata); - static void NVENCAPI HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata); -}; - -cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr& callback, cv::Size frameSize, double fps, SurfaceFormat format, CodecType codec) : - callback_(callback), - frameSize_(frameSize), - codec_(codec), - inputFormat_(format), - cuCtxLock_(0) -{ - surfaceFormat_ = inputFormat_ == SF_BGR ? YV12 : static_cast(inputFormat_); - - initEncoder(fps); - - initGpuMemory(); - - initCallBacks(); - - createHWEncoder(); -} - -cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr& callback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec) : - callback_(callback), - frameSize_(frameSize), - codec_(codec), - inputFormat_(format), - cuCtxLock_(0) -{ - surfaceFormat_ = inputFormat_ == SF_BGR ? YV12 : static_cast(inputFormat_); - - initEncoder(fps); - - setEncodeParams(params); - - initGpuMemory(); - - initCallBacks(); - - createHWEncoder(); -} - -void cv::gpu::VideoWriter_GPU::Impl::initEncoder(double fps) -{ - int err; - - // Set codec - - static const unsigned long codecs_id[] = + class VideoWriterImpl : public VideoWriter { - NV_CODEC_TYPE_MPEG1, NV_CODEC_TYPE_MPEG2, NV_CODEC_TYPE_MPEG4, NV_CODEC_TYPE_H264, NV_CODEC_TYPE_VC1 - }; - err = NVSetCodec(encoder_, codecs_id[codec_]); - if (err) - CV_Error(cv::Error::StsNotImplemented, "Codec format is not supported"); + public: + VideoWriterImpl(const Ptr& callback, Size frameSize, double fps, SurfaceFormat format, CodecType codec = H264); + VideoWriterImpl(const Ptr& callback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec = H264); - // Set default params + void write(InputArray frame, bool lastFrame = false); - err = NVSetDefaultParam(encoder_); - CV_Assert( err == 0 ); + EncoderParams getEncoderParams() const; - // Set some common params + private: + void initEncoder(double fps); + void setEncodeParams(const EncoderParams& params); + void initGpuMemory(); + void initCallBacks(); + void createHWEncoder(); - int inputSize[] = { frameSize_.width, frameSize_.height }; - err = NVSetParamValue(encoder_, NVVE_IN_SIZE, &inputSize); - CV_Assert( err == 0 ); - err = NVSetParamValue(encoder_, NVVE_OUT_SIZE, &inputSize); - CV_Assert( err == 0 ); + Ptr callback_; + Size frameSize_; - int aspectRatio[] = { frameSize_.width, frameSize_.height, ASPECT_RATIO_DAR }; - err = NVSetParamValue(encoder_, NVVE_ASPECT_RATIO, &aspectRatio); - CV_Assert( err == 0 ); + CodecType codec_; + SurfaceFormat inputFormat_; + NVVE_SurfaceFormat surfaceFormat_; - // FPS + NVEncoderWrapper encoder_; - int frame_rate = static_cast(fps + 0.5); - int frame_rate_base = 1; - while (fabs(static_cast(frame_rate) / frame_rate_base) - fps > 0.001) - { - frame_rate_base *= 10; - frame_rate = static_cast(fps*frame_rate_base + 0.5); - } - int FrameRate[] = { frame_rate, frame_rate_base }; - err = NVSetParamValue(encoder_, NVVE_FRAME_RATE, &FrameRate); - CV_Assert( err == 0 ); + GpuMat videoFrame_; + CUvideoctxlock cuCtxLock_; - // Select device for encoding + // CallBacks - int gpuID = cv::gpu::getDevice(); - err = NVSetParamValue(encoder_, NVVE_FORCE_GPU_SELECTION, &gpuID); - CV_Assert( err == 0 ); -} - -void cv::gpu::VideoWriter_GPU::Impl::setEncodeParams(const EncoderParams& params) -{ - int err; - - int P_Interval = params.P_Interval; - err = NVSetParamValue(encoder_, NVVE_P_INTERVAL, &P_Interval); - CV_Assert( err == 0 ); - - int IDR_Period = params.IDR_Period; - err = NVSetParamValue(encoder_, NVVE_IDR_PERIOD, &IDR_Period); - CV_Assert( err == 0 ); - - int DynamicGOP = params.DynamicGOP; - err = NVSetParamValue(encoder_, NVVE_DYNAMIC_GOP, &DynamicGOP); - CV_Assert( err == 0 ); - - NVVE_RateCtrlType RCType = static_cast(params.RCType); - err = NVSetParamValue(encoder_, NVVE_RC_TYPE, &RCType); - CV_Assert( err == 0 ); - - int AvgBitrate = params.AvgBitrate; - err = NVSetParamValue(encoder_, NVVE_AVG_BITRATE, &AvgBitrate); - CV_Assert( err == 0 ); - - int PeakBitrate = params.PeakBitrate; - err = NVSetParamValue(encoder_, NVVE_PEAK_BITRATE, &PeakBitrate); - CV_Assert( err == 0 ); - - int QP_Level_Intra = params.QP_Level_Intra; - err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTRA, &QP_Level_Intra); - CV_Assert( err == 0 ); - - int QP_Level_InterP = params.QP_Level_InterP; - err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTER_P, &QP_Level_InterP); - CV_Assert( err == 0 ); - - int QP_Level_InterB = params.QP_Level_InterB; - err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTER_B, &QP_Level_InterB); - CV_Assert( err == 0 ); - - int DeblockMode = params.DeblockMode; - err = NVSetParamValue(encoder_, NVVE_DEBLOCK_MODE, &DeblockMode); - CV_Assert( err == 0 ); - - int ProfileLevel = params.ProfileLevel; - err = NVSetParamValue(encoder_, NVVE_PROFILE_LEVEL, &ProfileLevel); - CV_Assert( err == 0 ); - - int ForceIntra = params.ForceIntra; - err = NVSetParamValue(encoder_, NVVE_FORCE_INTRA, &ForceIntra); - CV_Assert( err == 0 ); - - int ForceIDR = params.ForceIDR; - err = NVSetParamValue(encoder_, NVVE_FORCE_IDR, &ForceIDR); - CV_Assert( err == 0 ); - - int ClearStat = params.ClearStat; - err = NVSetParamValue(encoder_, NVVE_CLEAR_STAT, &ClearStat); - CV_Assert( err == 0 ); - - NVVE_DI_MODE DIMode = static_cast(params.DIMode); - err = NVSetParamValue(encoder_, NVVE_SET_DEINTERLACE, &DIMode); - CV_Assert( err == 0 ); - - if (params.Presets != -1) - { - NVVE_PRESETS_TARGET Presets = static_cast(params.Presets); - err = NVSetParamValue(encoder_, NVVE_PRESETS, &Presets); - CV_Assert ( err == 0 ); - } - - int DisableCabac = params.DisableCabac; - err = NVSetParamValue(encoder_, NVVE_DISABLE_CABAC, &DisableCabac); - CV_Assert ( err == 0 ); - - int NaluFramingType = params.NaluFramingType; - err = NVSetParamValue(encoder_, NVVE_CONFIGURE_NALU_FRAMING_TYPE, &NaluFramingType); - CV_Assert ( err == 0 ); - - int DisableSPSPPS = params.DisableSPSPPS; - err = NVSetParamValue(encoder_, NVVE_DISABLE_SPS_PPS, &DisableSPSPPS); - CV_Assert ( err == 0 ); -} - -cv::gpu::VideoWriter_GPU::EncoderParams cv::gpu::VideoWriter_GPU::Impl::getParams() const -{ - int err; - - EncoderParams params; - - int P_Interval; - err = NVGetParamValue(encoder_, NVVE_P_INTERVAL, &P_Interval); - CV_Assert( err == 0 ); - params.P_Interval = P_Interval; - - int IDR_Period; - err = NVGetParamValue(encoder_, NVVE_IDR_PERIOD, &IDR_Period); - CV_Assert( err == 0 ); - params.IDR_Period = IDR_Period; - - int DynamicGOP; - err = NVGetParamValue(encoder_, NVVE_DYNAMIC_GOP, &DynamicGOP); - CV_Assert( err == 0 ); - params.DynamicGOP = DynamicGOP; - - NVVE_RateCtrlType RCType; - err = NVGetParamValue(encoder_, NVVE_RC_TYPE, &RCType); - CV_Assert( err == 0 ); - params.RCType = RCType; - - int AvgBitrate; - err = NVGetParamValue(encoder_, NVVE_AVG_BITRATE, &AvgBitrate); - CV_Assert( err == 0 ); - params.AvgBitrate = AvgBitrate; - - int PeakBitrate; - err = NVGetParamValue(encoder_, NVVE_PEAK_BITRATE, &PeakBitrate); - CV_Assert( err == 0 ); - params.PeakBitrate = PeakBitrate; - - int QP_Level_Intra; - err = NVGetParamValue(encoder_, NVVE_QP_LEVEL_INTRA, &QP_Level_Intra); - CV_Assert( err == 0 ); - params.QP_Level_Intra = QP_Level_Intra; - - int QP_Level_InterP; - err = NVGetParamValue(encoder_, NVVE_QP_LEVEL_INTER_P, &QP_Level_InterP); - CV_Assert( err == 0 ); - params.QP_Level_InterP = QP_Level_InterP; - - int QP_Level_InterB; - err = NVGetParamValue(encoder_, NVVE_QP_LEVEL_INTER_B, &QP_Level_InterB); - CV_Assert( err == 0 ); - params.QP_Level_InterB = QP_Level_InterB; - - int DeblockMode; - err = NVGetParamValue(encoder_, NVVE_DEBLOCK_MODE, &DeblockMode); - CV_Assert( err == 0 ); - params.DeblockMode = DeblockMode; - - int ProfileLevel; - err = NVGetParamValue(encoder_, NVVE_PROFILE_LEVEL, &ProfileLevel); - CV_Assert( err == 0 ); - params.ProfileLevel = ProfileLevel; - - int ForceIntra; - err = NVGetParamValue(encoder_, NVVE_FORCE_INTRA, &ForceIntra); - CV_Assert( err == 0 ); - params.ForceIntra = ForceIntra; - - int ForceIDR; - err = NVGetParamValue(encoder_, NVVE_FORCE_IDR, &ForceIDR); - CV_Assert( err == 0 ); - params.ForceIDR = ForceIDR; - - int ClearStat; - err = NVGetParamValue(encoder_, NVVE_CLEAR_STAT, &ClearStat); - CV_Assert( err == 0 ); - params.ClearStat = ClearStat; - - NVVE_DI_MODE DIMode; - err = NVGetParamValue(encoder_, NVVE_SET_DEINTERLACE, &DIMode); - CV_Assert( err == 0 ); - params.DIMode = DIMode; - - params.Presets = -1; - - int DisableCabac; - err = NVGetParamValue(encoder_, NVVE_DISABLE_CABAC, &DisableCabac); - CV_Assert ( err == 0 ); - params.DisableCabac = DisableCabac; - - int NaluFramingType; - err = NVGetParamValue(encoder_, NVVE_CONFIGURE_NALU_FRAMING_TYPE, &NaluFramingType); - CV_Assert ( err == 0 ); - params.NaluFramingType = NaluFramingType; - - int DisableSPSPPS; - err = NVGetParamValue(encoder_, NVVE_DISABLE_SPS_PPS, &DisableSPSPPS); - CV_Assert ( err == 0 ); - params.DisableSPSPPS = DisableSPSPPS; - - return params; -} - -void cv::gpu::VideoWriter_GPU::Impl::initGpuMemory() -{ - int err; - CUresult cuRes; - - // initialize context - cv::gpu::GpuMat temp(1, 1, CV_8U); - temp.release(); - - static const int bpp[] = - { - 16, // UYVY, 4:2:2 - 16, // YUY2, 4:2:2 - 12, // YV12, 4:2:0 - 12, // NV12, 4:2:0 - 12, // IYUV, 4:2:0 + static unsigned char* NVENCAPI HandleAcquireBitStream(int* pBufferSize, void* pUserdata); + static void NVENCAPI HandleReleaseBitStream(int nBytesInBuffer, unsigned char* cb, void* pUserdata); + static void NVENCAPI HandleOnBeginFrame(const NVVE_BeginFrameInfo* pbfi, void* pUserdata); + static void NVENCAPI HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata); }; - CUcontext cuContext; - cuRes = cuCtxGetCurrent(&cuContext); - CV_Assert( cuRes == CUDA_SUCCESS ); + VideoWriterImpl::VideoWriterImpl(const Ptr& callback, Size frameSize, double fps, SurfaceFormat format, CodecType codec) : + callback_(callback), + frameSize_(frameSize), + codec_(codec), + inputFormat_(format), + cuCtxLock_(0) + { + surfaceFormat_ = (inputFormat_ == SF_BGR ? YV12 : static_cast(inputFormat_)); - // Allocate the CUDA memory Pitched Surface - if (surfaceFormat_ == UYVY || surfaceFormat_ == YUY2) - videoFrame_.create(frameSize_.height, (frameSize_.width * bpp[surfaceFormat_]) / 8, CV_8UC1); - else - videoFrame_.create((frameSize_.height * bpp[surfaceFormat_]) / 8, frameSize_.width, CV_8UC1); + initEncoder(fps); - // Create the Video Context Lock (used for synchronization) - cuRes = cuvidCtxLockCreate(&cuCtxLock_, cuContext); - CV_Assert( cuRes == CUDA_SUCCESS ); + initGpuMemory(); - // 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 + initCallBacks(); - int iUseDeviceMem = 1; - err = NVSetParamValue(encoder_, NVVE_DEVICE_MEMORY_INPUT, &iUseDeviceMem); - CV_Assert ( err == 0 ); + createHWEncoder(); + } - err = NVSetParamValue(encoder_, NVVE_DEVICE_CTX_LOCK, &cuCtxLock_); - CV_Assert ( err == 0 ); -} + VideoWriterImpl::VideoWriterImpl(const Ptr& callback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec) : + callback_(callback), + frameSize_(frameSize), + codec_(codec), + inputFormat_(format), + cuCtxLock_(0) + { + surfaceFormat_ = (inputFormat_ == SF_BGR ? YV12 : static_cast(inputFormat_)); -void cv::gpu::VideoWriter_GPU::Impl::initCallBacks() -{ - NVVE_CallbackParams cb; - memset(&cb, 0, sizeof(NVVE_CallbackParams)); + initEncoder(fps); - cb.pfnacquirebitstream = HandleAcquireBitStream; - cb.pfnonbeginframe = HandleOnBeginFrame; - cb.pfnonendframe = HandleOnEndFrame; - cb.pfnreleasebitstream = HandleReleaseBitStream; + setEncodeParams(params); - NVRegisterCB(encoder_, cb, this); -} + initGpuMemory(); -void cv::gpu::VideoWriter_GPU::Impl::createHWEncoder() -{ - int err; + initCallBacks(); - // Create the NVIDIA HW resources for Encoding on NVIDIA hardware - err = NVCreateHWEncoder(encoder_); - CV_Assert( err == 0 ); -} + createHWEncoder(); + } + + void VideoWriterImpl::initEncoder(double fps) + { + int err; + + // Set codec + + static const unsigned long codecs_id[] = + { + NV_CODEC_TYPE_MPEG1, NV_CODEC_TYPE_MPEG2, NV_CODEC_TYPE_MPEG4, NV_CODEC_TYPE_H264, NV_CODEC_TYPE_VC1 + }; + err = NVSetCodec(encoder_, codecs_id[codec_]); + if (err) + CV_Error(Error::StsNotImplemented, "Codec format is not supported"); + + // Set default params + + err = NVSetDefaultParam(encoder_); + CV_Assert( err == 0 ); + + // Set some common params + + int inputSize[] = { frameSize_.width, frameSize_.height }; + err = NVSetParamValue(encoder_, NVVE_IN_SIZE, &inputSize); + CV_Assert( err == 0 ); + err = NVSetParamValue(encoder_, NVVE_OUT_SIZE, &inputSize); + CV_Assert( err == 0 ); + + int aspectRatio[] = { frameSize_.width, frameSize_.height, ASPECT_RATIO_DAR }; + err = NVSetParamValue(encoder_, NVVE_ASPECT_RATIO, &aspectRatio); + CV_Assert( err == 0 ); + + // FPS + + int frame_rate = static_cast(fps + 0.5); + int frame_rate_base = 1; + while (fabs(static_cast(frame_rate) / frame_rate_base) - fps > 0.001) + { + frame_rate_base *= 10; + frame_rate = static_cast(fps*frame_rate_base + 0.5); + } + int FrameRate[] = { frame_rate, frame_rate_base }; + err = NVSetParamValue(encoder_, NVVE_FRAME_RATE, &FrameRate); + CV_Assert( err == 0 ); + + // Select device for encoding + + int gpuID = getDevice(); + err = NVSetParamValue(encoder_, NVVE_FORCE_GPU_SELECTION, &gpuID); + CV_Assert( err == 0 ); + } + + void VideoWriterImpl::setEncodeParams(const EncoderParams& params) + { + int err; + + int P_Interval = params.P_Interval; + err = NVSetParamValue(encoder_, NVVE_P_INTERVAL, &P_Interval); + CV_Assert( err == 0 ); + + int IDR_Period = params.IDR_Period; + err = NVSetParamValue(encoder_, NVVE_IDR_PERIOD, &IDR_Period); + CV_Assert( err == 0 ); + + int DynamicGOP = params.DynamicGOP; + err = NVSetParamValue(encoder_, NVVE_DYNAMIC_GOP, &DynamicGOP); + CV_Assert( err == 0 ); + + NVVE_RateCtrlType RCType = static_cast(params.RCType); + err = NVSetParamValue(encoder_, NVVE_RC_TYPE, &RCType); + CV_Assert( err == 0 ); + + int AvgBitrate = params.AvgBitrate; + err = NVSetParamValue(encoder_, NVVE_AVG_BITRATE, &AvgBitrate); + CV_Assert( err == 0 ); + + int PeakBitrate = params.PeakBitrate; + err = NVSetParamValue(encoder_, NVVE_PEAK_BITRATE, &PeakBitrate); + CV_Assert( err == 0 ); + + int QP_Level_Intra = params.QP_Level_Intra; + err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTRA, &QP_Level_Intra); + CV_Assert( err == 0 ); + + int QP_Level_InterP = params.QP_Level_InterP; + err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTER_P, &QP_Level_InterP); + CV_Assert( err == 0 ); + + int QP_Level_InterB = params.QP_Level_InterB; + err = NVSetParamValue(encoder_, NVVE_QP_LEVEL_INTER_B, &QP_Level_InterB); + CV_Assert( err == 0 ); + + int DeblockMode = params.DeblockMode; + err = NVSetParamValue(encoder_, NVVE_DEBLOCK_MODE, &DeblockMode); + CV_Assert( err == 0 ); + + int ProfileLevel = params.ProfileLevel; + err = NVSetParamValue(encoder_, NVVE_PROFILE_LEVEL, &ProfileLevel); + CV_Assert( err == 0 ); + + int ForceIntra = params.ForceIntra; + err = NVSetParamValue(encoder_, NVVE_FORCE_INTRA, &ForceIntra); + CV_Assert( err == 0 ); + + int ForceIDR = params.ForceIDR; + err = NVSetParamValue(encoder_, NVVE_FORCE_IDR, &ForceIDR); + CV_Assert( err == 0 ); + + int ClearStat = params.ClearStat; + err = NVSetParamValue(encoder_, NVVE_CLEAR_STAT, &ClearStat); + CV_Assert( err == 0 ); + + NVVE_DI_MODE DIMode = static_cast(params.DIMode); + err = NVSetParamValue(encoder_, NVVE_SET_DEINTERLACE, &DIMode); + CV_Assert( err == 0 ); + + if (params.Presets != -1) + { + NVVE_PRESETS_TARGET Presets = static_cast(params.Presets); + err = NVSetParamValue(encoder_, NVVE_PRESETS, &Presets); + CV_Assert( err == 0 ); + } + + int DisableCabac = params.DisableCabac; + err = NVSetParamValue(encoder_, NVVE_DISABLE_CABAC, &DisableCabac); + CV_Assert( err == 0 ); + + int NaluFramingType = params.NaluFramingType; + err = NVSetParamValue(encoder_, NVVE_CONFIGURE_NALU_FRAMING_TYPE, &NaluFramingType); + CV_Assert( err == 0 ); + + int DisableSPSPPS = params.DisableSPSPPS; + err = NVSetParamValue(encoder_, NVVE_DISABLE_SPS_PPS, &DisableSPSPPS); + CV_Assert( err == 0 ); + } + + EncoderParams VideoWriterImpl::getEncoderParams() const + { + int err; + + EncoderParams params; + + int P_Interval; + err = NVGetParamValue(encoder_, NVVE_P_INTERVAL, &P_Interval); + CV_Assert( err == 0 ); + params.P_Interval = P_Interval; + + int IDR_Period; + err = NVGetParamValue(encoder_, NVVE_IDR_PERIOD, &IDR_Period); + CV_Assert( err == 0 ); + params.IDR_Period = IDR_Period; + + int DynamicGOP; + err = NVGetParamValue(encoder_, NVVE_DYNAMIC_GOP, &DynamicGOP); + CV_Assert( err == 0 ); + params.DynamicGOP = DynamicGOP; + + NVVE_RateCtrlType RCType; + err = NVGetParamValue(encoder_, NVVE_RC_TYPE, &RCType); + CV_Assert( err == 0 ); + params.RCType = RCType; + + int AvgBitrate; + err = NVGetParamValue(encoder_, NVVE_AVG_BITRATE, &AvgBitrate); + CV_Assert( err == 0 ); + params.AvgBitrate = AvgBitrate; + + int PeakBitrate; + err = NVGetParamValue(encoder_, NVVE_PEAK_BITRATE, &PeakBitrate); + CV_Assert( err == 0 ); + params.PeakBitrate = PeakBitrate; + + int QP_Level_Intra; + err = NVGetParamValue(encoder_, NVVE_QP_LEVEL_INTRA, &QP_Level_Intra); + CV_Assert( err == 0 ); + params.QP_Level_Intra = QP_Level_Intra; + + int QP_Level_InterP; + err = NVGetParamValue(encoder_, NVVE_QP_LEVEL_INTER_P, &QP_Level_InterP); + CV_Assert( err == 0 ); + params.QP_Level_InterP = QP_Level_InterP; + + int QP_Level_InterB; + err = NVGetParamValue(encoder_, NVVE_QP_LEVEL_INTER_B, &QP_Level_InterB); + CV_Assert( err == 0 ); + params.QP_Level_InterB = QP_Level_InterB; + + int DeblockMode; + err = NVGetParamValue(encoder_, NVVE_DEBLOCK_MODE, &DeblockMode); + CV_Assert( err == 0 ); + params.DeblockMode = DeblockMode; + + int ProfileLevel; + err = NVGetParamValue(encoder_, NVVE_PROFILE_LEVEL, &ProfileLevel); + CV_Assert( err == 0 ); + params.ProfileLevel = ProfileLevel; + + int ForceIntra; + err = NVGetParamValue(encoder_, NVVE_FORCE_INTRA, &ForceIntra); + CV_Assert( err == 0 ); + params.ForceIntra = ForceIntra; + + int ForceIDR; + err = NVGetParamValue(encoder_, NVVE_FORCE_IDR, &ForceIDR); + CV_Assert( err == 0 ); + params.ForceIDR = ForceIDR; + + int ClearStat; + err = NVGetParamValue(encoder_, NVVE_CLEAR_STAT, &ClearStat); + CV_Assert( err == 0 ); + params.ClearStat = ClearStat; + + NVVE_DI_MODE DIMode; + err = NVGetParamValue(encoder_, NVVE_SET_DEINTERLACE, &DIMode); + CV_Assert( err == 0 ); + params.DIMode = DIMode; + + params.Presets = -1; + + int DisableCabac; + err = NVGetParamValue(encoder_, NVVE_DISABLE_CABAC, &DisableCabac); + CV_Assert( err == 0 ); + params.DisableCabac = DisableCabac; + + int NaluFramingType; + err = NVGetParamValue(encoder_, NVVE_CONFIGURE_NALU_FRAMING_TYPE, &NaluFramingType); + CV_Assert( err == 0 ); + params.NaluFramingType = NaluFramingType; + + int DisableSPSPPS; + err = NVGetParamValue(encoder_, NVVE_DISABLE_SPS_PPS, &DisableSPSPPS); + CV_Assert( err == 0 ); + params.DisableSPSPPS = DisableSPSPPS; + + return params; + } + + void VideoWriterImpl::initGpuMemory() + { + int err; + + // initialize context + GpuMat temp(1, 1, CV_8U); + temp.release(); + + static const int bpp[] = + { + 16, // UYVY, 4:2:2 + 16, // YUY2, 4:2:2 + 12, // YV12, 4:2:0 + 12, // NV12, 4:2:0 + 12, // IYUV, 4:2:0 + }; + + CUcontext cuContext; + cuSafeCall( cuCtxGetCurrent(&cuContext) ); + + // Allocate the CUDA memory Pitched Surface + if (surfaceFormat_ == UYVY || surfaceFormat_ == YUY2) + videoFrame_.create(frameSize_.height, (frameSize_.width * bpp[surfaceFormat_]) / 8, CV_8UC1); + else + videoFrame_.create((frameSize_.height * bpp[surfaceFormat_]) / 8, frameSize_.width, CV_8UC1); + + // Create the Video Context Lock (used for synchronization) + cuSafeCall( cuvidCtxLockCreate(&cuCtxLock_, cuContext) ); + + // 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 + + int iUseDeviceMem = 1; + err = NVSetParamValue(encoder_, NVVE_DEVICE_MEMORY_INPUT, &iUseDeviceMem); + CV_Assert( err == 0 ); + + err = NVSetParamValue(encoder_, NVVE_DEVICE_CTX_LOCK, &cuCtxLock_); + CV_Assert( err == 0 ); + } + + void VideoWriterImpl::initCallBacks() + { + NVVE_CallbackParams cb; + memset(&cb, 0, sizeof(NVVE_CallbackParams)); + + cb.pfnacquirebitstream = HandleAcquireBitStream; + cb.pfnonbeginframe = HandleOnBeginFrame; + cb.pfnonendframe = HandleOnEndFrame; + cb.pfnreleasebitstream = HandleReleaseBitStream; + + NVRegisterCB(encoder_, cb, this); + } + + void VideoWriterImpl::createHWEncoder() + { + int err; + + // Create the NVIDIA HW resources for Encoding on NVIDIA hardware + err = NVCreateHWEncoder(encoder_); + CV_Assert( err == 0 ); + } -namespace -{ // UYVY/YUY2 are both 4:2:2 formats (16bpc) // 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 // YUV Copy setup CUDA_MEMCPY2D stCopyYUV422; - memset((void*)&stCopyYUV422, 0, sizeof(stCopyYUV422)); + memset(&stCopyYUV422, 0, sizeof(CUDA_MEMCPY2D)); + stCopyYUV422.srcXInBytes = 0; stCopyYUV422.srcY = 0; stCopyYUV422.srcMemoryType = CU_MEMORYTYPE_DEVICE; @@ -527,21 +514,19 @@ namespace stCopyYUV422.Height = frameSize.height; // DMA Luma/Chroma - res = cuMemcpy2D(&stCopyYUV422); - CV_Assert( res == CUDA_SUCCESS ); + cuSafeCall( cuMemcpy2D(&stCopyYUV422) ); } // YV12/IYUV are both 4:2:0 planar formats (12bpc) // 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 // (1) luma copy setup CUDA_MEMCPY2D stCopyLuma; - memset((void*)&stCopyLuma, 0, sizeof(stCopyLuma)); + memset(&stCopyLuma, 0, sizeof(CUDA_MEMCPY2D)); + stCopyLuma.srcXInBytes = 0; stCopyLuma.srcY = 0; stCopyLuma.srcMemoryType = CU_MEMORYTYPE_DEVICE; @@ -563,7 +548,8 @@ namespace // (2) chroma copy setup, U/V can be done together CUDA_MEMCPY2D stCopyChroma; - memset((void*)&stCopyChroma, 0, sizeof(stCopyChroma)); + memset(&stCopyChroma, 0, sizeof(CUDA_MEMCPY2D)); + stCopyChroma.srcXInBytes = 0; stCopyChroma.srcY = frameSize.height << 1; // U/V chroma offset stCopyChroma.srcMemoryType = CU_MEMORYTYPE_DEVICE; @@ -584,26 +570,23 @@ namespace stCopyChroma.Height = frameSize.height; // U/V are sent together // DMA Luma - res = cuMemcpy2D(&stCopyLuma); - CV_Assert( res == CUDA_SUCCESS ); + cuSafeCall( cuMemcpy2D(&stCopyLuma) ); // DMA Chroma channels (UV side by side) - res = cuMemcpy2D(&stCopyChroma); - CV_Assert( res == CUDA_SUCCESS ); + cuSafeCall( cuMemcpy2D(&stCopyChroma) ); } // NV12 is 4:2:0 format (12bpc) // 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 // 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 CUDA_MEMCPY2D stCopyNV12; - memset((void*)&stCopyNV12, 0, sizeof(stCopyNV12)); + memset(&stCopyNV12, 0, sizeof(CUDA_MEMCPY2D)); + stCopyNV12.srcXInBytes = 0; stCopyNV12.srcY = 0; stCopyNV12.srcMemoryType = CU_MEMORYTYPE_DEVICE; @@ -621,141 +604,137 @@ namespace stCopyNV12.dstPitch = dst.step; stCopyNV12.WidthInBytes = frameSize.width; - stCopyNV12.Height =(frameSize.height * 3) >> 1; + stCopyNV12.Height = (frameSize.height * 3) >> 1; // DMA Luma/Chroma - res = cuMemcpy2D(&stCopyNV12); - CV_Assert( res == CUDA_SUCCESS ); - } -} - -namespace cv { namespace gpu { namespace cudev -{ - void RGB_to_YV12(const PtrStepSzb src, int cn, PtrStepSzb dst, cudaStream_t stream = 0); -}}} - -void cv::gpu::VideoWriter_GPU::Impl::write(const cv::gpu::GpuMat& frame, bool lastFrame) -{ - if (inputFormat_ == SF_BGR) - { - CV_Assert( frame.size() == frameSize_ ); - CV_Assert( frame.type() == CV_8UC1 || frame.type() == CV_8UC3 || frame.type() == CV_8UC4 ); - } - else - { - CV_Assert( frame.size() == videoFrame_.size() ); - CV_Assert( frame.type() == videoFrame_.type() ); + cuSafeCall( cuMemcpy2D(&stCopyNV12) ); } - NVVE_EncodeFrameParams efparams; - efparams.Width = frameSize_.width; - efparams.Height = frameSize_.height; - efparams.Pitch = static_cast(videoFrame_.step); - efparams.SurfFmt = surfaceFormat_; - efparams.PictureStruc = FRAME_PICTURE; - efparams.topfieldfirst = 0; - efparams.repeatFirstField = 0; - efparams.progressiveFrame = (surfaceFormat_ == NV12) ? 1 : 0; - efparams.bLast = lastFrame; - 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 - CUresult res = cuvidCtxLock(cuCtxLock_, 0); - CV_Assert( res == CUDA_SUCCESS ); - - if (inputFormat_ == SF_BGR) - cv::gpu::cudev::RGB_to_YV12(frame, frame.channels(), videoFrame_); - else + void VideoWriterImpl::write(InputArray _frame, bool lastFrame) { - switch (surfaceFormat_) + GpuMat frame = _frame.getGpuMat(); + + if (inputFormat_ == SF_BGR) { - case UYVY: // UYVY (4:2:2) - case YUY2: // YUY2 (4:2:2) - copyUYVYorYUY2Frame(frameSize_, frame, videoFrame_); - break; - - case YV12: // YV12 (4:2:0), Y V U - case IYUV: // IYUV (4:2:0), Y U V - copyYV12orIYUVFrame(frameSize_, frame, videoFrame_); - break; - - case NV12: // NV12 (4:2:0) - copyNV12Frame(frameSize_, frame, videoFrame_); - break; + CV_Assert( frame.size() == frameSize_ ); + CV_Assert( frame.type() == CV_8UC1 || frame.type() == CV_8UC3 || frame.type() == CV_8UC4 ); } + else + { + CV_Assert( frame.size() == videoFrame_.size() ); + CV_Assert( frame.type() == videoFrame_.type() ); + } + + NVVE_EncodeFrameParams efparams; + efparams.Width = frameSize_.width; + efparams.Height = frameSize_.height; + efparams.Pitch = static_cast(videoFrame_.step); + efparams.SurfFmt = surfaceFormat_; + efparams.PictureStruc = FRAME_PICTURE; + efparams.topfieldfirst = 0; + efparams.repeatFirstField = 0; + efparams.progressiveFrame = (surfaceFormat_ == NV12) ? 1 : 0; + efparams.bLast = lastFrame; + 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 + cuSafeCall( cuvidCtxLock(cuCtxLock_, 0) ); + + if (inputFormat_ == SF_BGR) + { + cudev::RGB_to_YV12(frame, frame.channels(), videoFrame_); + } + else + { + switch (surfaceFormat_) + { + case UYVY: // UYVY (4:2:2) + case YUY2: // YUY2 (4:2:2) + copyUYVYorYUY2Frame(frameSize_, frame, videoFrame_); + break; + + case YV12: // YV12 (4:2:0), Y V U + case IYUV: // IYUV (4:2:0), Y U V + copyYV12orIYUVFrame(frameSize_, frame, videoFrame_); + break; + + case NV12: // NV12 (4:2:0) + copyNV12Frame(frameSize_, frame, videoFrame_); + break; + } + } + + cuSafeCall( cuvidCtxUnlock(cuCtxLock_, 0) ); + + int err = NVEncodeFrame(encoder_, &efparams, 0, videoFrame_.data); + CV_Assert( err == 0 ); } - res = cuvidCtxUnlock(cuCtxLock_, 0); - CV_Assert( res == CUDA_SUCCESS ); - - int err = NVEncodeFrame(encoder_, &efparams, 0, videoFrame_.data); - CV_Assert( err == 0 ); -} - -unsigned char* NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleAcquireBitStream(int* pBufferSize, void* pUserdata) -{ - Impl* thiz = static_cast(pUserdata); - - return thiz->callback_->acquireBitStream(pBufferSize); -} - -void NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleReleaseBitStream(int nBytesInBuffer, unsigned char* cb, void* pUserdata) -{ - Impl* thiz = static_cast(pUserdata); - - thiz->callback_->releaseBitStream(cb, nBytesInBuffer); -} - -void NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleOnBeginFrame(const NVVE_BeginFrameInfo* pbfi, void* pUserdata) -{ - Impl* thiz = static_cast(pUserdata); - - thiz->callback_->onBeginFrame(pbfi->nFrameNumber, static_cast(pbfi->nPicType)); -} - -void NVENCAPI cv::gpu::VideoWriter_GPU::Impl::HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata) -{ - Impl* thiz = static_cast(pUserdata); - - thiz->callback_->onEndFrame(pefi->nFrameNumber, static_cast(pefi->nPicType)); -} - -/////////////////////////////////////////////////////////////////////////// -// FFMPEG - -class EncoderCallBackFFMPEG : public cv::gpu::VideoWriter_GPU::EncoderCallBack -{ -public: - EncoderCallBackFFMPEG(const cv::String& fileName, cv::Size frameSize, double fps); - ~EncoderCallBackFFMPEG(); - - unsigned char* acquireBitStream(int* bufferSize); - void releaseBitStream(unsigned char* data, int size); - void onBeginFrame(int frameNumber, PicType picType); - void onEndFrame(int frameNumber, PicType picType); - -private: - EncoderCallBackFFMPEG(const EncoderCallBackFFMPEG&); - EncoderCallBackFFMPEG& operator=(const EncoderCallBackFFMPEG&); - - struct OutputMediaStream_FFMPEG* stream_; - std::vector buf_; - bool isKeyFrame_; -}; - -namespace -{ - Create_OutputMediaStream_FFMPEG_Plugin create_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() + unsigned char* NVENCAPI VideoWriterImpl::HandleAcquireBitStream(int* pBufferSize, void* pUserdata) { - static bool initialized = 0; + VideoWriterImpl* thiz = static_cast(pUserdata); + + return thiz->callback_->acquireBitStream(pBufferSize); + } + + void NVENCAPI VideoWriterImpl::HandleReleaseBitStream(int nBytesInBuffer, unsigned char* cb, void* pUserdata) + { + VideoWriterImpl* thiz = static_cast(pUserdata); + + thiz->callback_->releaseBitStream(cb, nBytesInBuffer); + } + + void NVENCAPI VideoWriterImpl::HandleOnBeginFrame(const NVVE_BeginFrameInfo* pbfi, void* pUserdata) + { + VideoWriterImpl* thiz = static_cast(pUserdata); + + thiz->callback_->onBeginFrame(pbfi->nFrameNumber, static_cast(pbfi->nPicType)); + } + + void NVENCAPI VideoWriterImpl::HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata) + { + VideoWriterImpl* thiz = static_cast(pUserdata); + + thiz->callback_->onEndFrame(pefi->nFrameNumber, static_cast(pefi->nPicType)); + } + + /////////////////////////////////////////////////////////////////////////// + // FFMPEG + + class EncoderCallBackFFMPEG : public EncoderCallBack + { + public: + EncoderCallBackFFMPEG(const String& fileName, Size frameSize, double fps); + ~EncoderCallBackFFMPEG(); + + unsigned char* acquireBitStream(int* bufferSize); + void releaseBitStream(unsigned char* data, int size); + void onBeginFrame(int frameNumber, PicType picType); + void onEndFrame(int frameNumber, PicType picType); + + private: + static bool init_MediaStream_FFMPEG(); + + struct OutputMediaStream_FFMPEG* stream_; + std::vector buf_; + 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; + }; + + Create_OutputMediaStream_FFMPEG_Plugin EncoderCallBackFFMPEG::create_OutputMediaStream_FFMPEG_p = 0; + Release_OutputMediaStream_FFMPEG_Plugin EncoderCallBackFFMPEG::release_OutputMediaStream_FFMPEG_p = 0; + Write_OutputMediaStream_FFMPEG_Plugin EncoderCallBackFFMPEG::write_OutputMediaStream_FFMPEG_p = 0; + + bool EncoderCallBackFFMPEG::init_MediaStream_FFMPEG() + { + static bool initialized = false; if (!initialized) { - #if defined WIN32 || defined _WIN32 + #if defined(WIN32) || defined(_WIN32) const char* module_name = "opencv_ffmpeg" 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__) @@ -776,7 +755,7 @@ namespace 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; release_OutputMediaStream_FFMPEG_p = release_OutputMediaStream_FFMPEG; write_OutputMediaStream_FFMPEG_p = write_OutputMediaStream_FFMPEG; @@ -787,134 +766,52 @@ namespace return initialized; } -} -EncoderCallBackFFMPEG::EncoderCallBackFFMPEG(const cv::String& fileName, cv::Size frameSize, double fps) : - stream_(0), isKeyFrame_(false) -{ - int buf_size = std::max(frameSize.area() * 4, 1024 * 1024); - buf_.resize(buf_size); + EncoderCallBackFFMPEG::EncoderCallBackFFMPEG(const String& fileName, Size frameSize, double fps) : + stream_(0), isKeyFrame_(false) + { + int buf_size = std::max(frameSize.area() * 4, 1024 * 1024); + buf_.resize(buf_size); - CV_Assert( init_MediaStream_FFMPEG() ); + CV_Assert( init_MediaStream_FFMPEG() ); - stream_ = create_OutputMediaStream_FFMPEG_p(fileName.c_str(), frameSize.width, frameSize.height, fps); - CV_Assert( stream_ != 0 ); -} + stream_ = create_OutputMediaStream_FFMPEG_p(fileName.c_str(), frameSize.width, frameSize.height, fps); + CV_Assert( stream_ != 0 ); + } -EncoderCallBackFFMPEG::~EncoderCallBackFFMPEG() -{ - release_OutputMediaStream_FFMPEG_p(stream_); -} + EncoderCallBackFFMPEG::~EncoderCallBackFFMPEG() + { + release_OutputMediaStream_FFMPEG_p(stream_); + } -unsigned char* EncoderCallBackFFMPEG::acquireBitStream(int* bufferSize) -{ - *bufferSize = static_cast(buf_.size()); - return &buf_[0]; -} + unsigned char* EncoderCallBackFFMPEG::acquireBitStream(int* bufferSize) + { + *bufferSize = static_cast(buf_.size()); + return &buf_[0]; + } -void EncoderCallBackFFMPEG::releaseBitStream(unsigned char* data, int size) -{ - write_OutputMediaStream_FFMPEG_p(stream_, data, size, isKeyFrame_); -} + void EncoderCallBackFFMPEG::releaseBitStream(unsigned char* data, int size) + { + write_OutputMediaStream_FFMPEG_p(stream_, data, size, isKeyFrame_); + } -void EncoderCallBackFFMPEG::onBeginFrame(int frameNumber, PicType picType) -{ - (void) frameNumber; - isKeyFrame_ = picType == IFRAME; -} + void EncoderCallBackFFMPEG::onBeginFrame(int frameNumber, PicType picType) + { + (void) frameNumber; + isKeyFrame_ = (picType == IFRAME); + } -void EncoderCallBackFFMPEG::onEndFrame(int frameNumber, PicType picType) -{ - (void) frameNumber; - (void) picType; + void EncoderCallBackFFMPEG::onEndFrame(int frameNumber, PicType picType) + { + (void) frameNumber; + (void) picType; + } } /////////////////////////////////////////////////////////////////////////// -// VideoWriter_GPU +// EncoderParams -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, cv::Size frameSize, double fps, SurfaceFormat format) -{ - open(encoderCallback, frameSize, fps, format); -} - -cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr& 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(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(new EncoderCallBackFFMPEG(fileName, frameSize, fps)); - open(encoderCallback, frameSize, fps, params, format); -} - -void cv::gpu::VideoWriter_GPU::open(const cv::Ptr& 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, 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 - -cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams() +cv::gpucodec::EncoderParams::EncoderParams() { P_Interval = 3; IDR_Period = 15; @@ -937,66 +834,86 @@ cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams() DisableSPSPPS = 0; } -cv::gpu::VideoWriter_GPU::EncoderParams::EncoderParams(const String& configFile) +cv::gpucodec::EncoderParams::EncoderParams(const String& 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::read(fs["P_Interval" ], P_Interval, 3); - cv::read(fs["IDR_Period" ], IDR_Period, 15); - cv::read(fs["DynamicGOP" ], DynamicGOP, 0); - cv::read(fs["RCType" ], RCType, 1); - cv::read(fs["AvgBitrate" ], AvgBitrate, 4000000); - cv::read(fs["PeakBitrate" ], PeakBitrate, 10000000); - cv::read(fs["QP_Level_Intra" ], QP_Level_Intra, 25); - cv::read(fs["QP_Level_InterP"], QP_Level_InterP, 28); - cv::read(fs["QP_Level_InterB"], QP_Level_InterB, 31); - cv::read(fs["DeblockMode" ], DeblockMode, 1); - cv::read(fs["ProfileLevel" ], ProfileLevel, 65357); - cv::read(fs["ForceIntra" ], ForceIntra, 0); - cv::read(fs["ForceIDR" ], ForceIDR, 0); - cv::read(fs["ClearStat" ], ClearStat, 0); - cv::read(fs["DIMode" ], DIMode, 1); - cv::read(fs["Presets" ], Presets, 2); - cv::read(fs["DisableCabac" ], DisableCabac, 0); - cv::read(fs["NaluFramingType"], NaluFramingType, 0); - cv::read(fs["DisableSPSPPS" ], DisableSPSPPS, 0); + read(fs["P_Interval" ], P_Interval, 3); + read(fs["IDR_Period" ], IDR_Period, 15); + read(fs["DynamicGOP" ], DynamicGOP, 0); + read(fs["RCType" ], RCType, 1); + read(fs["AvgBitrate" ], AvgBitrate, 4000000); + read(fs["PeakBitrate" ], PeakBitrate, 10000000); + read(fs["QP_Level_Intra" ], QP_Level_Intra, 25); + read(fs["QP_Level_InterP"], QP_Level_InterP, 28); + read(fs["QP_Level_InterB"], QP_Level_InterB, 31); + read(fs["DeblockMode" ], DeblockMode, 1); + read(fs["ProfileLevel" ], ProfileLevel, 65357); + read(fs["ForceIntra" ], ForceIntra, 0); + read(fs["ForceIDR" ], ForceIDR, 0); + read(fs["ClearStat" ], ClearStat, 0); + read(fs["DIMode" ], DIMode, 1); + read(fs["Presets" ], Presets, 2); + read(fs["DisableCabac" ], DisableCabac, 0); + read(fs["NaluFramingType"], NaluFramingType, 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::write(fs, "P_Interval" , P_Interval); - cv::write(fs, "IDR_Period" , IDR_Period); - cv::write(fs, "DynamicGOP" , DynamicGOP); - cv::write(fs, "RCType" , RCType); - cv::write(fs, "AvgBitrate" , AvgBitrate); - cv::write(fs, "PeakBitrate" , PeakBitrate); - cv::write(fs, "QP_Level_Intra" , QP_Level_Intra); - cv::write(fs, "QP_Level_InterP", QP_Level_InterP); - cv::write(fs, "QP_Level_InterB", QP_Level_InterB); - cv::write(fs, "DeblockMode" , DeblockMode); - cv::write(fs, "ProfileLevel" , ProfileLevel); - cv::write(fs, "ForceIntra" , ForceIntra); - cv::write(fs, "ForceIDR" , ForceIDR); - cv::write(fs, "ClearStat" , ClearStat); - cv::write(fs, "DIMode" , DIMode); - cv::write(fs, "Presets" , Presets); - cv::write(fs, "DisableCabac" , DisableCabac); - cv::write(fs, "NaluFramingType", NaluFramingType); - cv::write(fs, "DisableSPSPPS" , DisableSPSPPS); + write(fs, "P_Interval" , P_Interval); + write(fs, "IDR_Period" , IDR_Period); + write(fs, "DynamicGOP" , DynamicGOP); + write(fs, "RCType" , RCType); + write(fs, "AvgBitrate" , AvgBitrate); + write(fs, "PeakBitrate" , PeakBitrate); + write(fs, "QP_Level_Intra" , QP_Level_Intra); + write(fs, "QP_Level_InterP", QP_Level_InterP); + write(fs, "QP_Level_InterB", QP_Level_InterB); + write(fs, "DeblockMode" , DeblockMode); + write(fs, "ProfileLevel" , ProfileLevel); + write(fs, "ForceIntra" , ForceIntra); + write(fs, "ForceIDR" , ForceIDR); + write(fs, "ClearStat" , ClearStat); + write(fs, "DIMode" , DIMode); + write(fs, "Presets" , Presets); + write(fs, "DisableCabac" , DisableCabac); + write(fs, "NaluFramingType", NaluFramingType); + write(fs, "DisableSPSPPS" , DisableSPSPPS); +} + +/////////////////////////////////////////////////////////////////////////// +// createVideoWriter + +Ptr cv::gpucodec::createVideoWriter(const String& fileName, Size frameSize, double fps, SurfaceFormat format) +{ + Ptr encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps)); + return createVideoWriter(encoderCallback, frameSize, fps, format); +} + +Ptr cv::gpucodec::createVideoWriter(const String& fileName, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format) +{ + Ptr encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps)); + return createVideoWriter(encoderCallback, frameSize, fps, params, format); +} + +Ptr cv::gpucodec::createVideoWriter(const Ptr& encoderCallback, Size frameSize, double fps, SurfaceFormat format) +{ + return new VideoWriterImpl(encoderCallback, frameSize, fps, format); +} + +Ptr cv::gpucodec::createVideoWriter(const Ptr& encoderCallback, Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format) +{ + return new VideoWriterImpl(encoderCallback, frameSize, fps, params, format); } #endif // !defined HAVE_CUDA || !defined WIN32 - -template <> void cv::Ptr::delete_obj() -{ - if (obj) delete obj; -} diff --git a/modules/gpucodec/test/test_video.cpp b/modules/gpucodec/test/test_video.cpp index 55fc3f87c..26bcc02d5 100644 --- a/modules/gpucodec/test/test_video.cpp +++ b/modules/gpucodec/test/test_video.cpp @@ -57,19 +57,15 @@ GPU_TEST_P(Video, Reader) const std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "video/" + GET_PARAM(1); - cv::gpu::VideoReader_GPU reader(inputFile); - ASSERT_TRUE(reader.isOpened()); + cv::Ptr reader = cv::gpucodec::createVideoReader(inputFile); cv::gpu::GpuMat frame; for (int i = 0; i < 10; ++i) { - ASSERT_TRUE(reader.read(frame)); + ASSERT_TRUE(reader->nextFrame(frame)); ASSERT_FALSE(frame.empty()); } - - reader.close(); - ASSERT_FALSE(reader.isOpened()); } ////////////////////////////////////////////////////// @@ -89,7 +85,7 @@ GPU_TEST_P(Video, Writer) cv::VideoCapture reader(inputFile); ASSERT_TRUE(reader.isOpened()); - cv::gpu::VideoWriter_GPU d_writer; + cv::Ptr d_writer; cv::Mat frame; cv::gpu::GpuMat d_frame; @@ -101,14 +97,14 @@ GPU_TEST_P(Video, Writer) d_frame.upload(frame); - if (!d_writer.isOpened()) - d_writer.open(outputFile, frame.size(), FPS); + if (d_writer.empty()) + d_writer = cv::gpucodec::createVideoWriter(outputFile, frame.size(), FPS); - d_writer.write(d_frame); + d_writer->write(d_frame); } reader.release(); - d_writer.close(); + d_writer.release(); reader.open(outputFile); ASSERT_TRUE(reader.isOpened()); diff --git a/modules/superres/src/frame_source.cpp b/modules/superres/src/frame_source.cpp index cba2b14ea..7da817cfa 100644 --- a/modules/superres/src/frame_source.cpp +++ b/modules/superres/src/frame_source.cpp @@ -210,7 +210,7 @@ namespace private: String fileName_; - VideoReader_GPU reader_; + Ptr reader_; GpuMat frame_; }; @@ -223,13 +223,13 @@ namespace { if (_frame.kind() == _InputArray::GPU_MAT) { - bool res = reader_.read(_frame.getGpuMatRef()); + bool res = reader_->nextFrame(_frame.getGpuMatRef()); if (!res) _frame.release(); } else { - bool res = reader_.read(frame_); + bool res = reader_->nextFrame(frame_); if (!res) _frame.release(); else @@ -239,9 +239,7 @@ namespace void VideoFrameSource_GPU::reset() { - reader_.close(); - reader_.open(fileName_); - CV_Assert( reader_.isOpened() ); + reader_ = gpucodec::createVideoReader(fileName_); } } diff --git a/samples/gpu/video_reader.cpp b/samples/gpu/video_reader.cpp index 7eea72639..42f6f91db 100644 --- a/samples/gpu/video_reader.cpp +++ b/samples/gpu/video_reader.cpp @@ -30,8 +30,7 @@ int main(int argc, const char* argv[]) cv::VideoCapture reader(fname); cv::gpu::GpuMat d_frame; - cv::gpu::VideoReader_GPU d_reader(fname); - d_reader.dumpFormat(std::cout); + cv::Ptr d_reader = cv::gpucodec::createVideoReader(fname); cv::TickMeter tm; std::vector cpu_times; @@ -46,7 +45,7 @@ int main(int argc, const char* argv[]) cpu_times.push_back(tm.getTimeMilli()); tm.reset(); tm.start(); - if (!d_reader.read(d_frame)) + if (!d_reader->nextFrame(d_frame)) break; tm.stop(); gpu_times.push_back(tm.getTimeMilli()); diff --git a/samples/gpu/video_writer.cpp b/samples/gpu/video_writer.cpp index d540d0409..c1bcc5d36 100644 --- a/samples/gpu/video_writer.cpp +++ b/samples/gpu/video_writer.cpp @@ -33,7 +33,7 @@ int main(int argc, const char* argv[]) cv::gpu::printShortCudaDeviceInfo(cv::gpu::getDevice()); cv::VideoWriter writer; - cv::gpu::VideoWriter_GPU d_writer; + cv::Ptr d_writer; cv::Mat frame; cv::gpu::GpuMat d_frame; @@ -64,11 +64,11 @@ int main(int argc, const char* argv[]) return -1; } - if (!d_writer.isOpened()) + if (d_writer.empty()) { 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); @@ -81,7 +81,7 @@ int main(int argc, const char* argv[]) cpu_times.push_back(tm.getTimeMilli()); tm.reset(); tm.start(); - d_writer.write(d_frame); + d_writer->write(d_frame); tm.stop(); gpu_times.push_back(tm.getTimeMilli()); }