mirror of
https://github.com/opencv/opencv_contrib.git
synced 2025-10-20 04:25:42 +08:00
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
This commit is contained in:
@@ -320,6 +320,18 @@ enum class VideoReaderProps {
|
|||||||
PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB = 3, //!< Number of raw packages recieved since the last call to grab().
|
PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB = 3, //!< Number of raw packages recieved since the last call to grab().
|
||||||
PROP_RAW_MODE = 4, //!< Status of raw mode.
|
PROP_RAW_MODE = 4, //!< Status of raw mode.
|
||||||
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.
|
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.
|
||||||
|
PROP_COLOR_FORMAT = 6, //!< Set the ColorFormat of the decoded frame. This can be changed before every call to nextFrame() and retrieve().
|
||||||
|
#ifndef CV_DOXYGEN
|
||||||
|
PROP_NOT_SUPPORTED
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief ColorFormat for the frame returned by the decoder.
|
||||||
|
*/
|
||||||
|
enum class ColorFormat {
|
||||||
|
BGRA = 1,
|
||||||
|
BGR = 2,
|
||||||
|
GRAY = 3,
|
||||||
#ifndef CV_DOXYGEN
|
#ifndef CV_DOXYGEN
|
||||||
PROP_NOT_SUPPORTED
|
PROP_NOT_SUPPORTED
|
||||||
#endif
|
#endif
|
||||||
@@ -382,6 +394,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
CV_WRAP virtual bool set(const VideoReaderProps propertyId, const double propertyVal) = 0;
|
CV_WRAP virtual bool set(const VideoReaderProps propertyId, const double propertyVal) = 0;
|
||||||
|
|
||||||
|
CV_WRAP virtual void set(const ColorFormat _colorFormat) = 0;
|
||||||
|
|
||||||
/** @brief Returns the specified VideoReader property
|
/** @brief Returns the specified VideoReader property
|
||||||
|
|
||||||
@param propertyId Property identifier from cv::cudacodec::VideoReaderProps (eg. cv::cudacodec::VideoReaderProps::PROP_DECODED_FRAME_IDX,
|
@param propertyId Property identifier from cv::cudacodec::VideoReaderProps (eg. cv::cudacodec::VideoReaderProps::PROP_DECODED_FRAME_IDX,
|
||||||
|
@@ -60,7 +60,7 @@
|
|||||||
using namespace cv;
|
using namespace cv;
|
||||||
using namespace cv::cudev;
|
using namespace cv::cudev;
|
||||||
|
|
||||||
void videoDecPostProcessFrame(const GpuMat& decodedFrame, GpuMat& _outFrame, int width, int height, cudaStream_t stream);
|
void nv12ToBgra(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, cudaStream_t stream);
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@@ -112,7 +112,7 @@ namespace
|
|||||||
#define COLOR_COMPONENT_BIT_SIZE 10
|
#define COLOR_COMPONENT_BIT_SIZE 10
|
||||||
#define COLOR_COMPONENT_MASK 0x3FF
|
#define COLOR_COMPONENT_MASK 0x3FF
|
||||||
|
|
||||||
__global__ void NV12_to_RGB(const uchar* srcImage, size_t nSourcePitch,
|
__global__ void NV12_to_BGRA(const uchar* srcImage, size_t nSourcePitch,
|
||||||
uint* dstImage, size_t nDestPitch,
|
uint* dstImage, size_t nDestPitch,
|
||||||
uint width, uint height)
|
uint width, uint height)
|
||||||
{
|
{
|
||||||
@@ -186,19 +186,13 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void videoDecPostProcessFrame(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, cudaStream_t stream)
|
void nv12ToBgra(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, cudaStream_t stream)
|
||||||
{
|
{
|
||||||
// Final Stage: NV12toARGB color space conversion
|
|
||||||
|
|
||||||
outFrame.create(height, width, CV_8UC4);
|
outFrame.create(height, width, CV_8UC4);
|
||||||
|
|
||||||
dim3 block(32, 8);
|
dim3 block(32, 8);
|
||||||
dim3 grid(divUp(width, 2 * block.x), divUp(height, block.y));
|
dim3 grid(divUp(width, 2 * block.x), divUp(height, block.y));
|
||||||
|
NV12_to_BGRA<< <grid, block, 0, stream >> > (decodedFrame.ptr<uchar>(), decodedFrame.step,
|
||||||
NV12_to_RGB<<<grid, block, 0, stream>>>(decodedFrame.ptr<uchar>(), decodedFrame.step,
|
outFrame.ptr<uint>(), outFrame.step, width, height);
|
||||||
outFrame.ptr<uint>(), outFrame.step,
|
|
||||||
width, height);
|
|
||||||
|
|
||||||
CV_CUDEV_SAFE_CALL(cudaGetLastError());
|
CV_CUDEV_SAFE_CALL(cudaGetLastError());
|
||||||
if (stream == 0)
|
if (stream == 0)
|
||||||
CV_CUDEV_SAFE_CALL(cudaDeviceSynchronize());
|
CV_CUDEV_SAFE_CALL(cudaDeviceSynchronize());
|
||||||
|
@@ -53,7 +53,28 @@ Ptr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>&, co
|
|||||||
|
|
||||||
#else // HAVE_NVCUVID
|
#else // HAVE_NVCUVID
|
||||||
|
|
||||||
void videoDecPostProcessFrame(const GpuMat& decodedFrame, GpuMat& _outFrame, int width, int height, cudaStream_t stream);
|
void nv12ToBgra(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, cudaStream_t stream);
|
||||||
|
|
||||||
|
void videoDecPostProcessFrame(const GpuMat& decodedFrame, GpuMat& outFrame, int width, int height, const ColorFormat colorFormat,
|
||||||
|
cudaStream_t stream)
|
||||||
|
{
|
||||||
|
if (colorFormat == ColorFormat::BGRA) {
|
||||||
|
nv12ToBgra(decodedFrame, outFrame, width, height, stream);
|
||||||
|
}
|
||||||
|
else if (colorFormat == ColorFormat::BGR) {
|
||||||
|
outFrame.create(height, width, CV_8UC3);
|
||||||
|
Npp8u* pSrc[2] = { decodedFrame.data, &decodedFrame.data[decodedFrame.step * height] };
|
||||||
|
NppiSize oSizeROI = { width,height };
|
||||||
|
NppStreamContext nppStreamCtx;
|
||||||
|
nppSafeCall(nppGetStreamContext(&nppStreamCtx));
|
||||||
|
nppStreamCtx.hStream = stream;
|
||||||
|
nppSafeCall(nppiNV12ToBGR_8u_P2C3R_Ctx(pSrc, decodedFrame.step, outFrame.data, outFrame.step, oSizeROI, nppStreamCtx));
|
||||||
|
}
|
||||||
|
else if (colorFormat == ColorFormat::GRAY) {
|
||||||
|
outFrame.create(height, width, CV_8UC1);
|
||||||
|
cudaMemcpy2DAsync(outFrame.ptr(), outFrame.step, decodedFrame.ptr(), decodedFrame.step, width, height, cudaMemcpyDeviceToDevice, stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using namespace cv::cudacodec::detail;
|
using namespace cv::cudacodec::detail;
|
||||||
|
|
||||||
@@ -75,6 +96,8 @@ namespace
|
|||||||
|
|
||||||
bool set(const VideoReaderProps propertyId, const double propertyVal) CV_OVERRIDE;
|
bool set(const VideoReaderProps propertyId, const double propertyVal) CV_OVERRIDE;
|
||||||
|
|
||||||
|
void VideoReaderImpl::set(const ColorFormat _colorFormat) CV_OVERRIDE;
|
||||||
|
|
||||||
bool get(const VideoReaderProps propertyId, double& propertyVal) const CV_OVERRIDE;
|
bool get(const VideoReaderProps propertyId, double& propertyVal) const CV_OVERRIDE;
|
||||||
|
|
||||||
bool get(const int propertyId, double& propertyVal) const CV_OVERRIDE;
|
bool get(const int propertyId, double& propertyVal) const CV_OVERRIDE;
|
||||||
@@ -96,6 +119,7 @@ namespace
|
|||||||
static const int decodedFrameIdx = 0;
|
static const int decodedFrameIdx = 0;
|
||||||
static const int extraDataIdx = 1;
|
static const int extraDataIdx = 1;
|
||||||
static const int rawPacketsBaseIdx = 2;
|
static const int rawPacketsBaseIdx = 2;
|
||||||
|
ColorFormat colorFormat = ColorFormat::BGRA;
|
||||||
};
|
};
|
||||||
|
|
||||||
FormatInfo VideoReaderImpl::format() const
|
FormatInfo VideoReaderImpl::format() const
|
||||||
@@ -193,7 +217,7 @@ namespace
|
|||||||
|
|
||||||
// perform post processing on the CUDA surface (performs colors space conversion and post processing)
|
// perform post processing on the CUDA surface (performs colors space conversion and post processing)
|
||||||
// comment this out if we include the line of code seen above
|
// comment this out if we include the line of code seen above
|
||||||
videoDecPostProcessFrame(decodedFrame, frame, videoDecoder_->targetWidth(), videoDecoder_->targetHeight(), StreamAccessor::getStream(stream));
|
videoDecPostProcessFrame(decodedFrame, frame, videoDecoder_->targetWidth(), videoDecoder_->targetHeight(), colorFormat, StreamAccessor::getStream(stream));
|
||||||
|
|
||||||
// unmap video frame
|
// unmap video frame
|
||||||
// unmapFrame() synchronizes with the VideoDecode API (ensures the frame has finished decoding)
|
// unmapFrame() synchronizes with the VideoDecode API (ensures the frame has finished decoding)
|
||||||
@@ -237,11 +261,14 @@ namespace
|
|||||||
switch (propertyId) {
|
switch (propertyId) {
|
||||||
case VideoReaderProps::PROP_RAW_MODE :
|
case VideoReaderProps::PROP_RAW_MODE :
|
||||||
videoSource_->SetRawMode(static_cast<bool>(propertyVal));
|
videoSource_->SetRawMode(static_cast<bool>(propertyVal));
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VideoReaderImpl::set(const ColorFormat _colorFormat) {
|
||||||
|
colorFormat = _colorFormat;
|
||||||
|
}
|
||||||
|
|
||||||
bool VideoReaderImpl::get(const VideoReaderProps propertyId, double& propertyVal) const {
|
bool VideoReaderImpl::get(const VideoReaderProps propertyId, double& propertyVal) const {
|
||||||
switch (propertyId)
|
switch (propertyId)
|
||||||
{
|
{
|
||||||
|
@@ -183,17 +183,27 @@ CUDA_TEST_P(Video, Reader)
|
|||||||
if (GET_PARAM(1) == "cv/video/768x576.avi" && !videoio_registry::hasBackend(CAP_FFMPEG))
|
if (GET_PARAM(1) == "cv/video/768x576.avi" && !videoio_registry::hasBackend(CAP_FFMPEG))
|
||||||
throw SkipTestException("FFmpeg backend not found");
|
throw SkipTestException("FFmpeg backend not found");
|
||||||
|
|
||||||
|
const std::vector<std::pair< cudacodec::ColorFormat, int>> formatsToChannels = {
|
||||||
|
{cudacodec::ColorFormat::GRAY,1},
|
||||||
|
{cudacodec::ColorFormat::BGR,3},
|
||||||
|
{cudacodec::ColorFormat::BGRA,4},
|
||||||
|
};
|
||||||
|
|
||||||
std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../" + GET_PARAM(1);
|
std::string inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "../" + GET_PARAM(1);
|
||||||
cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(inputFile);
|
cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(inputFile);
|
||||||
cv::cudacodec::FormatInfo fmt = reader->format();
|
cv::cudacodec::FormatInfo fmt = reader->format();
|
||||||
cv::cuda::GpuMat frame;
|
cv::cuda::GpuMat frame;
|
||||||
for (int i = 0; i < 100; i++)
|
for (int i = 0; i < 100; i++)
|
||||||
{
|
{
|
||||||
|
// request a different colour format for each frame
|
||||||
|
const std::pair< cudacodec::ColorFormat, int>& formatToChannels = formatsToChannels[i % formatsToChannels.size()];
|
||||||
|
reader->set(formatToChannels.first);
|
||||||
ASSERT_TRUE(reader->nextFrame(frame));
|
ASSERT_TRUE(reader->nextFrame(frame));
|
||||||
if(!fmt.valid)
|
if(!fmt.valid)
|
||||||
fmt = reader->format();
|
fmt = reader->format();
|
||||||
ASSERT_TRUE(frame.cols == fmt.width && frame.rows == fmt.height);
|
ASSERT_TRUE(frame.cols == fmt.width && frame.rows == fmt.height);
|
||||||
ASSERT_FALSE(frame.empty());
|
ASSERT_FALSE(frame.empty());
|
||||||
|
ASSERT_TRUE(frame.channels() == formatToChannels.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user