Skip to content

Commit

Permalink
Merge pull request #3139 from cudawarped:pass_videocapture_params_to_…
Browse files Browse the repository at this point in the history
…videoreader

Pass cv::VideoCaptureProperties to VideoReader FFmpeg source

* Add missing codecs to cudacodec which uses Nvidia Video Codec SDK including checks to ensure codec used in input video file is supported on the current device.

* Allow VideoCaptureProperties to be passed to VideoCapture on initialization.
Include test for VideoReader but not for VideoCapture, assume pass through successful.
Use propertyId instead of c++ keyword property.
Remove unecessary error checks (parsers error is dependant on source) and output more informative exception.

* Prevent, fall back to CuvidVideoSource if VideoCapture params are passed and initialization fails and add test for this.

* Remove magic number from get methods, and make the types consistent with VideoCapture::get
Fix documentation.

* Add wrapper macro's and remove unecessary parameter from get().
  • Loading branch information
cudawarped authored Dec 28, 2021
1 parent 49e8f12 commit 758c1a9
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 73 deletions.
47 changes: 39 additions & 8 deletions modules/cudacodec/include/opencv2/cudacodec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,10 @@ enum class VideoReaderProps {
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().
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.
#ifndef CV_DOXYGEN
PROP_NOT_SUPPORTED
#endif
};

/** @brief Video reader interface.
Expand Down Expand Up @@ -369,19 +372,33 @@ class CV_EXPORTS_W VideoReader

/** @brief Sets a property in the VideoReader.
@param property Property identifier from cv::cudacodec::VideoReaderProps (eg. cv::cudacodec::PROP_DECODED_FRAME_IDX, cv::cudacodec::PROP_EXTRA_DATA_INDEX, ...)
@param propertyId Property identifier from cv::cudacodec::VideoReaderProps (eg. cv::cudacodec::VideoReaderProps::PROP_DECODED_FRAME_IDX,
cv::cudacodec::VideoReaderProps::PROP_EXTRA_DATA_INDEX, ...).
@param propertyVal Value of the property.
@return `true` if the property has been set.
*/
CV_WRAP virtual bool set(const VideoReaderProps property, const double propertyVal) = 0;
CV_WRAP virtual bool set(const VideoReaderProps propertyId, const double propertyVal) = 0;

/** @brief Returns the specified VideoReader property
@param property Property identifier from cv::cudacodec::VideoReaderProps (eg. cv::cudacodec::PROP_DECODED_FRAME_IDX, cv::cudacodec::PROP_EXTRA_DATA_INDEX, ...)
@param propertyVal Optional value for the property.
@return Value for the specified property. Value -1 is returned when querying a property that is not supported.
@param propertyId Property identifier from cv::cudacodec::VideoReaderProps (eg. cv::cudacodec::VideoReaderProps::PROP_DECODED_FRAME_IDX,
cv::cudacodec::VideoReaderProps::PROP_EXTRA_DATA_INDEX, ...).
@param propertyVal
In - Optional value required for querying specific propertyId's, e.g. the index of the raw package to be checked for a key frame (cv::cudacodec::VideoReaderProps::PROP_LRF_HAS_KEY_FRAME).
Out - Value of the property.
@return `true` unless the property is not supported.
*/
CV_WRAP virtual int get(const VideoReaderProps property, const int propertyVal = -1) const = 0;
CV_WRAP virtual bool get(const VideoReaderProps propertyId, CV_IN_OUT double& propertyVal) const = 0;

/** @brief Retrieves the specified property used by the VideoSource.
@param propertyId Property identifier from cv::VideoCaptureProperties (eg. cv::CAP_PROP_POS_MSEC, cv::CAP_PROP_POS_FRAMES, ...)
or one from @ref videoio_flags_others.
@param propertyVal Value for the specified property.
@return `true` unless the property is unset set or not supported.
*/
CV_WRAP virtual bool get(const int propertyId, CV_OUT double& propertyVal) const = 0;
};

/** @brief Interface for video demultiplexing. :
Expand Down Expand Up @@ -417,16 +434,30 @@ class CV_EXPORTS_W RawVideoSource
@param extraData 1D cv::Mat containing the extra data if it exists.
*/
virtual void getExtraData(cv::Mat& extraData) const = 0;

/** @brief Retrieves the specified property used by the VideoSource.
@param propertyId Property identifier from cv::VideoCaptureProperties (eg. cv::CAP_PROP_POS_MSEC, cv::CAP_PROP_POS_FRAMES, ...)
or one from @ref videoio_flags_others.
@param propertyVal Value for the specified property.
@return `true` unless the property is unset set or not supported.
*/
virtual bool get(const int propertyId, double& propertyVal) const = 0;
};

/** @brief Creates video reader.
@param filename Name of the input video file.
@param params Pass through parameters for VideoCapure. VideoCapture with the FFMpeg back end (CAP_FFMPEG) is used to parse the video input.
The `params` parameter allows to specify extra parameters encoded as pairs `(paramId_1, paramValue_1, paramId_2, paramValue_2, ...)`.
See cv::VideoCaptureProperties
e.g. when streaming from an RTSP source CAP_PROP_OPEN_TIMEOUT_MSEC may need to be set.
@param rawMode Allow the raw encoded data which has been read up until the last call to grab() to be retrieved by calling retrieve(rawData,RAW_DATA_IDX).
FFMPEG is used to read videos. User can implement own demultiplexing with cudacodec::RawVideoSource
*/
CV_EXPORTS_W Ptr<VideoReader> createVideoReader(const String& filename, const bool rawMode = false);
CV_EXPORTS_W Ptr<VideoReader> createVideoReader(const String& filename, const std::vector<int>& params = {}, const bool rawMode = false);

/** @overload
@param source RAW video source implemented by user.
Expand Down
18 changes: 16 additions & 2 deletions modules/cudacodec/src/ffmpeg_video_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ void FourccToChromaFormat(const int pixelFormat, ChromaFormat &chromaFormat, int
}
}

static
int StartCodeLen(unsigned char* data, const int sz) {
if (sz >= 3 && data[0] == 0 && data[1] == 0 && data[2] == 1)
return 3;
Expand All @@ -129,12 +130,13 @@ bool ParamSetsExist(unsigned char* parameterSets, const int szParameterSets, uns
return paramSetStartCodeLen != 0 && packetStartCodeLen != 0 && parameterSets[paramSetStartCodeLen] == data[packetStartCodeLen];
}

cv::cudacodec::detail::FFmpegVideoSource::FFmpegVideoSource(const String& fname)
cv::cudacodec::detail::FFmpegVideoSource::FFmpegVideoSource(const String& fname, const std::vector<int>& _videoCaptureParams)
: videoCaptureParams(_videoCaptureParams)
{
if (!videoio_registry::hasBackend(CAP_FFMPEG))
CV_Error(Error::StsNotImplemented, "FFmpeg backend not found");

cap.open(fname, CAP_FFMPEG);
cap.open(fname, CAP_FFMPEG, videoCaptureParams);
if (!cap.isOpened())
CV_Error(Error::StsUnsupportedFormat, "Unsupported video source");

Expand Down Expand Up @@ -176,6 +178,18 @@ void cv::cudacodec::detail::FFmpegVideoSource::updateFormat(const FormatInfo& vi
format_.valid = true;
}

bool cv::cudacodec::detail::FFmpegVideoSource::get(const int propertyId, double& propertyVal) const
{
CV_Assert(videoCaptureParams.size() % 2 == 0);
for (std::size_t i = 0; i < videoCaptureParams.size(); i += 2) {
if (videoCaptureParams.at(i) == propertyId) {
propertyVal = videoCaptureParams.at(i + 1);
return true;
}
}
return false;
}

bool cv::cudacodec::detail::FFmpegVideoSource::getNextPacket(unsigned char** data, size_t* size)
{
cap >> rawFrame;
Expand Down
5 changes: 4 additions & 1 deletion modules/cudacodec/src/ffmpeg_video_source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ namespace cv { namespace cudacodec { namespace detail {
class FFmpegVideoSource : public RawVideoSource
{
public:
FFmpegVideoSource(const String& fname);
FFmpegVideoSource(const String& fname, const std::vector<int>& params);
~FFmpegVideoSource();

bool getNextPacket(unsigned char** data, size_t* size) CV_OVERRIDE;
Expand All @@ -64,11 +64,14 @@ class FFmpegVideoSource : public RawVideoSource

void getExtraData(cv::Mat& _extraData) const CV_OVERRIDE { _extraData = extraData; }

bool get(const int propertyId, double& propertyVal) const;

private:
FormatInfo format_;
VideoCapture cap;
Mat rawFrame, extraData, dataWithHeader;
int iFrame = 0;
std::vector<int> videoCaptureParams;
};

}}}
Expand Down
59 changes: 37 additions & 22 deletions modules/cudacodec/src/video_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ using namespace cv::cudacodec;

#ifndef HAVE_NVCUVID

Ptr<VideoReader> cv::cudacodec::createVideoReader(const String&, const bool) { throw_no_cuda(); return Ptr<VideoReader>(); }
Ptr<VideoReader> cv::cudacodec::createVideoReader(const String&, const std::vector<int>&, const bool) { throw_no_cuda(); return Ptr<VideoReader>(); }
Ptr<VideoReader> cv::cudacodec::createVideoReader(const Ptr<RawVideoSource>&, const bool) { throw_no_cuda(); return Ptr<VideoReader>(); }

#else // HAVE_NVCUVID
Expand All @@ -73,9 +73,11 @@ namespace

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

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

int get(const VideoReaderProps property, const int propertyVal) const CV_OVERRIDE;
bool get(const VideoReaderProps propertyId, double& propertyVal) const CV_OVERRIDE;

bool get(const int propertyId, double& propertyVal) const CV_OVERRIDE;

private:
bool internalGrab(GpuMat& frame, Stream& stream);
Expand Down Expand Up @@ -136,8 +138,8 @@ namespace
};

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

if (frames_.empty())
{
Expand All @@ -148,8 +150,8 @@ namespace
if (frameQueue_->dequeue(displayInfo, rawPackets))
break;

if (videoSource_->hasError() || videoParser_->hasError())
CV_Error(Error::StsUnsupportedFormat, "Unsupported video source");
if (videoParser_->hasError())
CV_Error(Error::StsError, "Parsing/Decoding video source failed, check GPU memory is available and GPU supports hardware decoding.");

if (frameQueue_->isEndOfDecode())
return false;
Expand Down Expand Up @@ -231,42 +233,54 @@ namespace
return !frame.empty();
}

bool VideoReaderImpl::set(const VideoReaderProps property, const double propertyVal) {
switch (property) {
bool VideoReaderImpl::set(const VideoReaderProps propertyId, const double propertyVal) {
switch (propertyId) {
case VideoReaderProps::PROP_RAW_MODE :
videoSource_->SetRawMode(static_cast<bool>(propertyVal));
break;
}
return true;
}

int VideoReaderImpl::get(const VideoReaderProps property, const int propertyVal) const {
switch (property)
bool VideoReaderImpl::get(const VideoReaderProps propertyId, double& propertyVal) const {
switch (propertyId)
{
case VideoReaderProps::PROP_DECODED_FRAME_IDX:
return decodedFrameIdx;
propertyVal = decodedFrameIdx;
return true;
case VideoReaderProps::PROP_EXTRA_DATA_INDEX:
return extraDataIdx;
propertyVal = extraDataIdx;
return true;
case VideoReaderProps::PROP_RAW_PACKAGES_BASE_INDEX:
if (videoSource_->RawModeEnabled())
return rawPacketsBaseIdx;
if (videoSource_->RawModeEnabled()) {
propertyVal = rawPacketsBaseIdx;
return true;
}
else
break;
case VideoReaderProps::PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB:
return rawPackets.size();
propertyVal = rawPackets.size();
return true;
case::VideoReaderProps::PROP_RAW_MODE:
return videoSource_->RawModeEnabled();
propertyVal = videoSource_->RawModeEnabled();
return true;
case::VideoReaderProps::PROP_LRF_HAS_KEY_FRAME: {
const int iPacket = propertyVal - rawPacketsBaseIdx;
if (videoSource_->RawModeEnabled() && iPacket >= 0 && iPacket < rawPackets.size())
return rawPackets.at(iPacket).containsKeyFrame;
if (videoSource_->RawModeEnabled() && iPacket >= 0 && iPacket < rawPackets.size()) {
propertyVal = rawPackets.at(iPacket).containsKeyFrame;
return true;
}
else
break;
}
default:
break;
}
return -1;
return false;
}

bool VideoReaderImpl::get(const int propertyId, double& propertyVal) const {
return videoSource_->get(propertyId, propertyVal);
}

bool VideoReaderImpl::nextFrame(GpuMat& frame, Stream& stream)
Expand All @@ -277,7 +291,7 @@ namespace
}
}

Ptr<VideoReader> cv::cudacodec::createVideoReader(const String& filename, const bool rawMode)
Ptr<VideoReader> cv::cudacodec::createVideoReader(const String& filename, const std::vector<int>& params, const bool rawMode)
{
CV_Assert(!filename.empty());

Expand All @@ -286,11 +300,12 @@ Ptr<VideoReader> cv::cudacodec::createVideoReader(const String& filename, const
try
{
// prefer ffmpeg to cuvidGetSourceVideoFormat() which doesn't always return the corrct raw pixel format
Ptr<RawVideoSource> source(new FFmpegVideoSource(filename));
Ptr<RawVideoSource> source(new FFmpegVideoSource(filename, params));
videoSource.reset(new RawVideoSourceWrapper(source, rawMode));
}
catch (...)
{
if (params.size()) throw;
videoSource.reset(new CuvidVideoSource(filename));
}

Expand Down
5 changes: 5 additions & 0 deletions modules/cudacodec/src/video_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ void cv::cudacodec::detail::RawVideoSourceWrapper::updateFormat(const FormatInfo
source_->updateFormat(videoFormat);
}

bool cv::cudacodec::detail::RawVideoSourceWrapper::get(const int propertyId, double& propertyVal) const
{
return source_->get(propertyId, propertyVal);
}

void cv::cudacodec::detail::RawVideoSourceWrapper::start()
{
stop_ = false;
Expand Down
2 changes: 2 additions & 0 deletions modules/cudacodec/src/video_source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class VideoSource

virtual FormatInfo format() const = 0;
virtual void updateFormat(const FormatInfo& videoFormat) = 0;
virtual bool get(const int propertyId, double& propertyVal) const { return false; }
virtual void start() = 0;
virtual void stop() = 0;
virtual bool isStarted() const = 0;
Expand Down Expand Up @@ -89,6 +90,7 @@ class RawVideoSourceWrapper : public VideoSource

FormatInfo format() const CV_OVERRIDE;
void updateFormat(const FormatInfo& videoFormat) CV_OVERRIDE;
bool get(const int propertyId, double& propertyVal) const CV_OVERRIDE;
void start() CV_OVERRIDE;
void stop() CV_OVERRIDE;
bool isStarted() const CV_OVERRIDE;
Expand Down
Loading

0 comments on commit 758c1a9

Please sign in to comment.