CAP_PROP_AUDIO_TOTAL_CHANNELS = 64, //!< (read-only) Number of audio channels in the selected audio stream (mono, stereo, etc)
CAP_PROP_AUDIO_TOTAL_STREAMS = 65, //!< (read-only) Number of audio streams.
CAP_PROP_AUDIO_SYNCHRONIZE = 66, //!< (open, read) Enables audio synchronization.
+ CAP_PROP_LRF_HAS_KEY_FRAME = 67, //!< FFmpeg back-end only - Indicates whether the Last Raw Frame (LRF), output from VideoCapture::read() when VideoCapture is initialized with VideoCapture::open(CAP_FFMPEG, {CAP_PROP_FORMAT, -1}) or VideoCapture::set(CAP_PROP_FORMAT,-1) is called before the first call to VideoCapture::read(), contains encoded data for a key frame.
+ CAP_PROP_CODEC_EXTRADATA_INDEX = 68, //!< Positive index indicates that returning extra data is supported by the video back end. This can be retrieved as cap.retrieve(data, <returned index>). E.g. When reading from a h264 encoded RTSP stream, the FFmpeg backend could return the SPS and/or PPS if available (if sent in reply to a DESCRIBE request), from calls to cap.retrieve(data, <returned index>).
#ifndef CV_DOXYGEN
CV__CAP_PROP_LATEST
#endif
{
return ffmpegCapture ? icvGrabFrame_FFMPEG_p(ffmpegCapture)!=0 : false;
}
- virtual bool retrieveFrame(int, cv::OutputArray frame) CV_OVERRIDE
+ virtual bool retrieveFrame(int flag, cv::OutputArray frame) CV_OVERRIDE
{
unsigned char* data = 0;
int step=0, width=0, height=0, cn=0;
}
}
- if (!icvRetrieveFrame_FFMPEG_p(ffmpegCapture, &data, &step, &width, &height, &cn))
- return false;
+ if (flag == 0) {
+ if (!icvRetrieveFrame_FFMPEG_p(ffmpegCapture, &data, &step, &width, &height, &cn))
+ return false;
+ }
+ else {
+ if (!ffmpegCapture->retrieveFrame(flag, &data, &step, &width, &height, &cn))
+ return false;
+ }
cv::Mat tmp(height, width, CV_MAKETYPE(CV_8U, cn), data, step);
this->rotateFrame(tmp);
double getProperty(int) const;
bool setProperty(int, double);
bool grabFrame();
- bool retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn);
+ bool retrieveFrame(int flag, unsigned char** data, int* step, int* width, int* height, int* cn);
bool retrieveHWFrame(cv::OutputArray output);
void rotateFrame(cv::Mat &mat) const;
VideoAccelerationType va_type;
int hw_device;
int use_opencl;
+ int extraDataIdx;
};
void CvCapture_FFMPEG::init()
va_type = cv::VIDEO_ACCELERATION_NONE; // TODO OpenCV 5.0: change to _ANY?
hw_device = -1;
use_opencl = 0;
+ extraDataIdx = 1;
}
return valid;
}
-bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn)
+bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, int* width, int* height, int* cn)
{
if (!video_st)
return false;
- if (rawMode)
+ if (rawMode || flag == extraDataIdx)
{
- AVPacket& p = bsfc ? packet_filtered : packet;
- *data = p.data;
- *step = p.size;
- *width = p.size;
+ bool ret = true;
+ if (flag == 0) {
+ AVPacket& p = bsfc ? packet_filtered : packet;
+ *data = p.data;
+ *step = p.size;
+ ret = p.data != NULL;
+ }
+ else if (flag == extraDataIdx) {
+ *data = ic->streams[video_stream]->codec->extradata;
+ *step = ic->streams[video_stream]->codec->extradata_size;
+ }
+ *width = *step;
*height = 1;
*cn = 1;
- return p.data != NULL;
+ return ret;
}
AVFrame* sw_picture = picture;
if (rawMode)
return -1;
break;
+ case CAP_PROP_LRF_HAS_KEY_FRAME: {
+ const AVPacket& p = bsfc ? packet_filtered : packet;
+ return ((p.flags & AV_PKT_FLAG_KEY) != 0) ? 1 : 0;
+ }
+ case CAP_PROP_CODEC_EXTRADATA_INDEX:
+ return extraDataIdx;
case CAP_PROP_BITRATE:
return static_cast<double>(get_bitrate());
case CAP_PROP_ORIENTATION_META:
EXPECT_EQ((size_t)37118, data.total());
}
+TEST(videoio_ffmpeg, ffmpeg_check_extra_data)
+{
+ if (!videoio_registry::hasBackend(CAP_FFMPEG))
+ throw SkipTestException("FFmpeg backend was not found");
+
+ string video_file = findDataFile("video/big_buck_bunny.mp4");
+ VideoCapture cap;
+ EXPECT_NO_THROW(cap.open(video_file, CAP_FFMPEG));
+ ASSERT_TRUE(cap.isOpened()) << "Can't open the video";
+ const int codecExtradataIdx = (int)cap.get(CAP_PROP_CODEC_EXTRADATA_INDEX);
+#ifdef _WIN32 // handle old FFmpeg backend
+ if (codecExtradataIdx <= 0)
+ throw SkipTestException("Codec extra data is not supported by backend or video stream");
+#endif
+ Mat data;
+ ASSERT_TRUE(cap.retrieve(data, codecExtradataIdx));
+ EXPECT_EQ(CV_8UC1, data.type()) << "CV_8UC1 != " << typeToString(data.type());
+ EXPECT_TRUE(data.rows == 1 || data.cols == 1) << data.size;
+ EXPECT_EQ((size_t)45, data.total());
+}
+
TEST(videoio_ffmpeg, open_with_property)
{
if (!videoio_registry::hasBackend(CAP_FFMPEG))