Commit 53b9880f authored by cudawarped's avatar cudawarped Committed by Alexander Alekhin

Merge pull request #2180 from cudawarped:example_fix_for_cudacodec

OpenCV fix 14774 breaks cudacodec

* Example to describe comilation issue

* Added required changes, builds with -DWITH_FFMPEG=ON|OFF

* Working with standard ffmpeg cap.

* Changed cudacodec to use new retrieveRaw() function, to retrieve the raw encoded bitstream, from the videoio module  instead of its own implementation.

* Fix cv::cudacodec::VideoWriter

* Update to use VideoContainer

* Remove header used in testing

* Remove warning

* remove dependence on redundant ffmpeg codecs

* cudacodec: use .set(CAP_PROP_FORMAT, -1) to extract RAW streams

* whitespace

* addressed alalek's comment
parent 35972a1e
...@@ -59,6 +59,8 @@ ...@@ -59,6 +59,8 @@
namespace cv { namespace cudacodec { namespace cv { namespace cudacodec {
using namespace cuda; // Stream
//! @addtogroup cudacodec //! @addtogroup cudacodec
//! @{ //! @{
...@@ -253,6 +255,7 @@ enum Codec ...@@ -253,6 +255,7 @@ enum Codec
HEVC, HEVC,
VP8, VP8,
VP9, VP9,
NumCodecs,
Uncompressed_YUV420 = (('I'<<24)|('Y'<<16)|('U'<<8)|('V')), //!< Y,U,V (4:2:0) 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_YV12 = (('Y'<<24)|('V'<<16)|('1'<<8)|('2')), //!< Y,V,U (4:2:0)
...@@ -268,7 +271,8 @@ enum ChromaFormat ...@@ -268,7 +271,8 @@ enum ChromaFormat
Monochrome = 0, Monochrome = 0,
YUV420, YUV420,
YUV422, YUV422,
YUV444 YUV444,
NumFormats
}; };
/** @brief Struct providing information about video file format. : /** @brief Struct providing information about video file format. :
...@@ -298,7 +302,7 @@ public: ...@@ -298,7 +302,7 @@ public:
If no frames has been grabbed (there are no more frames in video file), the methods return false . If no frames has been grabbed (there are no more frames in video file), the methods return false .
The method throws Exception if error occurs. The method throws Exception if error occurs.
*/ */
CV_WRAP virtual bool nextFrame(OutputArray frame) = 0; CV_WRAP virtual bool nextFrame(OutputArray frame, Stream &stream = Stream::Null()) = 0;
/** @brief Returns information about video file format. /** @brief Returns information about video file format.
*/ */
...@@ -318,9 +322,8 @@ public: ...@@ -318,9 +322,8 @@ public:
@param data Pointer to frame data. @param data Pointer to frame data.
@param size Size in bytes of current frame. @param size Size in bytes of current frame.
@param endOfFile Indicates that it is end of stream.
*/ */
virtual bool getNextPacket(unsigned char** data, int* size, bool* endOfFile) = 0; virtual bool getNextPacket(unsigned char** data, size_t* size) = 0;
/** @brief Returns information about video file format. /** @brief Returns information about video file format.
*/ */
......
...@@ -46,14 +46,21 @@ ...@@ -46,14 +46,21 @@
namespace opencv_test { namespace { namespace opencv_test { namespace {
#if defined(HAVE_NVCUVID)
#if defined(HAVE_FFMPEG_WRAPPER) // should this be set in preprocessor or in cvconfig.h
#define VIDEO_SRC Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")
#else
// CUDA demuxer has to fall back to ffmpeg to process "gpu/video/768x576.avi"
#define VIDEO_SRC Values( "gpu/video/1920x1080.avi")
#endif
DEF_PARAM_TEST_1(FileName, string); DEF_PARAM_TEST_1(FileName, string);
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
// VideoReader // VideoReader
#if defined(HAVE_NVCUVID) PERF_TEST_P(FileName, VideoReader, VIDEO_SRC)
PERF_TEST_P(FileName, VideoReader, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"))
{ {
declare.time(20); declare.time(20);
...@@ -89,7 +96,7 @@ PERF_TEST_P(FileName, VideoReader, Values("gpu/video/768x576.avi", "gpu/video/19 ...@@ -89,7 +96,7 @@ PERF_TEST_P(FileName, VideoReader, Values("gpu/video/768x576.avi", "gpu/video/19
#if defined(HAVE_NVCUVID) && defined(_WIN32) #if defined(HAVE_NVCUVID) && defined(_WIN32)
PERF_TEST_P(FileName, VideoWriter, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")) PERF_TEST_P(FileName, VideoWriter, VIDEO_SRC)
{ {
declare.time(30); declare.time(30);
......
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
using namespace cv; using namespace cv;
using namespace cv::cudev; using namespace cv::cudev;
void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height); void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height, cudaStream_t stream);
namespace namespace
{ {
...@@ -186,7 +186,7 @@ namespace ...@@ -186,7 +186,7 @@ namespace
} }
} }
void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height) void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height, cudaStream_t stream)
{ {
// Final Stage: NV12toARGB color space conversion // Final Stage: NV12toARGB color space conversion
...@@ -196,11 +196,12 @@ void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, ...@@ -196,11 +196,12 @@ void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame,
dim3 block(32, 8); dim3 block(32, 8);
dim3 grid(divUp(width, 2 * block.x), divUp(height, block.y)); dim3 grid(divUp(width, 2 * block.x), divUp(height, block.y));
NV12_to_RGB<<<grid, block>>>(decodedFrame.ptr<uchar>(), decodedFrame.step, NV12_to_RGB<<<grid, block, 0, stream>>>(decodedFrame.ptr<uchar>(), decodedFrame.step,
outFrame.ptr<uint>(), outFrame.step, outFrame.ptr<uint>(), outFrame.step,
width, height); width, height);
CV_CUDEV_SAFE_CALL( cudaGetLastError() ); CV_CUDEV_SAFE_CALL( cudaGetLastError() );
if (stream == 0)
CV_CUDEV_SAFE_CALL( cudaDeviceSynchronize() ); CV_CUDEV_SAFE_CALL( cudaDeviceSynchronize() );
} }
......
...@@ -68,6 +68,7 @@ cv::cudacodec::detail::CuvidVideoSource::CuvidVideoSource(const String& fname) ...@@ -68,6 +68,7 @@ cv::cudacodec::detail::CuvidVideoSource::CuvidVideoSource(const String& fname)
CUVIDEOFORMAT vidfmt; CUVIDEOFORMAT vidfmt;
cuSafeCall( cuvidGetSourceVideoFormat(videoSource_, &vidfmt, 0) ); cuSafeCall( cuvidGetSourceVideoFormat(videoSource_, &vidfmt, 0) );
CV_Assert(Codec::NumCodecs == cudaVideoCodec::cudaVideoCodec_NumCodecs);
format_.codec = static_cast<Codec>(vidfmt.codec); format_.codec = static_cast<Codec>(vidfmt.codec);
format_.chromaFormat = static_cast<ChromaFormat>(vidfmt.chroma_format); format_.chromaFormat = static_cast<ChromaFormat>(vidfmt.chroma_format);
format_.nBitDepthMinus8 = vidfmt.bit_depth_luma_minus8; format_.nBitDepthMinus8 = vidfmt.bit_depth_luma_minus8;
......
...@@ -44,82 +44,100 @@ ...@@ -44,82 +44,100 @@
#include "precomp.hpp" #include "precomp.hpp"
#ifdef HAVE_NVCUVID #ifdef HAVE_NVCUVID
using namespace cv; using namespace cv;
using namespace cv::cudacodec; using namespace cv::cudacodec;
using namespace cv::cudacodec::detail; using namespace cv::cudacodec::detail;
namespace #ifndef CV_FOURCC_MACRO
{ #define CV_FOURCC_MACRO(c1, c2, c3, c4) (((c1) & 255) + (((c2) & 255) << 8) + (((c3) & 255) << 16) + (((c4) & 255) << 24))
Create_InputMediaStream_FFMPEG_Plugin create_InputMediaStream_FFMPEG_p = 0; #endif
Release_InputMediaStream_FFMPEG_Plugin release_InputMediaStream_FFMPEG_p = 0;
Read_InputMediaStream_FFMPEG_Plugin read_InputMediaStream_FFMPEG_p = 0;
bool init_MediaStream_FFMPEG() static std::string fourccToString(int fourcc)
{ {
static bool initialized = 0; union {
int u32;
if (!initialized) unsigned char c[4];
{ } i32_c;
#if defined _WIN32 i32_c.u32 = fourcc;
const char* module_name = "opencv_ffmpeg" return cv::format("%c%c%c%c",
CVAUX_STR(CV_VERSION_MAJOR) CVAUX_STR(CV_VERSION_MINOR) CVAUX_STR(CV_VERSION_REVISION) (i32_c.c[0] >= ' ' && i32_c.c[0] < 128) ? i32_c.c[0] : '?',
#if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__) (i32_c.c[1] >= ' ' && i32_c.c[1] < 128) ? i32_c.c[1] : '?',
"_64" (i32_c.c[2] >= ' ' && i32_c.c[2] < 128) ? i32_c.c[2] : '?',
#endif (i32_c.c[3] >= ' ' && i32_c.c[3] < 128) ? i32_c.c[3] : '?');
".dll"; }
static HMODULE cvFFOpenCV = LoadLibrary(module_name);
if (cvFFOpenCV) static
Codec FourccToCodec(int codec)
{
switch (codec)
{ {
create_InputMediaStream_FFMPEG_p = case CV_FOURCC_MACRO('m', 'p', 'e', 'g'): // fallthru
(Create_InputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "create_InputMediaStream_FFMPEG"); case CV_FOURCC_MACRO('M', 'P', 'G', '1'): return MPEG1;
release_InputMediaStream_FFMPEG_p = case CV_FOURCC_MACRO('M', 'P', 'G', '2'): return MPEG2;
(Release_InputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "release_InputMediaStream_FFMPEG"); case CV_FOURCC_MACRO('X', 'V', 'I', 'D'): // fallthru
read_InputMediaStream_FFMPEG_p = case CV_FOURCC_MACRO('D', 'I', 'V', 'X'): return MPEG4;
(Read_InputMediaStream_FFMPEG_Plugin)GetProcAddress(cvFFOpenCV, "read_InputMediaStream_FFMPEG"); case CV_FOURCC_MACRO('W', 'V', 'C', '1'): return VC1;
case CV_FOURCC_MACRO('H', '2', '6', '4'): // fallthru
initialized = create_InputMediaStream_FFMPEG_p != 0 && release_InputMediaStream_FFMPEG_p != 0 && read_InputMediaStream_FFMPEG_p != 0; case CV_FOURCC_MACRO('h', '2', '6', '4'): // fallthru
case CV_FOURCC_MACRO('a', 'v', 'c', '1'): return H264;
case CV_FOURCC_MACRO('H', '2', '6', '5'): // fallthru
case CV_FOURCC_MACRO('h', '2', '6', '5'): // fallthru
case CV_FOURCC_MACRO('h', 'e', 'v', 'c'): return HEVC;
case CV_FOURCC_MACRO('M', 'J', 'P', 'G'): return JPEG;
case CV_FOURCC_MACRO('V', 'P', '8', '0'): return VP8;
case CV_FOURCC_MACRO('V', 'P', '9', '0'): return VP9;
default:
break;
} }
#elif defined HAVE_FFMPEG
create_InputMediaStream_FFMPEG_p = create_InputMediaStream_FFMPEG;
release_InputMediaStream_FFMPEG_p = release_InputMediaStream_FFMPEG;
read_InputMediaStream_FFMPEG_p = read_InputMediaStream_FFMPEG;
initialized = true; std::string msg = cv::format("Unknown codec FOURCC: 0x%08X (%s)", codec, fourccToString(codec).c_str());
#endif CV_LOG_WARNING(NULL, msg);
} CV_Error(Error::StsUnsupportedFormat, msg);
}
return initialized; static
void FourccToChromaFormat(const int pixelFormat, ChromaFormat &chromaFormat, int & nBitDepthMinus8)
{
switch (pixelFormat)
{
case CV_FOURCC_MACRO('I', '4', '2', '0'):
chromaFormat = YUV420;
nBitDepthMinus8 = 0;
break;
default:
CV_LOG_WARNING(NULL, cv::format("ChromaFormat not recognized: 0x%08X (%s). Assuming I420", pixelFormat, fourccToString(pixelFormat).c_str()));
chromaFormat = YUV420;
nBitDepthMinus8 = 0;
break;
} }
} }
cv::cudacodec::detail::FFmpegVideoSource::FFmpegVideoSource(const String& fname) : cv::cudacodec::detail::FFmpegVideoSource::FFmpegVideoSource(const String& fname)
stream_(0)
{ {
CV_Assert( init_MediaStream_FFMPEG() ); if (!videoio_registry::hasBackend(CAP_FFMPEG))
CV_Error(Error::StsNotImplemented, "FFmpeg backend not found");
int codec;
int chroma_format;
int width;
int height;
stream_ = create_InputMediaStream_FFMPEG_p(fname.c_str(), &codec, &chroma_format, &width, &height); cap.open(fname, CAP_FFMPEG);
if (!stream_) if (!cap.isOpened())
CV_Error(Error::StsUnsupportedFormat, "Unsupported video source"); CV_Error(Error::StsUnsupportedFormat, "Unsupported video source");
format_.codec = static_cast<Codec>(codec); if (!cap.set(CAP_PROP_FORMAT, -1)) // turn off video decoder (extract stream)
format_.chromaFormat = static_cast<ChromaFormat>(chroma_format); CV_Error(Error::StsUnsupportedFormat, "Fetching of RAW video streams is not supported");
format_.nBitDepthMinus8 = -1; CV_Assert(cap.get(CAP_PROP_FORMAT) == -1);
format_.width = width;
format_.height = height; int codec = (int)cap.get(CAP_PROP_FOURCC);
int pixelFormat = (int)cap.get(CAP_PROP_CODEC_PIXEL_FORMAT);
format_.codec = FourccToCodec(codec);
format_.height = cap.get(CAP_PROP_FRAME_HEIGHT);
format_.width = cap.get(CAP_PROP_FRAME_WIDTH);
FourccToChromaFormat(pixelFormat, format_.chromaFormat, format_.nBitDepthMinus8);
} }
cv::cudacodec::detail::FFmpegVideoSource::~FFmpegVideoSource() cv::cudacodec::detail::FFmpegVideoSource::~FFmpegVideoSource()
{ {
if (stream_) if (cap.isOpened())
release_InputMediaStream_FFMPEG_p(stream_); cap.release();
} }
FormatInfo cv::cudacodec::detail::FFmpegVideoSource::format() const FormatInfo cv::cudacodec::detail::FFmpegVideoSource::format() const
...@@ -127,14 +145,12 @@ FormatInfo cv::cudacodec::detail::FFmpegVideoSource::format() const ...@@ -127,14 +145,12 @@ FormatInfo cv::cudacodec::detail::FFmpegVideoSource::format() const
return format_; return format_;
} }
bool cv::cudacodec::detail::FFmpegVideoSource::getNextPacket(unsigned char** data, int* size, bool* bEndOfFile) bool cv::cudacodec::detail::FFmpegVideoSource::getNextPacket(unsigned char** data, size_t* size)
{ {
int endOfFile; cap >> rawFrame;
*data = rawFrame.data;
int res = read_InputMediaStream_FFMPEG_p(stream_, data, size, &endOfFile); *size = rawFrame.total();
return *size != 0;
*bEndOfFile = (endOfFile != 0);
return res != 0;
} }
#endif // HAVE_CUDA #endif // HAVE_CUDA
...@@ -46,8 +46,6 @@ ...@@ -46,8 +46,6 @@
#include "opencv2/cudacodec.hpp" #include "opencv2/cudacodec.hpp"
struct InputMediaStream_FFMPEG;
namespace cv { namespace cudacodec { namespace detail { namespace cv { namespace cudacodec { namespace detail {
class FFmpegVideoSource : public RawVideoSource class FFmpegVideoSource : public RawVideoSource
...@@ -56,14 +54,14 @@ public: ...@@ -56,14 +54,14 @@ public:
FFmpegVideoSource(const String& fname); FFmpegVideoSource(const String& fname);
~FFmpegVideoSource(); ~FFmpegVideoSource();
bool getNextPacket(unsigned char** data, int* size, bool* endOfFile) CV_OVERRIDE; bool getNextPacket(unsigned char** data, size_t* size) CV_OVERRIDE;
FormatInfo format() const CV_OVERRIDE; FormatInfo format() const CV_OVERRIDE;
private: private:
FormatInfo format_; FormatInfo format_;
VideoCapture cap;
InputMediaStream_FFMPEG* stream_; Mat rawFrame;
}; };
}}} }}}
......
...@@ -52,8 +52,10 @@ ...@@ -52,8 +52,10 @@
#include <iostream> #include <iostream>
#include "opencv2/cudacodec.hpp" #include "opencv2/cudacodec.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/videoio/registry.hpp"
#include "opencv2/core/private.cuda.hpp" #include "opencv2/core/private.cuda.hpp"
#include <opencv2/core/utils/logger.hpp>
#ifdef HAVE_NVCUVID #ifdef HAVE_NVCUVID
#if CUDA_VERSION >= 9000 && CUDA_VERSION < 10000 #if CUDA_VERSION >= 9000 && CUDA_VERSION < 10000
...@@ -81,7 +83,6 @@ ...@@ -81,7 +83,6 @@
#include "video_decoder.hpp" #include "video_decoder.hpp"
#include "video_parser.hpp" #include "video_parser.hpp"
#include "../src/cap_ffmpeg_api.hpp"
#endif #endif
#endif /* OPENCV_PRECOMP_H */ #endif /* OPENCV_PRECOMP_H */
...@@ -47,7 +47,8 @@ ...@@ -47,7 +47,8 @@
void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat) void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat)
{ {
release(); if (videoFormat.nBitDepthMinus8 > 0 || videoFormat.chromaFormat != YUV420)
CV_Error(Error::StsUnsupportedFormat, "NV12 output requires 8 bit YUV420");
cudaVideoCodec _codec = static_cast<cudaVideoCodec>(videoFormat.codec); cudaVideoCodec _codec = static_cast<cudaVideoCodec>(videoFormat.codec);
cudaVideoChromaFormat _chromaFormat = static_cast<cudaVideoChromaFormat>(videoFormat.chromaFormat); cudaVideoChromaFormat _chromaFormat = static_cast<cudaVideoChromaFormat>(videoFormat.chromaFormat);
...@@ -89,12 +90,13 @@ void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat) ...@@ -89,12 +90,13 @@ void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat)
#if (CUDART_VERSION >= 9000) #if (CUDART_VERSION >= 9000)
// Check video format is supported by GPU's hardware video decoder // Check video format is supported by GPU's hardware video decoder
if (videoFormat.nBitDepthMinus8 != -1) { // info not available call to create CuvidVideoSource() failed
CUVIDDECODECAPS decodeCaps = {}; CUVIDDECODECAPS decodeCaps = {};
decodeCaps.eCodecType = _codec; decodeCaps.eCodecType = _codec;
decodeCaps.eChromaFormat = _chromaFormat; decodeCaps.eChromaFormat = _chromaFormat;
decodeCaps.nBitDepthMinus8 = videoFormat.nBitDepthMinus8; decodeCaps.nBitDepthMinus8 = videoFormat.nBitDepthMinus8;
cuSafeCall(cuCtxPushCurrent(ctx_));
cuSafeCall(cuvidGetDecoderCaps(&decodeCaps)); cuSafeCall(cuvidGetDecoderCaps(&decodeCaps));
cuSafeCall(cuCtxPopCurrent(NULL));
if (!decodeCaps.bIsSupported) if (!decodeCaps.bIsSupported)
CV_Error(Error::StsUnsupportedFormat, "Video source is not supported by hardware video decoder"); CV_Error(Error::StsUnsupportedFormat, "Video source is not supported by hardware video decoder");
...@@ -102,7 +104,8 @@ void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat) ...@@ -102,7 +104,8 @@ void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat)
videoFormat.height >= decodeCaps.nMinHeight && videoFormat.height >= decodeCaps.nMinHeight &&
videoFormat.width <= decodeCaps.nMaxWidth && videoFormat.width <= decodeCaps.nMaxWidth &&
videoFormat.height <= decodeCaps.nMaxHeight); videoFormat.height <= decodeCaps.nMaxHeight);
}
CV_Assert((videoFormat.width >> 4)* (videoFormat.height >> 4) <= decodeCaps.nMaxMBCount);
#endif #endif
// Fill the decoder-create-info struct from the given video-format struct. // Fill the decoder-create-info struct from the given video-format struct.
...@@ -113,11 +116,6 @@ void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat) ...@@ -113,11 +116,6 @@ void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat)
createInfo_.ulWidth = videoFormat.width; createInfo_.ulWidth = videoFormat.width;
createInfo_.ulHeight = videoFormat.height; createInfo_.ulHeight = videoFormat.height;
createInfo_.ulNumDecodeSurfaces = FrameQueue::MaximumSize; createInfo_.ulNumDecodeSurfaces = FrameQueue::MaximumSize;
// Limit decode memory to 24MB (16M pixels at 4:2:0 = 24M bytes)
while (createInfo_.ulNumDecodeSurfaces * videoFormat.width * videoFormat.height > 16 * 1024 * 1024)
createInfo_.ulNumDecodeSurfaces--;
createInfo_.ChromaFormat = _chromaFormat; createInfo_.ChromaFormat = _chromaFormat;
createInfo_.OutputFormat = cudaVideoSurfaceFormat_NV12; createInfo_.OutputFormat = cudaVideoSurfaceFormat_NV12;
createInfo_.DeinterlaceMode = cudaVideoDeinterlaceMode_Adaptive; createInfo_.DeinterlaceMode = cudaVideoDeinterlaceMode_Adaptive;
...@@ -131,8 +129,9 @@ void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat) ...@@ -131,8 +129,9 @@ void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat)
createInfo_.ulCreationFlags = videoCreateFlags; createInfo_.ulCreationFlags = videoCreateFlags;
createInfo_.vidLock = lock_; createInfo_.vidLock = lock_;
// create the decoder cuSafeCall(cuCtxPushCurrent(ctx_));
cuSafeCall( cuvidCreateDecoder(&decoder_, &createInfo_) ); cuSafeCall(cuvidCreateDecoder(&decoder_, &createInfo_));
cuSafeCall(cuCtxPopCurrent(NULL));
} }
void cv::cudacodec::detail::VideoDecoder::release() void cv::cudacodec::detail::VideoDecoder::release()
......
...@@ -59,7 +59,7 @@ namespace cv { namespace cudacodec { namespace detail ...@@ -59,7 +59,7 @@ namespace cv { namespace cudacodec { namespace detail
class VideoDecoder class VideoDecoder
{ {
public: public:
VideoDecoder(const FormatInfo& videoFormat, CUvideoctxlock lock) : lock_(lock), decoder_(0) VideoDecoder(const FormatInfo& videoFormat, CUcontext ctx, CUvideoctxlock lock) : ctx_(ctx), lock_(lock), decoder_(0)
{ {
create(videoFormat); create(videoFormat);
} }
...@@ -83,6 +83,7 @@ public: ...@@ -83,6 +83,7 @@ public:
unsigned long targetHeight() const { return createInfo_.ulTargetHeight; } unsigned long targetHeight() const { return createInfo_.ulTargetHeight; }
cudaVideoChromaFormat chromaFormat() const { return createInfo_.ChromaFormat; } cudaVideoChromaFormat chromaFormat() const { return createInfo_.ChromaFormat; }
int nBitDepthMinus8() const { return createInfo_.bitDepthMinus8; }
bool decodePicture(CUVIDPICPARAMS* picParams) bool decodePicture(CUVIDPICPARAMS* picParams)
{ {
...@@ -96,6 +97,7 @@ public: ...@@ -96,6 +97,7 @@ public:
cuSafeCall( cuvidMapVideoFrame(decoder_, picIdx, &ptr, &pitch, &videoProcParams) ); cuSafeCall( cuvidMapVideoFrame(decoder_, picIdx, &ptr, &pitch, &videoProcParams) );
return cuda::GpuMat(targetHeight() * 3 / 2, targetWidth(), CV_8UC1, (void*) ptr, pitch); return cuda::GpuMat(targetHeight() * 3 / 2, targetWidth(), CV_8UC1, (void*) ptr, pitch);
} }
...@@ -107,6 +109,7 @@ public: ...@@ -107,6 +109,7 @@ public:
private: private:
CUvideoctxlock lock_; CUvideoctxlock lock_;
CUcontext ctx_;
CUVIDDECODECREATEINFO createInfo_; CUVIDDECODECREATEINFO createInfo_;
CUvideodecoder decoder_; CUvideodecoder decoder_;
}; };
......
...@@ -80,7 +80,7 @@ bool cv::cudacodec::detail::VideoParser::parseVideoData(const unsigned char* dat ...@@ -80,7 +80,7 @@ bool cv::cudacodec::detail::VideoParser::parseVideoData(const unsigned char* dat
return false; return false;
} }
const int maxUnparsedPackets = 15; const int maxUnparsedPackets = 20;
++unparsedPackets_; ++unparsedPackets_;
if (unparsedPackets_ > maxUnparsedPackets) if (unparsedPackets_ > maxUnparsedPackets)
...@@ -105,7 +105,8 @@ int CUDAAPI cv::cudacodec::detail::VideoParser::HandleVideoSequence(void* userDa ...@@ -105,7 +105,8 @@ int CUDAAPI cv::cudacodec::detail::VideoParser::HandleVideoSequence(void* userDa
if (format->codec != thiz->videoDecoder_->codec() || if (format->codec != thiz->videoDecoder_->codec() ||
format->coded_width != thiz->videoDecoder_->frameWidth() || format->coded_width != thiz->videoDecoder_->frameWidth() ||
format->coded_height != thiz->videoDecoder_->frameHeight() || format->coded_height != thiz->videoDecoder_->frameHeight() ||
format->chroma_format != thiz->videoDecoder_->chromaFormat()) format->chroma_format != thiz->videoDecoder_->chromaFormat()||
format->bit_depth_luma_minus8 != thiz->videoDecoder_->nBitDepthMinus8())
{ {
FormatInfo newFormat; FormatInfo newFormat;
...@@ -113,6 +114,7 @@ int CUDAAPI cv::cudacodec::detail::VideoParser::HandleVideoSequence(void* userDa ...@@ -113,6 +114,7 @@ int CUDAAPI cv::cudacodec::detail::VideoParser::HandleVideoSequence(void* userDa
newFormat.chromaFormat = static_cast<ChromaFormat>(format->chroma_format); newFormat.chromaFormat = static_cast<ChromaFormat>(format->chroma_format);
newFormat.width = format->coded_width; newFormat.width = format->coded_width;
newFormat.height = format->coded_height; newFormat.height = format->coded_height;
newFormat.nBitDepthMinus8 = format->bit_depth_luma_minus8;
try try
{ {
......
...@@ -53,7 +53,7 @@ Ptr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>&) { ...@@ -53,7 +53,7 @@ Ptr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>&) {
#else // HAVE_NVCUVID #else // HAVE_NVCUVID
void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height); void videoDecPostProcessFrame(const GpuMat& decodedFrame, OutputArray _outFrame, int width, int height, cudaStream_t stream);
using namespace cv::cudacodec::detail; using namespace cv::cudacodec::detail;
...@@ -65,7 +65,7 @@ namespace ...@@ -65,7 +65,7 @@ namespace
explicit VideoReaderImpl(const Ptr<VideoSource>& source); explicit VideoReaderImpl(const Ptr<VideoSource>& source);
~VideoReaderImpl(); ~VideoReaderImpl();
bool nextFrame(OutputArray frame) CV_OVERRIDE; bool nextFrame(OutputArray frame, Stream& stream) CV_OVERRIDE;
FormatInfo format() const CV_OVERRIDE; FormatInfo format() const CV_OVERRIDE;
...@@ -99,7 +99,7 @@ namespace ...@@ -99,7 +99,7 @@ namespace
cuSafeCall( cuvidCtxLockCreate(&lock_, ctx) ); cuSafeCall( cuvidCtxLockCreate(&lock_, ctx) );
frameQueue_.reset(new FrameQueue); frameQueue_.reset(new FrameQueue);
videoDecoder_.reset(new VideoDecoder(videoSource_->format(), lock_)); videoDecoder_.reset(new VideoDecoder(videoSource_->format(), ctx, lock_));
videoParser_.reset(new VideoParser(videoDecoder_, frameQueue_)); videoParser_.reset(new VideoParser(videoDecoder_, frameQueue_));
videoSource_->setVideoParser(videoParser_); videoSource_->setVideoParser(videoParser_);
...@@ -122,14 +122,11 @@ namespace ...@@ -122,14 +122,11 @@ namespace
CUvideoctxlock m_lock; CUvideoctxlock m_lock;
}; };
bool VideoReaderImpl::nextFrame(OutputArray frame) bool VideoReaderImpl::nextFrame(OutputArray frame, Stream& stream)
{ {
if (videoSource_->hasError() || videoParser_->hasError()) if (videoSource_->hasError() || videoParser_->hasError())
CV_Error(Error::StsUnsupportedFormat, "Unsupported video source"); CV_Error(Error::StsUnsupportedFormat, "Unsupported video source");
if (!videoSource_->isStarted() || frameQueue_->isEndOfDecode())
return false;
if (frames_.empty()) if (frames_.empty())
{ {
CUVIDPARSERDISPINFO displayInfo; CUVIDPARSERDISPINFO displayInfo;
...@@ -180,7 +177,7 @@ namespace ...@@ -180,7 +177,7 @@ namespace
// perform post processing on the CUDA surface (performs colors space conversion and post processing) // perform post processing on the CUDA surface (performs colors space conversion and post processing)
// comment this out if we include the line of code seen above // comment this out if we include the line of code seen above
videoDecPostProcessFrame(decodedFrame, frame, videoDecoder_->targetWidth(), videoDecoder_->targetHeight()); videoDecPostProcessFrame(decodedFrame, frame, videoDecoder_->targetWidth(), videoDecoder_->targetHeight(), StreamAccessor::getStream(stream));
// unmap video frame // unmap video frame
// unmapFrame() synchronizes with the VideoDecode API (ensures the frame has finished decoding) // unmapFrame() synchronizes with the VideoDecode API (ensures the frame has finished decoding)
...@@ -203,12 +200,13 @@ Ptr<VideoReader> cv::cudacodec::createVideoReader(const String& filename) ...@@ -203,12 +200,13 @@ Ptr<VideoReader> cv::cudacodec::createVideoReader(const String& filename)
try try
{ {
videoSource.reset(new CuvidVideoSource(filename)); // prefer ffmpeg to cuvidGetSourceVideoFormat() which doesn't always return the corrct raw pixel format
Ptr<RawVideoSource> source(new FFmpegVideoSource(filename));
videoSource.reset(new RawVideoSourceWrapper(source));
} }
catch (...) catch (...)
{ {
Ptr<RawVideoSource> source(new FFmpegVideoSource(filename)); videoSource.reset(new CuvidVideoSource(filename));
videoSource.reset(new RawVideoSourceWrapper(source));
} }
return makePtr<VideoReaderImpl>(videoSource); return makePtr<VideoReaderImpl>(videoSource);
......
...@@ -96,12 +96,11 @@ void cv::cudacodec::detail::RawVideoSourceWrapper::readLoop(void* userData) ...@@ -96,12 +96,11 @@ void cv::cudacodec::detail::RawVideoSourceWrapper::readLoop(void* userData)
for (;;) for (;;)
{ {
unsigned char* data; unsigned char* data;
int size; size_t size;
bool endOfFile;
if (!thiz->source_->getNextPacket(&data, &size, &endOfFile)) if (!thiz->source_->getNextPacket(&data, &size))
{ {
thiz->hasError_ = !endOfFile; thiz->hasError_ = false;
break; break;
} }
......
...@@ -54,11 +54,11 @@ cv::cudacodec::EncoderParams::EncoderParams(const String&) { throw_no_cuda(); } ...@@ -54,11 +54,11 @@ cv::cudacodec::EncoderParams::EncoderParams(const String&) { throw_no_cuda(); }
void cv::cudacodec::EncoderParams::load(const String&) { throw_no_cuda(); } void cv::cudacodec::EncoderParams::load(const String&) { throw_no_cuda(); }
void cv::cudacodec::EncoderParams::save(const String&) const { throw_no_cuda(); } void cv::cudacodec::EncoderParams::save(const String&) const { throw_no_cuda(); }
Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const String&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); } Ptr<cv::cudacodec::VideoWriter> cv::cudacodec::createVideoWriter(const String&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr<cv::cudacodec::VideoWriter>(); }
Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const String&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); } Ptr<cv::cudacodec::VideoWriter> cv::cudacodec::createVideoWriter(const String&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr<cv::cudacodec::VideoWriter>(); }
Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); } Ptr<cv::cudacodec::VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr<cv::cudacodec::VideoWriter>(); }
Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); } Ptr<cv::cudacodec::VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr<cv::cudacodec::VideoWriter>(); }
#else // !defined HAVE_NVCUVENC || !defined _WIN32 #else // !defined HAVE_NVCUVENC || !defined _WIN32
...@@ -913,4 +913,4 @@ Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>& en ...@@ -913,4 +913,4 @@ Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>& en
return makePtr<VideoWriterImpl>(encoderCallback, frameSize, fps, params, format); return makePtr<VideoWriterImpl>(encoderCallback, frameSize, fps, params, format);
} }
#endif // !defined HAVE_NVCUVENC || !defined _WIN32 #endif // !defined HAVE_NVCUVENC || !defined _WIN32 || defined HAVE_FFMPEG_WRAPPER
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#define OPENCV_TEST_PRECOMP_HPP #define OPENCV_TEST_PRECOMP_HPP
#include "opencv2/ts.hpp" #include "opencv2/ts.hpp"
#include "opencv2/videoio/registry.hpp"
#include "opencv2/ts/cuda_test.hpp" #include "opencv2/ts/cuda_test.hpp"
#include "opencv2/cudacodec.hpp" #include "opencv2/cudacodec.hpp"
......
...@@ -41,15 +41,15 @@ ...@@ -41,15 +41,15 @@
//M*/ //M*/
#include "test_precomp.hpp" #include "test_precomp.hpp"
namespace opencv_test {
namespace {
namespace opencv_test { namespace { #if defined(HAVE_NVCUVID) || defined(HAVE_NVCUVENC)
#ifdef HAVE_NVCUVID
PARAM_TEST_CASE(Video, cv::cuda::DeviceInfo, std::string) PARAM_TEST_CASE(Video, cv::cuda::DeviceInfo, std::string)
{ {
}; };
#if defined(HAVE_NVCUVID)
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
// VideoReader // VideoReader
...@@ -57,24 +57,26 @@ CUDA_TEST_P(Video, Reader) ...@@ -57,24 +57,26 @@ CUDA_TEST_P(Video, Reader)
{ {
cv::cuda::setDevice(GET_PARAM(0).deviceID()); cv::cuda::setDevice(GET_PARAM(0).deviceID());
const std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "video/" + GET_PARAM(1); // CUDA demuxer has to fall back to ffmpeg to process "gpu/video/768x576.avi"
if (GET_PARAM(1) == "gpu/video/768x576.avi" && !videoio_registry::hasBackend(CAP_FFMPEG))
throw SkipTestException("FFmpeg backend not found");
std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../" + GET_PARAM(1);
cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(inputFile); cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(inputFile);
cv::cuda::GpuMat frame; cv::cuda::GpuMat frame;
for (int i = 0; i < 100; i++)
for (int i = 0; i < 10; ++i)
{ {
ASSERT_TRUE(reader->nextFrame(frame)); ASSERT_TRUE(reader->nextFrame(frame));
ASSERT_FALSE(frame.empty()); ASSERT_FALSE(frame.empty());
} }
} }
#endif // HAVE_NVCUVID
#if defined(_WIN32) && defined(HAVE_NVCUVENC)
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
// VideoWriter // VideoWriter
#ifdef _WIN32
CUDA_TEST_P(Video, Writer) CUDA_TEST_P(Video, Writer)
{ {
cv::cuda::setDevice(GET_PARAM(0).deviceID()); cv::cuda::setDevice(GET_PARAM(0).deviceID());
...@@ -118,11 +120,14 @@ CUDA_TEST_P(Video, Writer) ...@@ -118,11 +120,14 @@ CUDA_TEST_P(Video, Writer)
} }
} }
#endif // _WIN32 #endif // _WIN32, HAVE_NVCUVENC
#define VIDEO_SRC "gpu/video/768x576.avi", "gpu/video/1920x1080.avi", "highgui/video/big_buck_bunny.avi", \
"highgui/video/big_buck_bunny.h264", "highgui/video/big_buck_bunny.h265", "highgui/video/big_buck_bunny.mpg", \
"highgui/video/big_buck_bunny.mpg"
INSTANTIATE_TEST_CASE_P(CUDA_Codec, Video, testing::Combine( INSTANTIATE_TEST_CASE_P(CUDA_Codec, Video, testing::Combine(
ALL_DEVICES, ALL_DEVICES,
testing::Values(std::string("768x576.avi"), std::string("1920x1080.avi")))); testing::Values(VIDEO_SRC)));
#endif // HAVE_NVCUVID #endif // HAVE_NVCUVID || HAVE_NVCUVENC
}} // namespace }} // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment