From 25f56cecd42f1c56bcd77fc68602fa59b2e993e6 Mon Sep 17 00:00:00 2001 From: cudawarped <12133430+cudawarped@users.noreply.github.com> Date: Fri, 28 Apr 2023 11:40:43 +0300 Subject: [PATCH] cudacodec::VideoReader - ensure FormatInfo is valid before returning from createVideoReader --- modules/cudacodec/src/video_decoder.hpp | 1 + modules/cudacodec/src/video_reader.cpp | 28 +++++++++++++++---- modules/cudacodec/test/test_video.cpp | 37 ++++++++----------------- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/modules/cudacodec/src/video_decoder.hpp b/modules/cudacodec/src/video_decoder.hpp index 76d731f2078..fbeee9f8904 100644 --- a/modules/cudacodec/src/video_decoder.hpp +++ b/modules/cudacodec/src/video_decoder.hpp @@ -69,6 +69,7 @@ class VideoDecoder void create(const FormatInfo& videoFormat); void release(); + bool inited() { AutoLock autoLock(mtx_); return decoder_; } // Get the code-type currently used. cudaVideoCodec codec() const { return static_cast(videoFormat_.codec); } diff --git a/modules/cudacodec/src/video_reader.cpp b/modules/cudacodec/src/video_reader.cpp index 3d71c3532e8..1acf19b9517 100644 --- a/modules/cudacodec/src/video_reader.cpp +++ b/modules/cudacodec/src/video_reader.cpp @@ -67,14 +67,11 @@ void cvtFromNv12(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int he outFrame.create(height, width, CV_8UC3); Npp8u* pSrc[2] = { decodedFrame.data, &decodedFrame.data[decodedFrame.step * height] }; NppiSize oSizeROI = { width,height }; -#if (CUDART_VERSION < 9200) - CV_Error(Error::StsUnsupportedFormat, "ColorFormat::BGR is not supported until CUDA 9.2, use default ColorFormat::BGRA."); -#elif (CUDART_VERSION < 10100) +#if (CUDART_VERSION < 10100) cv::cuda::NppStreamHandler h(stream); if (videoFullRangeFlag) nppSafeCall(nppiNV12ToBGR_709HDTV_8u_P2C3R(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI)); else { - CV_LOG_DEBUG(NULL, "Color reproduction may be inaccurate due CUDA version <= 11.0, for better results upgrade CUDA runtime or try ColorFormat::BGRA."); nppSafeCall(nppiNV12ToBGR_8u_P2C3R(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI)); } #elif (CUDART_VERSION >= 10100) @@ -85,7 +82,6 @@ void cvtFromNv12(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int he nppSafeCall(nppiNV12ToBGR_709HDTV_8u_P2C3R_Ctx(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI, nppStreamCtx)); else { #if (CUDART_VERSION < 11000) - CV_LOG_DEBUG(NULL, "Color reproduction may be inaccurate due CUDA version <= 11.0, for better results upgrade CUDA runtime or try ColorFormat::BGRA."); nppSafeCall(nppiNV12ToBGR_8u_P2C3R_Ctx(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI, nppStreamCtx)); #else nppSafeCall(nppiNV12ToBGR_709CSC_8u_P2C3R_Ctx(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI, nppStreamCtx)); @@ -137,6 +133,7 @@ namespace private: bool internalGrab(GpuMat& frame, Stream& stream); + void waitForDecoderInit(); Ptr videoSource_; @@ -160,6 +157,16 @@ namespace return videoSource_->format(); } + void VideoReaderImpl::waitForDecoderInit() { + for (;;) + { + if (videoDecoder_->inited()) break; + if (videoParser_->hasError() || frameQueue_->isEndOfDecode()) + CV_Error(Error::StsError, "Parsing/Decoding video source failed, check GPU memory is available and GPU supports hardware decoding."); + Thread::sleep(1); + } + } + VideoReaderImpl::VideoReaderImpl(const Ptr& source, const int minNumDecodeSurfaces, const bool allowFrameDrop, const bool udpSource, const Size targetSz, const Rect srcRoi, const Rect targetRoi) : videoSource_(source), @@ -177,6 +184,8 @@ namespace videoParser_.reset(new VideoParser(videoDecoder_, frameQueue_, allowFrameDrop, udpSource)); videoSource_->setVideoParser(videoParser_); videoSource_->start(); + waitForDecoderInit(); + videoSource_->updateFormat(videoDecoder_->format()); } VideoReaderImpl::~VideoReaderImpl() @@ -307,6 +316,15 @@ namespace bool VideoReaderImpl::set(const ColorFormat colorFormat_) { if (!ValidColorFormat(colorFormat_)) return false; + if (colorFormat_ == ColorFormat::BGR) { +#if (CUDART_VERSION < 9200) + CV_LOG_DEBUG(NULL, "ColorFormat::BGR is not supported until CUDA 9.2, use default ColorFormat::BGRA."); + return false; +#elif (CUDART_VERSION < 11000) + if (!videoDecoder_->format().videoFullRangeFlag) + CV_LOG_DEBUG(NULL, "Color reproduction may be inaccurate due CUDA version <= 11.0, for better results upgrade CUDA runtime or try ColorFormat::BGRA."); +#endif + } colorFormat = colorFormat_; return true; } diff --git a/modules/cudacodec/test/test_video.cpp b/modules/cudacodec/test/test_video.cpp index 2f05c1ac324..dde294fe680 100644 --- a/modules/cudacodec/test/test_video.cpp +++ b/modules/cudacodec/test/test_video.cpp @@ -212,10 +212,11 @@ CUDA_TEST_P(Scaling, Reader) params.targetRoi = Rect(static_cast(params.targetSz.width * targetRoiIn.x), static_cast(params.targetSz.height * targetRoiIn.y), static_cast(params.targetSz.width * targetRoiIn.width), static_cast(params.targetSz.height * targetRoiIn.height)); cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile, {}, params); + const cudacodec::FormatInfo format = reader->format(); + ASSERT_TRUE(format.valid); ASSERT_TRUE(reader->set(cudacodec::ColorFormat::GRAY)); GpuMat frame; ASSERT_TRUE(reader->nextFrame(frame)); - const cudacodec::FormatInfo format = reader->format(); Size targetSzOut; targetSzOut.width = params.targetSz.width - params.targetSz.width % 2; targetSzOut.height = params.targetSz.height - params.targetSz.height % 2; Rect srcRoiOut, targetRoiOut; @@ -223,7 +224,7 @@ CUDA_TEST_P(Scaling, Reader) srcRoiOut.y = params.srcRoi.y - params.srcRoi.y % 2; srcRoiOut.height = params.srcRoi.height - params.srcRoi.height % 2; targetRoiOut.x = params.targetRoi.x - params.targetRoi.x % 4; targetRoiOut.width = params.targetRoi.width - params.targetRoi.width % 4; targetRoiOut.y = params.targetRoi.y - params.targetRoi.y % 2; targetRoiOut.height = params.targetRoi.height - params.targetRoi.height % 2; - ASSERT_TRUE(format.valid && format.targetSz == targetSzOut && format.srcRoi == srcRoiOut && format.targetRoi == targetRoiOut); + ASSERT_TRUE(format.targetSz == targetSzOut && format.srcRoi == srcRoiOut && format.targetRoi == targetRoiOut); ASSERT_TRUE(frame.size() == targetSzOut); GpuMat frameGs; cv::cuda::resize(frameOr(srcRoiOut), frameGs, targetRoiOut.size(), 0, 0, INTER_AREA); @@ -287,6 +288,7 @@ CUDA_TEST_P(Video, Reader) cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile); ASSERT_FALSE(reader->set(cudacodec::ColorFormat::RGB)); cv::cudacodec::FormatInfo fmt = reader->format(); + ASSERT_TRUE(fmt.valid); cv::cuda::GpuMat frame; for (int i = 0; i < 10; i++) { @@ -296,8 +298,6 @@ CUDA_TEST_P(Video, Reader) double colorFormat; ASSERT_TRUE(reader->get(cudacodec::VideoReaderProps::PROP_COLOR_FORMAT, colorFormat) && static_cast(colorFormat) == formatToChannels.first); ASSERT_TRUE(reader->nextFrame(frame)); - if(!fmt.valid) - fmt = reader->format(); const int height = formatToChannels.first == cudacodec::ColorFormat::NV_NV12 ? static_cast(1.5 * fmt.height) : fmt.height; ASSERT_TRUE(frame.cols == fmt.width && frame.rows == height); ASSERT_FALSE(frame.empty()); @@ -312,6 +312,8 @@ CUDA_TEST_P(ColorConversion, Reader) const std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../" + get<0>(GET_PARAM(2)); const bool videoFullRangeFlag = get<1>(GET_PARAM(2)); cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile); + cv::cudacodec::FormatInfo fmt = reader->format(); + ASSERT_TRUE(fmt.valid); reader->set(colorFormat); cv::VideoCapture cap(inputFile); @@ -322,8 +324,8 @@ CUDA_TEST_P(ColorConversion, Reader) reader->nextFrame(frame); frame.download(frameFromDevice); cap.read(frameHost); - const cv::cudacodec::FormatInfo fmt = reader->format(); - ASSERT_TRUE(fmt.valid && fmt.videoFullRangeFlag == videoFullRangeFlag); + fmt = reader->format(); + ASSERT_TRUE(fmt.videoFullRangeFlag == videoFullRangeFlag); if (colorFormat == cv::cudacodec::ColorFormat::BGRA) cv::cvtColor(frameHost, frameHostGs, COLOR_BGR2BGRA); else @@ -438,11 +440,7 @@ CUDA_TEST_P(CheckDecodeSurfaces, Reader) { cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile); cv::cudacodec::FormatInfo fmt = reader->format(); - if (!fmt.valid) { - reader->grab(); - fmt = reader->format(); - ASSERT_TRUE(fmt.valid); - } + ASSERT_TRUE(fmt.valid); ulNumDecodeSurfaces = fmt.ulNumDecodeSurfaces; } @@ -451,11 +449,7 @@ CUDA_TEST_P(CheckDecodeSurfaces, Reader) params.minNumDecodeSurfaces = ulNumDecodeSurfaces - 1; cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile, {}, params); cv::cudacodec::FormatInfo fmt = reader->format(); - if (!fmt.valid) { - reader->grab(); - fmt = reader->format(); - ASSERT_TRUE(fmt.valid); - } + ASSERT_TRUE(fmt.valid); ASSERT_TRUE(fmt.ulNumDecodeSurfaces == ulNumDecodeSurfaces); for (int i = 0; i < 100; i++) ASSERT_TRUE(reader->grab()); } @@ -465,11 +459,7 @@ CUDA_TEST_P(CheckDecodeSurfaces, Reader) params.minNumDecodeSurfaces = ulNumDecodeSurfaces + 1; cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile, {}, params); cv::cudacodec::FormatInfo fmt = reader->format(); - if (!fmt.valid) { - reader->grab(); - fmt = reader->format(); - ASSERT_TRUE(fmt.valid); - } + ASSERT_TRUE(fmt.valid); ASSERT_TRUE(fmt.ulNumDecodeSurfaces == ulNumDecodeSurfaces + 1); for (int i = 0; i < 100; i++) ASSERT_TRUE(reader->grab()); } @@ -517,16 +507,13 @@ CUDA_TEST_P(TransCode, H264ToH265) { cv::Ptr reader = cv::cudacodec::createVideoReader(inputFile); cv::cudacodec::FormatInfo fmt = reader->format(); + ASSERT_TRUE(fmt.valid); reader->set(cudacodec::ColorFormat::NV_NV12); cv::Ptr writer; cv::cuda::GpuMat frame; cv::cuda::Stream stream; for (int i = 0; i < nFrames; ++i) { ASSERT_TRUE(reader->nextFrame(frame, stream)); - if (!fmt.valid) { - fmt = reader->format(); - ASSERT_TRUE(fmt.valid); - } ASSERT_FALSE(frame.empty()); Mat tst; frame.download(tst); if (writer.empty()) {