Skip to content

Commit 9c4738b

Browse files
authored
Merge pull request #3248 from cudawarped:videoreader_decode_all_to_nv12
Force VideoReader to decode all YUV video formats to NV12 * Force decoding of all supported YUV inputs to NV12 and log warning to indicate this is taking place. Add YUV output. * Update to include missing CUDA stream argument to raw frame copy. * Fix copy paste oversight.
1 parent e72e171 commit 9c4738b

File tree

4 files changed

+45
-12
lines changed

4 files changed

+45
-12
lines changed

modules/cudacodec/include/opencv2/cudacodec.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,13 @@ enum class VideoReaderProps {
326326
#endif
327327
};
328328

329-
/** @brief ColorFormat for the frame returned by the decoder.
329+
/** @brief ColorFormat for the frame returned by nextFrame()/retrieve().
330330
*/
331331
enum class ColorFormat {
332332
BGRA = 1,
333333
BGR = 2,
334334
GRAY = 3,
335+
YUV = 4,
335336
#ifndef CV_DOXYGEN
336337
PROP_NOT_SUPPORTED
337338
#endif
@@ -394,7 +395,11 @@ class CV_EXPORTS_W VideoReader
394395
*/
395396
CV_WRAP virtual bool set(const VideoReaderProps propertyId, const double propertyVal) = 0;
396397

397-
CV_WRAP virtual void set(const ColorFormat _colorFormat) = 0;
398+
/** @brief Set the desired ColorFormat for the frame returned by nextFrame()/retrieve().
399+
400+
@param colorFormat Value of the ColorFormat.
401+
*/
402+
CV_WRAP virtual void set(const ColorFormat colorFormat) = 0;
398403

399404
/** @brief Returns the specified VideoReader property
400405

modules/cudacodec/src/video_decoder.cpp

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,36 @@
4545

4646
#ifdef HAVE_NVCUVID
4747

48+
static const char* GetVideoChromaFormatString(cudaVideoChromaFormat eChromaFormat) {
49+
static struct {
50+
cudaVideoChromaFormat eChromaFormat;
51+
const char* name;
52+
} aChromaFormatName[] = {
53+
{ cudaVideoChromaFormat_Monochrome, "YUV 400 (Monochrome)" },
54+
{ cudaVideoChromaFormat_420, "YUV 420" },
55+
{ cudaVideoChromaFormat_422, "YUV 422" },
56+
{ cudaVideoChromaFormat_444, "YUV 444" },
57+
};
58+
59+
if (eChromaFormat >= 0 && eChromaFormat < sizeof(aChromaFormatName) / sizeof(aChromaFormatName[0])) {
60+
return aChromaFormatName[eChromaFormat].name;
61+
}
62+
return "Unknown";
63+
}
64+
4865
void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat)
4966
{
50-
if (videoFormat.nBitDepthMinus8 > 0 || videoFormat.chromaFormat == YUV444)
51-
CV_Error(Error::StsUnsupportedFormat, "NV12 output currently supported for 8 bit YUV420, YUV422 and Monochrome inputs.");
52-
5367
videoFormat_ = videoFormat;
5468
const cudaVideoCodec _codec = static_cast<cudaVideoCodec>(videoFormat.codec);
5569
const cudaVideoChromaFormat _chromaFormat = static_cast<cudaVideoChromaFormat>(videoFormat.chromaFormat);
70+
if (videoFormat.nBitDepthMinus8 > 0) {
71+
std::ostringstream warning;
72+
warning << "NV12 (8 bit luma, 4 bit chroma) is currently the only supported decoder output format. Video input is " << videoFormat.nBitDepthMinus8 + 8 << " bit " \
73+
<< std::string(GetVideoChromaFormatString(_chromaFormat)) << ". Truncating luma to 8 bits";
74+
if (videoFormat.chromaFormat != YUV420)
75+
warning << " and chroma to 4 bits";
76+
CV_LOG_WARNING(NULL, warning.str());
77+
}
5678
const cudaVideoCreateFlags videoCreateFlags = (_codec == cudaVideoCodec_JPEG || _codec == cudaVideoCodec_MPEG2) ?
5779
cudaVideoCreate_PreferCUDA :
5880
cudaVideoCreate_PreferCUVID;
@@ -98,7 +120,7 @@ void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat)
98120
cuSafeCall(cuCtxPushCurrent(ctx_));
99121
cuSafeCall(cuvidGetDecoderCaps(&decodeCaps));
100122
cuSafeCall(cuCtxPopCurrent(NULL));
101-
if (!decodeCaps.bIsSupported)
123+
if (!(decodeCaps.bIsSupported && (decodeCaps.nOutputFormatMask & (1 << cudaVideoSurfaceFormat_NV12))))
102124
CV_Error(Error::StsUnsupportedFormat, "Video source is not supported by hardware video decoder");
103125

104126
CV_Assert(videoFormat.ulWidth >= decodeCaps.nMinWidth &&
@@ -115,6 +137,7 @@ void cv::cudacodec::detail::VideoDecoder::create(const FormatInfo& videoFormat)
115137
createInfo_.ulHeight = videoFormat.ulHeight;
116138
createInfo_.ulNumDecodeSurfaces = videoFormat.ulNumDecodeSurfaces;
117139
createInfo_.ChromaFormat = _chromaFormat;
140+
createInfo_.bitDepthMinus8 = videoFormat.nBitDepthMinus8;
118141
createInfo_.OutputFormat = cudaVideoSurfaceFormat_NV12;
119142
createInfo_.DeinterlaceMode = static_cast<cudaVideoDeinterlaceMode>(videoFormat.deinterlaceMode);
120143
createInfo_.ulTargetWidth = videoFormat.width;

modules/cudacodec/src/video_reader.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,26 @@ Ptr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>&, co
5656
void nv12ToBgra(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, cudaStream_t stream);
5757

5858
void videoDecPostProcessFrame(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, const ColorFormat colorFormat,
59-
cudaStream_t stream)
59+
Stream stream)
6060
{
6161
if (colorFormat == ColorFormat::BGRA) {
62-
nv12ToBgra(decodedFrame, outFrame, width, height, stream);
62+
nv12ToBgra(decodedFrame, outFrame, width, height, StreamAccessor::getStream(stream));
6363
}
6464
else if (colorFormat == ColorFormat::BGR) {
6565
outFrame.create(height, width, CV_8UC3);
6666
Npp8u* pSrc[2] = { decodedFrame.data, &decodedFrame.data[decodedFrame.step * height] };
6767
NppiSize oSizeROI = { width,height };
6868
NppStreamContext nppStreamCtx;
6969
nppSafeCall(nppGetStreamContext(&nppStreamCtx));
70-
nppStreamCtx.hStream = stream;
70+
nppStreamCtx.hStream = StreamAccessor::getStream(stream);
7171
nppSafeCall(nppiNV12ToBGR_8u_P2C3R_Ctx(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI, nppStreamCtx));
7272
}
7373
else if (colorFormat == ColorFormat::GRAY) {
7474
outFrame.create(height, width, CV_8UC1);
75-
cudaMemcpy2DAsync(outFrame.ptr(), outFrame.step, decodedFrame.ptr(), decodedFrame.step, width, height, cudaMemcpyDeviceToDevice, stream);
75+
cudaMemcpy2DAsync(outFrame.ptr(), outFrame.step, decodedFrame.ptr(), decodedFrame.step, width, height, cudaMemcpyDeviceToDevice, StreamAccessor::getStream(stream));
76+
}
77+
else if (colorFormat == ColorFormat::YUV) {
78+
decodedFrame.copyTo(outFrame, stream);
7679
}
7780
}
7881

@@ -217,7 +220,7 @@ namespace
217220

218221
// perform post processing on the CUDA surface (performs colors space conversion and post processing)
219222
// comment this out if we include the line of code seen above
220-
videoDecPostProcessFrame(decodedFrame, frame, videoDecoder_->targetWidth(), videoDecoder_->targetHeight(), colorFormat, StreamAccessor::getStream(stream));
223+
videoDecPostProcessFrame(decodedFrame, frame, videoDecoder_->targetWidth(), videoDecoder_->targetHeight(), colorFormat, stream);
221224

222225
// unmap video frame
223226
// unmapFrame() synchronizes with the VideoDecode API (ensures the frame has finished decoding)

modules/cudacodec/test/test_video.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ CUDA_TEST_P(Video, Reader)
187187
{cudacodec::ColorFormat::GRAY,1},
188188
{cudacodec::ColorFormat::BGR,3},
189189
{cudacodec::ColorFormat::BGRA,4},
190+
{cudacodec::ColorFormat::YUV,1}
190191
};
191192

192193
std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../" + GET_PARAM(1);
@@ -201,7 +202,8 @@ CUDA_TEST_P(Video, Reader)
201202
ASSERT_TRUE(reader->nextFrame(frame));
202203
if(!fmt.valid)
203204
fmt = reader->format();
204-
ASSERT_TRUE(frame.cols == fmt.width && frame.rows == fmt.height);
205+
const int height = formatToChannels.first == cudacodec::ColorFormat::YUV ? 1.5 * fmt.height : fmt.height;
206+
ASSERT_TRUE(frame.cols == fmt.width && frame.rows == height);
205207
ASSERT_FALSE(frame.empty());
206208
ASSERT_TRUE(frame.channels() == formatToChannels.second);
207209
}

0 commit comments

Comments
 (0)