Skip to content

Commit ed38f75

Browse files
committed
Merge pull request #3209 from cudawarped:cudacodec_change_n_decode_surfaces
2 parents 172a044 + c3ac120 commit ed38f75

File tree

5 files changed

+75
-17
lines changed

5 files changed

+75
-17
lines changed

modules/cudacodec/include/opencv2/cudacodec.hpp

+10-2
Original file line numberDiff line numberDiff line change
@@ -457,16 +457,24 @@ The `params` parameter allows to specify extra parameters encoded as pairs `(par
457457
See cv::VideoCaptureProperties
458458
e.g. when streaming from an RTSP source CAP_PROP_OPEN_TIMEOUT_MSEC may need to be set.
459459
@param rawMode Allow the raw encoded data which has been read up until the last call to grab() to be retrieved by calling retrieve(rawData,RAW_DATA_IDX).
460+
@param minNumDecodeSurfaces Minimum number of internal decode surfaces used by the hardware decoder. NVDEC will automatically determine the minimum number of
461+
surfaces it requires for correct functionality and optimal video memory usage but not necessarily for best performance, which depends on the design of the
462+
overall application. The optimal number of decode surfaces (in terms of performance and memory utilization) should be decided by experimentation for each application,
463+
but it cannot go below the number determined by NVDEC.
460464
461465
FFMPEG is used to read videos. User can implement own demultiplexing with cudacodec::RawVideoSource
462466
*/
463-
CV_EXPORTS_W Ptr<VideoReader> createVideoReader(const String& filename, const std::vector<int>& params = {}, const bool rawMode = false);
467+
CV_EXPORTS_W Ptr<VideoReader> createVideoReader(const String& filename, const std::vector<int>& params = {}, const bool rawMode = false, const int minNumDecodeSurfaces = 0);
464468

465469
/** @overload
466470
@param source RAW video source implemented by user.
467471
@param rawMode Allow the raw encoded data which has been read up until the last call to grab() to be retrieved by calling retrieve(rawData,RAW_DATA_IDX).
472+
@param minNumDecodeSurfaces Minimum number of internal decode surfaces used by the hardware decoder. NVDEC will automatically determine the minimum number of
473+
surfaces it requires for correct functionality and optimal video memory usage but not necessarily for best performance, which depends on the design of the
474+
overall application. The optimal number of decode surfaces (in terms of performance and memory utilization) should be decided by experimentation for each application,
475+
but it cannot go below the number determined by NVDEC.
468476
*/
469-
CV_EXPORTS_W Ptr<VideoReader> createVideoReader(const Ptr<RawVideoSource>& source, const bool rawMode = false);
477+
CV_EXPORTS_W Ptr<VideoReader> createVideoReader(const Ptr<RawVideoSource>& source, const bool rawMode = false, const int minNumDecodeSurfaces = 0);
470478

471479
//! @}
472480

modules/cudacodec/src/video_decoder.hpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ namespace cv { namespace cudacodec { namespace detail {
4949
class VideoDecoder
5050
{
5151
public:
52-
VideoDecoder(const Codec& codec, CUcontext ctx, CUvideoctxlock lock) : ctx_(ctx), lock_(lock), decoder_(0)
52+
VideoDecoder(const Codec& codec, const int minNumDecodeSurfaces, CUcontext ctx, CUvideoctxlock lock) : ctx_(ctx), lock_(lock), decoder_(0)
5353
{
5454
videoFormat_.codec = codec;
55+
videoFormat_.ulNumDecodeSurfaces = minNumDecodeSurfaces;
5556
}
5657

5758
~VideoDecoder()
@@ -64,7 +65,7 @@ class VideoDecoder
6465

6566
// Get the code-type currently used.
6667
cudaVideoCodec codec() const { return static_cast<cudaVideoCodec>(videoFormat_.codec); }
67-
unsigned long maxDecodeSurfaces() const { return videoFormat_.ulNumDecodeSurfaces; }
68+
int nDecodeSurfaces() const { return videoFormat_.ulNumDecodeSurfaces; }
6869

6970
unsigned long frameWidth() const { return videoFormat_.ulWidth; }
7071
unsigned long frameHeight() const { return videoFormat_.ulHeight; }

modules/cudacodec/src/video_parser.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ int CUDAAPI cv::cudacodec::detail::VideoParser::HandleVideoSequence(void* userDa
110110
format->coded_height != thiz->videoDecoder_->frameHeight() ||
111111
format->chroma_format != thiz->videoDecoder_->chromaFormat()||
112112
format->bit_depth_luma_minus8 != thiz->videoDecoder_->nBitDepthMinus8() ||
113-
format->min_num_decode_surfaces != thiz->videoDecoder_->maxDecodeSurfaces())
113+
format->min_num_decode_surfaces != thiz->videoDecoder_->nDecodeSurfaces())
114114
{
115115
FormatInfo newFormat;
116116
newFormat.codec = static_cast<Codec>(format->codec);
@@ -122,7 +122,7 @@ int CUDAAPI cv::cudacodec::detail::VideoParser::HandleVideoSequence(void* userDa
122122
newFormat.height = format->coded_height;
123123
newFormat.displayArea = Rect(Point(format->display_area.left, format->display_area.top), Point(format->display_area.right, format->display_area.bottom));
124124
newFormat.fps = format->frame_rate.numerator / static_cast<float>(format->frame_rate.denominator);
125-
newFormat.ulNumDecodeSurfaces = format->min_num_decode_surfaces;
125+
newFormat.ulNumDecodeSurfaces = max(thiz->videoDecoder_->nDecodeSurfaces(), static_cast<int>(format->min_num_decode_surfaces));
126126
if (format->progressive_sequence)
127127
newFormat.deinterlaceMode = Weave;
128128
else
@@ -154,7 +154,7 @@ int CUDAAPI cv::cudacodec::detail::VideoParser::HandleVideoSequence(void* userDa
154154
}
155155
}
156156

157-
return thiz->videoDecoder_->maxDecodeSurfaces();
157+
return thiz->videoDecoder_->nDecodeSurfaces();
158158
}
159159

160160
int CUDAAPI cv::cudacodec::detail::VideoParser::HandlePictureDecode(void* userData, CUVIDPICPARAMS* picParams)

modules/cudacodec/src/video_reader.cpp

+9-9
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ using namespace cv::cudacodec;
4848

4949
#ifndef HAVE_NVCUVID
5050

51-
Ptr<VideoReader> cv::cudacodec::createVideoReader(const String&, const std::vector<int>&, const bool) { throw_no_cuda(); return Ptr<VideoReader>(); }
52-
Ptr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>&, const bool) { throw_no_cuda(); return Ptr<VideoReader>(); }
51+
Ptr<VideoReader> cv::cudacodec::createVideoReader(const String&, const std::vector<int>&, const bool, const int) { throw_no_cuda(); return Ptr<VideoReader>(); }
52+
Ptr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>&, const bool, const int) { throw_no_cuda(); return Ptr<VideoReader>(); }
5353

5454
#else // HAVE_NVCUVID
5555

@@ -62,7 +62,7 @@ namespace
6262
class VideoReaderImpl : public VideoReader
6363
{
6464
public:
65-
explicit VideoReaderImpl(const Ptr<VideoSource>& source);
65+
explicit VideoReaderImpl(const Ptr<VideoSource>& source, const int minNumDecodeSurfaces);
6666
~VideoReaderImpl();
6767

6868
bool nextFrame(GpuMat& frame, Stream& stream) CV_OVERRIDE;
@@ -103,7 +103,7 @@ namespace
103103
return videoSource_->format();
104104
}
105105

106-
VideoReaderImpl::VideoReaderImpl(const Ptr<VideoSource>& source) :
106+
VideoReaderImpl::VideoReaderImpl(const Ptr<VideoSource>& source, const int minNumDecodeSurfaces) :
107107
videoSource_(source),
108108
lock_(0)
109109
{
@@ -115,7 +115,7 @@ namespace
115115
cuSafeCall( cuCtxGetCurrent(&ctx) );
116116
cuSafeCall( cuvidCtxLockCreate(&lock_, ctx) );
117117
frameQueue_.reset(new FrameQueue());
118-
videoDecoder_.reset(new VideoDecoder(videoSource_->format().codec, ctx, lock_));
118+
videoDecoder_.reset(new VideoDecoder(videoSource_->format().codec, minNumDecodeSurfaces, ctx, lock_));
119119
videoParser_.reset(new VideoParser(videoDecoder_, frameQueue_));
120120
videoSource_->setVideoParser(videoParser_);
121121
videoSource_->start();
@@ -291,7 +291,7 @@ namespace
291291
}
292292
}
293293

294-
Ptr<VideoReader> cv::cudacodec::createVideoReader(const String& filename, const std::vector<int>& params, const bool rawMode)
294+
Ptr<VideoReader> cv::cudacodec::createVideoReader(const String& filename, const std::vector<int>& params, const bool rawMode, const int minNumDecodeSurfaces)
295295
{
296296
CV_Assert(!filename.empty());
297297

@@ -309,13 +309,13 @@ Ptr<VideoReader> cv::cudacodec::createVideoReader(const String& filename, const
309309
videoSource.reset(new CuvidVideoSource(filename));
310310
}
311311

312-
return makePtr<VideoReaderImpl>(videoSource);
312+
return makePtr<VideoReaderImpl>(videoSource, minNumDecodeSurfaces);
313313
}
314314

315-
Ptr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>& source, const bool rawMode)
315+
Ptr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>& source, const bool rawMode, const int minNumDecodeSurfaces)
316316
{
317317
Ptr<VideoSource> videoSource(new RawVideoSourceWrapper(source, rawMode));
318-
return makePtr<VideoReaderImpl>(videoSource);
318+
return makePtr<VideoReaderImpl>(videoSource, minNumDecodeSurfaces);
319319
}
320320

321321
#endif // HAVE_NVCUVID

modules/cudacodec/test/test_video.cpp

+50-1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ PARAM_TEST_CASE(CheckKeyFrame, cv::cuda::DeviceInfo, std::string)
6666
{
6767
};
6868

69+
PARAM_TEST_CASE(CheckDecodeSurfaces, cv::cuda::DeviceInfo, std::string)
70+
{
71+
};
72+
6973
struct CheckParams : testing::TestWithParam<cv::cuda::DeviceInfo>
7074
{
7175
cv::cuda::DeviceInfo devInfo;
@@ -281,14 +285,55 @@ CUDA_TEST_P(CheckParams, Reader)
281285
cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(inputFile, {
282286
cv::VideoCaptureProperties::CAP_PROP_FORMAT, capPropFormats.at(i) });
283287
}
284-
catch (cv::Exception ex) {
288+
catch (cv::Exception &ex) {
285289
if (ex.code == Error::StsUnsupportedFormat)
286290
exceptionThrown = true;
287291
}
288292
ASSERT_EQ(exceptionThrown, exceptionsThrown.at(i));
289293
}
290294
}
291295
}
296+
297+
CUDA_TEST_P(CheckDecodeSurfaces, Reader)
298+
{
299+
cv::cuda::setDevice(GET_PARAM(0).deviceID());
300+
const std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../" + GET_PARAM(1);
301+
int ulNumDecodeSurfaces = 0;
302+
{
303+
cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(inputFile);
304+
cv::cudacodec::FormatInfo fmt = reader->format();
305+
if (!fmt.valid) {
306+
reader->grab();
307+
fmt = reader->format();
308+
ASSERT_TRUE(fmt.valid);
309+
}
310+
ulNumDecodeSurfaces = fmt.ulNumDecodeSurfaces;
311+
}
312+
313+
{
314+
cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(inputFile, {}, false, ulNumDecodeSurfaces - 1);
315+
cv::cudacodec::FormatInfo fmt = reader->format();
316+
if (!fmt.valid) {
317+
reader->grab();
318+
fmt = reader->format();
319+
ASSERT_TRUE(fmt.valid);
320+
}
321+
ASSERT_TRUE(fmt.ulNumDecodeSurfaces == ulNumDecodeSurfaces);
322+
for (int i = 0; i < 100; i++) ASSERT_TRUE(reader->grab());
323+
}
324+
325+
{
326+
cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(inputFile, {}, false, ulNumDecodeSurfaces + 1);
327+
cv::cudacodec::FormatInfo fmt = reader->format();
328+
if (!fmt.valid) {
329+
reader->grab();
330+
fmt = reader->format();
331+
ASSERT_TRUE(fmt.valid);
332+
}
333+
ASSERT_TRUE(fmt.ulNumDecodeSurfaces == ulNumDecodeSurfaces + 1);
334+
for (int i = 0; i < 100; i++) ASSERT_TRUE(reader->grab());
335+
}
336+
}
292337
#endif // HAVE_NVCUVID
293338

294339
#if defined(_WIN32) && defined(HAVE_NVCUVENC)
@@ -372,5 +417,9 @@ INSTANTIATE_TEST_CASE_P(CUDA_Codec, CheckKeyFrame, testing::Combine(
372417

373418
INSTANTIATE_TEST_CASE_P(CUDA_Codec, CheckParams, ALL_DEVICES);
374419

420+
INSTANTIATE_TEST_CASE_P(CUDA_Codec, CheckDecodeSurfaces, testing::Combine(
421+
ALL_DEVICES,
422+
testing::Values("highgui/video/big_buck_bunny.mp4")));
423+
375424
#endif // HAVE_NVCUVID || HAVE_NVCUVENC
376425
}} // namespace

0 commit comments

Comments
 (0)