Skip to content

Commit 1490611

Browse files
authored
Merge pull request #3198 from cudawarped:cudacodec_add_frame_colour_format_request
cudacodec::VideoReader add colour format selection functionality * Add capacity to select different colour formats for each decoded frame produced by cudacodec::VideoReader. Updated accompanying test. * Address warning
1 parent ed38f75 commit 1490611

File tree

4 files changed

+61
-16
lines changed

4 files changed

+61
-16
lines changed

modules/cudacodec/include/opencv2/cudacodec.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,18 @@ enum class VideoReaderProps {
320320
PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB = 3, //!< Number of raw packages recieved since the last call to grab().
321321
PROP_RAW_MODE = 4, //!< Status of raw mode.
322322
PROP_LRF_HAS_KEY_FRAME = 5, //!< FFmpeg source only - Indicates whether the Last Raw Frame (LRF), output from VideoReader::retrieve() when VideoReader is initialized in raw mode, contains encoded data for a key frame.
323+
PROP_COLOR_FORMAT = 6, //!< Set the ColorFormat of the decoded frame. This can be changed before every call to nextFrame() and retrieve().
324+
#ifndef CV_DOXYGEN
325+
PROP_NOT_SUPPORTED
326+
#endif
327+
};
328+
329+
/** @brief ColorFormat for the frame returned by the decoder.
330+
*/
331+
enum class ColorFormat {
332+
BGRA = 1,
333+
BGR = 2,
334+
GRAY = 3,
323335
#ifndef CV_DOXYGEN
324336
PROP_NOT_SUPPORTED
325337
#endif
@@ -382,6 +394,8 @@ class CV_EXPORTS_W VideoReader
382394
*/
383395
CV_WRAP virtual bool set(const VideoReaderProps propertyId, const double propertyVal) = 0;
384396

397+
CV_WRAP virtual void set(const ColorFormat _colorFormat) = 0;
398+
385399
/** @brief Returns the specified VideoReader property
386400
387401
@param propertyId Property identifier from cv::cudacodec::VideoReaderProps (eg. cv::cudacodec::VideoReaderProps::PROP_DECODED_FRAME_IDX,

modules/cudacodec/src/cuda/nv12_to_rgb.cu

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
using namespace cv;
6161
using namespace cv::cudev;
6262

63-
void videoDecPostProcessFrame(const GpuMat& decodedFrame, GpuMat& _outFrame, int width, int height, cudaStream_t stream);
63+
void nv12ToBgra(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, cudaStream_t stream);
6464

6565
namespace
6666
{
@@ -112,7 +112,7 @@ namespace
112112
#define COLOR_COMPONENT_BIT_SIZE 10
113113
#define COLOR_COMPONENT_MASK 0x3FF
114114

115-
__global__ void NV12_to_RGB(const uchar* srcImage, size_t nSourcePitch,
115+
__global__ void NV12_to_BGRA(const uchar* srcImage, size_t nSourcePitch,
116116
uint* dstImage, size_t nDestPitch,
117117
uint width, uint height)
118118
{
@@ -186,22 +186,16 @@ namespace
186186
}
187187
}
188188

189-
void videoDecPostProcessFrame(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, cudaStream_t stream)
189+
void nv12ToBgra(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, cudaStream_t stream)
190190
{
191-
// Final Stage: NV12toARGB color space conversion
192-
193191
outFrame.create(height, width, CV_8UC4);
194-
195192
dim3 block(32, 8);
196193
dim3 grid(divUp(width, 2 * block.x), divUp(height, block.y));
197-
198-
NV12_to_RGB<<<grid, block, 0, stream>>>(decodedFrame.ptr<uchar>(), decodedFrame.step,
199-
outFrame.ptr<uint>(), outFrame.step,
200-
width, height);
201-
202-
CV_CUDEV_SAFE_CALL( cudaGetLastError() );
194+
NV12_to_BGRA<< <grid, block, 0, stream >> > (decodedFrame.ptr<uchar>(), decodedFrame.step,
195+
outFrame.ptr<uint>(), outFrame.step, width, height);
196+
CV_CUDEV_SAFE_CALL(cudaGetLastError());
203197
if (stream == 0)
204-
CV_CUDEV_SAFE_CALL( cudaDeviceSynchronize() );
198+
CV_CUDEV_SAFE_CALL(cudaDeviceSynchronize());
205199
}
206200

207201
#endif

modules/cudacodec/src/video_reader.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,28 @@ Ptr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>&, co
5353

5454
#else // HAVE_NVCUVID
5555

56-
void videoDecPostProcessFrame(const GpuMat& decodedFrame, GpuMat& _outFrame, int width, int height, cudaStream_t stream);
56+
void nv12ToBgra(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, cudaStream_t stream);
57+
58+
void videoDecPostProcessFrame(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, const ColorFormat colorFormat,
59+
cudaStream_t stream)
60+
{
61+
if (colorFormat == ColorFormat::BGRA) {
62+
nv12ToBgra(decodedFrame, outFrame, width, height, stream);
63+
}
64+
else if (colorFormat == ColorFormat::BGR) {
65+
outFrame.create(height, width, CV_8UC3);
66+
Npp8u* pSrc[2] = { decodedFrame.data, &decodedFrame.data[decodedFrame.step * height] };
67+
NppiSize oSizeROI = { width,height };
68+
NppStreamContext nppStreamCtx;
69+
nppSafeCall(nppGetStreamContext(&nppStreamCtx));
70+
nppStreamCtx.hStream = stream;
71+
nppSafeCall(nppiNV12ToBGR_8u_P2C3R_Ctx(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI, nppStreamCtx));
72+
}
73+
else if (colorFormat == ColorFormat::GRAY) {
74+
outFrame.create(height, width, CV_8UC1);
75+
cudaMemcpy2DAsync(outFrame.ptr(), outFrame.step, decodedFrame.ptr(), decodedFrame.step, width, height, cudaMemcpyDeviceToDevice, stream);
76+
}
77+
}
5778

5879
using namespace cv::cudacodec::detail;
5980

@@ -75,6 +96,8 @@ namespace
7596

7697
bool set(const VideoReaderProps propertyId, const double propertyVal) CV_OVERRIDE;
7798

99+
void VideoReaderImpl::set(const ColorFormat _colorFormat) CV_OVERRIDE;
100+
78101
bool get(const VideoReaderProps propertyId, double& propertyVal) const CV_OVERRIDE;
79102

80103
bool get(const int propertyId, double& propertyVal) const CV_OVERRIDE;
@@ -96,6 +119,7 @@ namespace
96119
static const int decodedFrameIdx = 0;
97120
static const int extraDataIdx = 1;
98121
static const int rawPacketsBaseIdx = 2;
122+
ColorFormat colorFormat = ColorFormat::BGRA;
99123
};
100124

101125
FormatInfo VideoReaderImpl::format() const
@@ -193,7 +217,7 @@ namespace
193217

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

198222
// unmap video frame
199223
// unmapFrame() synchronizes with the VideoDecode API (ensures the frame has finished decoding)
@@ -237,11 +261,14 @@ namespace
237261
switch (propertyId) {
238262
case VideoReaderProps::PROP_RAW_MODE :
239263
videoSource_->SetRawMode(static_cast<bool>(propertyVal));
240-
break;
241264
}
242265
return true;
243266
}
244267

268+
void VideoReaderImpl::set(const ColorFormat _colorFormat) {
269+
colorFormat = _colorFormat;
270+
}
271+
245272
bool VideoReaderImpl::get(const VideoReaderProps propertyId, double& propertyVal) const {
246273
switch (propertyId)
247274
{

modules/cudacodec/test/test_video.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,17 +183,27 @@ CUDA_TEST_P(Video, Reader)
183183
if (GET_PARAM(1) == "cv/video/768x576.avi" && !videoio_registry::hasBackend(CAP_FFMPEG))
184184
throw SkipTestException("FFmpeg backend not found");
185185

186+
const std::vector<std::pair< cudacodec::ColorFormat, int>> formatsToChannels = {
187+
{cudacodec::ColorFormat::GRAY,1},
188+
{cudacodec::ColorFormat::BGR,3},
189+
{cudacodec::ColorFormat::BGRA,4},
190+
};
191+
186192
std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../" + GET_PARAM(1);
187193
cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(inputFile);
188194
cv::cudacodec::FormatInfo fmt = reader->format();
189195
cv::cuda::GpuMat frame;
190196
for (int i = 0; i < 100; i++)
191197
{
198+
// request a different colour format for each frame
199+
const std::pair< cudacodec::ColorFormat, int>& formatToChannels = formatsToChannels[i % formatsToChannels.size()];
200+
reader->set(formatToChannels.first);
192201
ASSERT_TRUE(reader->nextFrame(frame));
193202
if(!fmt.valid)
194203
fmt = reader->format();
195204
ASSERT_TRUE(frame.cols == fmt.width && frame.rows == fmt.height);
196205
ASSERT_FALSE(frame.empty());
206+
ASSERT_TRUE(frame.channels() == formatToChannels.second);
197207
}
198208
}
199209

0 commit comments

Comments
 (0)