Skip to content

Pass cv::VideoCaptureProperties to VideoReader FFmpeg source #3139

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Dec 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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