Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
cudawarped committed Aug 2, 2023
1 parent 2526e88 commit d7c3402
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 16 deletions.
44 changes: 43 additions & 1 deletion modules/cudacodec/include/opencv2/cudacodec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ struct CV_EXPORTS_W_SIMPLE FormatInfo
/** @brief cv::cudacodec::VideoReader generic properties identifier.
*/
enum class VideoReaderProps {
PROP_DECODED_FRAME_IDX = 0, //!< Index for retrieving the decoded frame using retrieve().
PROP_EXTRA_DATA_INDEX = 1, //!< Index for retrieving the extra data associated with a video source using retrieve().
PROP_RAW_PACKAGES_BASE_INDEX = 2, //!< Base index for retrieving raw encoded data using retrieve().
PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB = 3, //!< Number of raw packages recieved since the last call to grab().
Expand Down Expand Up @@ -378,9 +379,36 @@ class CV_EXPORTS_W VideoReader
*/
CV_WRAP virtual FormatInfo format() const = 0;

/** @brief Grabs the next frame from the video source.
@param stream Stream for the asynchronous version.
@return `true` (non-zero) in the case of success.
The method/function grabs the next frame from video file or camera and returns true (non-zero) in
the case of success.
The primary use of the function is for reading both the encoded and decoded video data when rawMode is enabled. With rawMode enabled
retrieve() can be called following grab() to retrieve all the data associated with the current video source since the last call to grab() or the creation of the VideoReader.
*/
CV_WRAP virtual bool grab(Stream& stream = Stream::Null()) = 0;

/** @brief Returns previously grabbed video data.
@param [out] frame The returned data which depends on the provided idx.
@param idx Determines the returned data inside image. The returned data can be the:
- Decoded frame, idx = get(PROP_DECODED_FRAME_IDX).
- Extra data if available, idx = get(PROP_EXTRA_DATA_INDEX).
- Raw encoded data package. To retrieve package i, idx = get(PROP_RAW_PACKAGES_BASE_INDEX) + i with i < get(PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB)
@return `false` if no frames have been grabbed
The method returns data associated with the current video source since the last call to grab() or the creation of the VideoReader. If no data is present
the method returns false and the function returns an empty image.
*/
virtual bool retrieve(OutputArray frame, const size_t idx = static_cast<size_t>(VideoReaderProps::PROP_DECODED_FRAME_IDX)) const = 0;

/** @brief Returns previously grabbed encoded video data.
@param [out] frame The encoded video data.
@param idx Determines the returned data inside image. The returned data can be the:
- Extra data if available, idx = get(PROP_EXTRA_DATA_INDEX).
- Raw encoded data package. To retrieve package i, idx = get(PROP_RAW_PACKAGES_BASE_INDEX) + i with i < get(PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB)
Expand All @@ -389,7 +417,21 @@ class CV_EXPORTS_W VideoReader
The method returns data associated with the current video source since the last call to grab() or the creation of the VideoReader. If no data is present
the method returns false and the function returns an empty image.
*/
CV_WRAP virtual bool retrieve(OutputArray frame, const size_t idx) const = 0;
CV_WRAP inline bool retrieve(CV_OUT Mat& frame, const size_t idx) const {
return retrieve(OutputArray(frame), idx);
}

/** @brief Returns the next video frame.
@param [out] frame The video frame. If grab() has not been called then this will be empty().
@return `false` if no frames have been grabbed
The method returns data associated with the current video source since the last call to grab(). If no data is present
the method returns false and the function returns an empty image.
*/
CV_WRAP inline bool retrieve(CV_OUT GpuMat& frame) const {
return retrieve(OutputArray(frame));
}

/** @brief Sets a property in the VideoReader.
Expand Down
2 changes: 2 additions & 0 deletions modules/cudacodec/misc/python/test/test_cudacodec.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ def test_reader(self):
self.assertTrue(ret and i_base == 2.0)
ret, gpu_mat3 = reader.nextFrame()
self.assertTrue(ret and isinstance(gpu_mat3,cv.cuda.GpuMat) and not gpu_mat3.empty())
ret = reader.retrieve(gpu_mat3)
self.assertTrue(ret and isinstance(gpu_mat3,cv.cuda.GpuMat) and not gpu_mat3.empty())
ret, n_raw_packages_since_last_grab = reader.getVideoReaderProps(cv.cudacodec.VideoReaderProps_PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB)
self.assertTrue(ret and n_raw_packages_since_last_grab > 0)
self.assertTrue(reader.rawPackageHasKeyFrame(int(i_base)))
Expand Down
26 changes: 24 additions & 2 deletions modules/cudacodec/src/video_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ namespace

FormatInfo format() const CV_OVERRIDE;

bool grab(Stream& stream) CV_OVERRIDE;

bool retrieve(OutputArray frame, const size_t idx) const CV_OVERRIDE;

bool set(const VideoReaderProps propertyId, const double propertyVal) CV_OVERRIDE;
Expand All @@ -134,6 +136,7 @@ namespace
bool rawPackageHasKeyFrame(const size_t idx) const CV_OVERRIDE;

private:
bool internalGrab(GpuMat& frame, Stream& stream);
void waitForDecoderInit();

Ptr<VideoSource> videoSource_;
Expand Down Expand Up @@ -204,7 +207,7 @@ namespace
CUvideoctxlock m_lock;
};

bool VideoReaderImpl::nextFrame(GpuMat& frame, Stream& stream) {
bool VideoReaderImpl::internalGrab(GpuMat& frame, Stream& stream) {
if (videoParser_->hasError())
CV_Error(Error::StsError, "Parsing/Decoding video source failed, check GPU memory is available and GPU supports hardware decoding.");

Expand Down Expand Up @@ -272,8 +275,17 @@ namespace
return true;
}

bool VideoReaderImpl::grab(Stream& stream) {
return internalGrab(lastFrame, stream);
}

bool VideoReaderImpl::retrieve(OutputArray frame, const size_t idx) const {
if (idx == extraDataIdx) {
if (idx == decodedFrameIdx) {
if (!frame.isGpuMat())
CV_Error(Error::StsUnsupportedFormat, "Decoded frame is stored on the device and must be retrieved using a cv::cuda::GpuMat");
frame.getGpuMatRef() = lastFrame;
}
else if (idx == extraDataIdx) {
if (!frame.isMat())
CV_Error(Error::StsUnsupportedFormat, "Extra data is stored on the host and must be retrieved using a cv::Mat");
videoSource_->getExtraData(frame.getMatRef());
Expand Down Expand Up @@ -326,6 +338,9 @@ namespace
bool VideoReaderImpl::get(const VideoReaderProps propertyId, size_t& propertyVal) const {
switch (propertyId)
{
case VideoReaderProps::PROP_DECODED_FRAME_IDX:
propertyVal = decodedFrameIdx;
return true;
case VideoReaderProps::PROP_EXTRA_DATA_INDEX:
propertyVal = extraDataIdx;
return true;
Expand Down Expand Up @@ -369,6 +384,13 @@ namespace
bool VideoReaderImpl::get(const int propertyId, double& propertyVal) const {
return videoSource_->get(propertyId, propertyVal);
}

bool VideoReaderImpl::nextFrame(GpuMat& frame, Stream& stream)
{
if (!internalGrab(frame, stream))
return false;
return true;
}
}

Ptr<VideoReader> cv::cudacodec::createVideoReader(const String& filename, const std::vector<int>& sourceParams, const VideoReaderInitParams params)
Expand Down
26 changes: 13 additions & 13 deletions modules/cudacodec/test/test_video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,8 @@ CUDA_TEST_P(CheckSet, Reader)
ASSERT_TRUE(reader->get(cv::cudacodec::VideoReaderProps::PROP_RAW_MODE, rawModeVal));
ASSERT_TRUE(rawModeVal);
bool rawPacketsAvailable = false;
GpuMat frame;
while (reader->nextFrame(frame)) {
size_t nRawPackages = 0;
while (reader->grab()) {
double nRawPackages = -1;
ASSERT_TRUE(reader->get(cv::cudacodec::VideoReaderProps::PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB, nRawPackages));
if (nRawPackages > 0) {
rawPacketsAvailable = true;
Expand All @@ -160,8 +159,7 @@ CUDA_TEST_P(CheckExtraData, Reader)
size_t extraDataIdx = 0;
ASSERT_TRUE(reader->get(cv::cudacodec::VideoReaderProps::PROP_EXTRA_DATA_INDEX, extraDataIdx));
ASSERT_EQ(extraDataIdx, static_cast<size_t>(1) );
GpuMat frame;
ASSERT_TRUE(reader->nextFrame(frame));
ASSERT_TRUE(reader->grab());
cv::Mat extraData;
const bool newData = reader->retrieve(extraData, extraDataIdx);
ASSERT_TRUE((newData && sz) || (!newData && !sz));
Expand All @@ -186,9 +184,8 @@ CUDA_TEST_P(CheckKeyFrame, Reader)
ASSERT_EQ(rawIdxBase, static_cast<size_t>(2));
constexpr int maxNPackagesToCheck = 2;
int nPackages = 0;
GpuMat frame;
while (nPackages < maxNPackagesToCheck) {
ASSERT_TRUE(reader->nextFrame(frame));
ASSERT_TRUE(reader->grab());
size_t N = 0;
ASSERT_TRUE(reader->get(cv::cudacodec::VideoReaderProps::PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB,N));
for (size_t i = rawIdxBase; i < N + rawIdxBase; i++) {
Expand Down Expand Up @@ -441,7 +438,8 @@ CUDA_TEST_P(VideoReadRaw, Reader)
cv::cuda::GpuMat frame;
for (int i = 0; i < 100; i++)
{
ASSERT_TRUE(reader->nextFrame(frame));
ASSERT_TRUE(reader->grab());
ASSERT_TRUE(reader->retrieve(frame));
ASSERT_FALSE(frame.empty());
size_t N = 0;
ASSERT_TRUE(reader->get(cv::cudacodec::VideoReaderProps::PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB, N));
Expand All @@ -460,12 +458,16 @@ CUDA_TEST_P(VideoReadRaw, Reader)
cv::cudacodec::VideoReaderInitParams params;
params.rawMode = true;
cv::Ptr<cv::cudacodec::VideoReader> readerActual = cv::cudacodec::createVideoReader(fileNameOut, {}, params);
double decodedFrameIdx = -1;
ASSERT_TRUE(readerActual->get(cv::cudacodec::VideoReaderProps::PROP_DECODED_FRAME_IDX, decodedFrameIdx));
ASSERT_EQ(decodedFrameIdx, 0);
cv::cuda::GpuMat reference, actual;
cv::Mat referenceHost, actualHost;
for (int i = 0; i < 100; i++)
{
ASSERT_TRUE(readerReference->nextFrame(reference));
ASSERT_TRUE(readerActual->nextFrame(actual));
ASSERT_TRUE(readerActual->grab());
ASSERT_TRUE(readerActual->retrieve(actual, static_cast<size_t>(decodedFrameIdx)));
actual.download(actualHost);
reference.download(referenceHost);
ASSERT_TRUE(cvtest::norm(actualHost, referenceHost, NORM_INF) == 0);
Expand Down Expand Up @@ -541,8 +543,7 @@ CUDA_TEST_P(CheckDecodeSurfaces, Reader)
cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(inputFile, {}, params);
cv::cudacodec::FormatInfo fmt = reader->format();
ASSERT_TRUE(fmt.ulNumDecodeSurfaces == ulNumDecodeSurfaces);
GpuMat frame;
for (int i = 0; i < 100; i++) ASSERT_TRUE(reader->nextFrame(frame));
for (int i = 0; i < 100; i++) ASSERT_TRUE(reader->grab());
}

{
Expand All @@ -551,8 +552,7 @@ CUDA_TEST_P(CheckDecodeSurfaces, Reader)
cv::Ptr<cv::cudacodec::VideoReader> reader = cv::cudacodec::createVideoReader(inputFile, {}, params);
cv::cudacodec::FormatInfo fmt = reader->format();
ASSERT_TRUE(fmt.ulNumDecodeSurfaces == ulNumDecodeSurfaces + 1);
GpuMat frame;
for (int i = 0; i < 100; i++) ASSERT_TRUE(reader->nextFrame(frame));
for (int i = 0; i < 100; i++) ASSERT_TRUE(reader->grab());
}
}

Expand Down

0 comments on commit d7c3402

Please sign in to comment.