Skip to content

Commit bfea856

Browse files
committed
cudacodec - Add 10 bit YUV420 and YUV444 encoding functionality
1 parent 89529d7 commit bfea856

File tree

3 files changed

+71
-4
lines changed

3 files changed

+71
-4
lines changed

modules/cudacodec/include/opencv2/cudacodec.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ enum ColorFormat {
106106
NV_IYUV = 9, //!< Nvidia Buffer Format - Planar YUV [Y plane followed by U and V planes]. VideoWriter only.
107107
NV_YUV444 = 10, //!< Nvidia Buffer Format - Planar YUV [Y plane followed by U and V planes]. VideoWriter only.
108108
NV_AYUV = 11, //!< Nvidia Buffer Format - 8 bit Packed A8Y8U8V8. This is a word-ordered format where a pixel is represented by a 32-bit word with V in the lowest 8 bits, U in the next 8 bits, Y in the 8 bits after that and A in the highest 8 bits. VideoWriter only.
109+
NV_YUV420_10BIT = 12, //!< Nvidia Buffer Format - 10 bit Semi-Planar YUV [Y plane followed by interleaved UV plane]. Each pixel of size 2 bytes. Most Significant 10 bits contain pixel data. VideoWriter only.
110+
NV_YUV444_10BIT = 13, //!< Nvidia Buffer Format - 10 bit Planar YUV444 [Y plane followed by U and V planes]. Each pixel of size 2 bytes. Most Significant 10 bits contain pixel data. VideoWriter only.
109111
#ifndef CV_DOXYGEN
110112
PROP_NOT_SUPPORTED
111113
#endif

modules/cudacodec/src/video_writer.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,22 +188,26 @@ NV_ENC_BUFFER_FORMAT EncBufferFormat(const ColorFormat colorFormat) {
188188
case ColorFormat::NV_IYUV: return NV_ENC_BUFFER_FORMAT_IYUV;
189189
case ColorFormat::NV_YUV444: return NV_ENC_BUFFER_FORMAT_YUV444;
190190
case ColorFormat::NV_AYUV: return NV_ENC_BUFFER_FORMAT_AYUV;
191+
case ColorFormat::NV_YUV420_10BIT: return NV_ENC_BUFFER_FORMAT_YUV420_10BIT;
192+
case ColorFormat::NV_YUV444_10BIT: return NV_ENC_BUFFER_FORMAT_YUV444_10BIT;
191193
default: return NV_ENC_BUFFER_FORMAT_UNDEFINED;
192194
}
193195
}
194196

195197
int NChannels(const ColorFormat colorFormat) {
196198
switch (colorFormat) {
197199
case ColorFormat::BGR:
198-
case ColorFormat::RGB:
199-
case ColorFormat::NV_IYUV:
200-
case ColorFormat::NV_YUV444: return 3;
200+
case ColorFormat::RGB: return 3;
201201
case ColorFormat::RGBA:
202202
case ColorFormat::BGRA:
203203
case ColorFormat::NV_AYUV: return 4;
204204
case ColorFormat::GRAY:
205205
case ColorFormat::NV_NV12:
206-
case ColorFormat::NV_YV12: return 1;
206+
case ColorFormat::NV_IYUV:
207+
case ColorFormat::NV_YV12:
208+
case ColorFormat::NV_YUV420_10BIT:
209+
case ColorFormat::NV_YUV444:
210+
case ColorFormat::NV_YUV444_10BIT: return 1;
207211
default: return 0;
208212
}
209213
}

modules/cudacodec/test/test_video.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,67 @@ CUDA_TEST_P(H264ToH265, Transcode)
10651065

10661066
INSTANTIATE_TEST_CASE_P(CUDA_Codec, H264ToH265, ALL_DEVICES);
10671067

1068+
CV_ENUM(YuvColorFormats, cudacodec::ColorFormat::NV_YUV444, cudacodec::ColorFormat::NV_YUV420_10BIT, cudacodec::ColorFormat::NV_YUV444_10BIT)
1069+
PARAM_TEST_CASE(YUVFormats, cv::cuda::DeviceInfo, YuvColorFormats)
1070+
{
1071+
};
1072+
1073+
CUDA_TEST_P(YUVFormats, Transcode)
1074+
{
1075+
cv::cuda::setDevice(GET_PARAM(0).deviceID());
1076+
const std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../highgui/video/big_buck_bunny.h265";
1077+
const cv::cudacodec::ColorFormat writerColorFormat = static_cast<cudacodec::ColorFormat>(static_cast<int>(GET_PARAM(1)));
1078+
constexpr double fps = 25;
1079+
const cudacodec::Codec codec = cudacodec::Codec::HEVC;
1080+
const std::string ext = ".mp4";
1081+
const std::string outputFile = cv::tempfile(ext.c_str());
1082+
constexpr int nFrames = 5;
1083+
vector<Mat> bgrGs;
1084+
{
1085+
VideoCapture cap(inputFile);
1086+
cv::Ptr<cv::cudacodec::VideoWriter> writer;
1087+
Mat frame, yuv, bgr;
1088+
cv::cudacodec::EncoderParams params;
1089+
params.tuningInfo = cv::cudacodec::EncodeTuningInfo::ENC_TUNING_INFO_LOSSLESS;
1090+
params.rateControlMode = cv::cudacodec::EncodeParamsRcMode::ENC_PARAMS_RC_CONSTQP;
1091+
for (int i = 0; i < nFrames; ++i) {
1092+
ASSERT_TRUE(cap.read(frame));
1093+
ASSERT_FALSE(frame.empty());
1094+
cudacodec::SurfaceFormat yuvFormat = cudacodec::SurfaceFormat::SF_YUV444;
1095+
cudacodec::BitDepth bitDepth = cudacodec::BitDepth::EIGHT;
1096+
if (writerColorFormat == cudacodec::ColorFormat::NV_YUV444_10BIT) {
1097+
yuvFormat = cudacodec::SurfaceFormat::SF_YUV444_16Bit;
1098+
bitDepth = cudacodec::BitDepth::SIXTEEN;
1099+
}
1100+
else if (writerColorFormat == cudacodec::ColorFormat::NV_YUV420_10BIT){
1101+
yuvFormat = cudacodec::SurfaceFormat::SF_P016;
1102+
bitDepth = cudacodec::BitDepth::SIXTEEN;
1103+
}
1104+
generateTestImages(frame, yuv, bgr, yuvFormat, cudacodec::ColorFormat::BGR, bitDepth, false);
1105+
bgrGs.push_back(bgr.clone());
1106+
if (writer.empty())
1107+
writer = cv::cudacodec::createVideoWriter(outputFile, frame.size(), codec, fps, writerColorFormat, params);
1108+
writer->write(yuv);
1109+
}
1110+
}
1111+
1112+
{
1113+
cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(outputFile);
1114+
reader->set(cudacodec::ColorFormat::BGR);
1115+
cv::cuda::GpuMat frame, frameGs;
1116+
Mat frameHost, frameGsHost;
1117+
for (int i = 0; i < nFrames; ++i) {
1118+
ASSERT_TRUE(reader->nextFrame(frame));
1119+
frame.download(frameHost);
1120+
frameGsHost = bgrGs[i];
1121+
const int diff = writerColorFormat == cudacodec::ColorFormat::NV_YUV420_10BIT || writerColorFormat == cudacodec::ColorFormat::NV_YUV444_10BIT ? 512 : 1;
1122+
EXPECT_MAT_NEAR(frameHost, frameGsHost, diff);
1123+
}
1124+
}
1125+
ASSERT_EQ(0, remove(outputFile.c_str()));
1126+
}
1127+
1128+
INSTANTIATE_TEST_CASE_P(CUDA_Codec, YUVFormats, testing::Combine(ALL_DEVICES, YuvColorFormats::all()));
10681129
#endif
10691130

10701131
#if defined(HAVE_NVCUVENC)

0 commit comments

Comments
 (0)