Merge pull request #17489 from Lapshin:ffmpeg_cap_consider_rotation_metadata_3.4
This commit is contained in:
commit
5bfa43f7d5
@ -177,6 +177,8 @@ enum VideoCaptureProperties {
|
||||
CAP_PROP_WB_TEMPERATURE=45, //!< white-balance color temperature
|
||||
CAP_PROP_CODEC_PIXEL_FORMAT =46, //!< (read-only) codec's pixel format. 4-character code - see VideoWriter::fourcc . Subset of [AV_PIX_FMT_*](https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/raw.c) or -1 if unknown
|
||||
CAP_PROP_BITRATE =47, //!< (read-only) Video bitrate in kbits/s
|
||||
CAP_PROP_ORIENTATION_META=48, //!< (read-only) Frame rotation defined by stream meta (applicable for FFmpeg back-end only)
|
||||
CAP_PROP_ORIENTATION_AUTO=49, //!< if true - rotates output frames of CvCapture considering video file's metadata (applicable for FFmpeg back-end only) (https://github.com/opencv/opencv/issues/15499)
|
||||
#ifndef CV_DOXYGEN
|
||||
CV__CAP_PROP_LATEST
|
||||
#endif
|
||||
|
||||
@ -235,7 +235,11 @@ public:
|
||||
if (!ffmpegCapture ||
|
||||
!icvRetrieveFrame_FFMPEG_p(ffmpegCapture, &data, &step, &width, &height, &cn))
|
||||
return false;
|
||||
cv::Mat(height, width, CV_MAKETYPE(CV_8U, cn), data, step).copyTo(frame);
|
||||
|
||||
cv::Mat tmp(height, width, CV_MAKETYPE(CV_8U, cn), data, step);
|
||||
this->rotateFrame(tmp);
|
||||
tmp.copyTo(frame);
|
||||
|
||||
return true;
|
||||
}
|
||||
virtual bool open( const cv::String& filename )
|
||||
@ -262,6 +266,30 @@ public:
|
||||
|
||||
protected:
|
||||
CvCapture_FFMPEG* ffmpegCapture;
|
||||
|
||||
void rotateFrame(cv::Mat &mat) const
|
||||
{
|
||||
bool rotation_auto = 0 != getProperty(CV_FFMPEG_CAP_PROP_ORIENTATION_AUTO);
|
||||
int rotation_angle = static_cast<int>(getProperty(CV_FFMPEG_CAP_PROP_ORIENTATION_META));
|
||||
|
||||
if(!rotation_auto || rotation_angle%360 == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cv::RotateFlags flag;
|
||||
if(rotation_angle == 90 || rotation_angle == -270) { // Rotate clockwise 90 degrees
|
||||
flag = cv::ROTATE_90_CLOCKWISE;
|
||||
} else if(rotation_angle == 270 || rotation_angle == -90) { // Rotate clockwise 270 degrees
|
||||
flag = cv::ROTATE_90_COUNTERCLOCKWISE;
|
||||
} else if(rotation_angle == 180 || rotation_angle == -180) { // Rotate clockwise 180 degrees
|
||||
flag = cv::ROTATE_180;
|
||||
} else { // Unsupported rotation
|
||||
return;
|
||||
}
|
||||
|
||||
cv::rotate(mat, mat, flag);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -28,7 +28,9 @@ enum
|
||||
CV_FFMPEG_CAP_PROP_SAR_NUM=40,
|
||||
CV_FFMPEG_CAP_PROP_SAR_DEN=41,
|
||||
CV_FFMPEG_CAP_PROP_CODEC_PIXEL_FORMAT=46,
|
||||
CV_FFMPEG_CAP_PROP_BITRATE=47
|
||||
CV_FFMPEG_CAP_PROP_BITRATE=47,
|
||||
CV_FFMPEG_CAP_PROP_ORIENTATION_META=48,
|
||||
CV_FFMPEG_CAP_PROP_ORIENTATION_AUTO=49
|
||||
};
|
||||
|
||||
typedef struct CvCapture_FFMPEG CvCapture_FFMPEG;
|
||||
|
||||
@ -482,6 +482,7 @@ struct CvCapture_FFMPEG
|
||||
bool setProperty(int, double);
|
||||
bool grabFrame();
|
||||
bool retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn);
|
||||
void rotateFrame(cv::Mat &mat) const;
|
||||
|
||||
void init();
|
||||
|
||||
@ -497,6 +498,7 @@ struct CvCapture_FFMPEG
|
||||
double r2d(AVRational r) const;
|
||||
int64_t dts_to_frame_number(int64_t dts);
|
||||
double dts_to_sec(int64_t dts) const;
|
||||
void get_rotation_angle();
|
||||
|
||||
AVFormatContext * ic;
|
||||
AVCodec * avcodec;
|
||||
@ -512,6 +514,8 @@ struct CvCapture_FFMPEG
|
||||
|
||||
int64_t frame_number, first_frame_number;
|
||||
|
||||
bool rotation_auto;
|
||||
int rotation_angle; // valid 0, 90, 180, 270
|
||||
double eps_zero;
|
||||
/*
|
||||
'filename' contains the filename of the videosource,
|
||||
@ -560,8 +564,17 @@ void CvCapture_FFMPEG::init()
|
||||
frame_number = 0;
|
||||
eps_zero = 0.000025;
|
||||
|
||||
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
|
||||
rotation_angle = 0;
|
||||
|
||||
#if (LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0))
|
||||
#if (LIBAVUTIL_BUILD >= CALC_FFMPEG_VERSION(52, 92, 100))
|
||||
rotation_auto = true;
|
||||
#else
|
||||
rotation_auto = false;
|
||||
#endif
|
||||
dict = NULL;
|
||||
#else
|
||||
rotation_auto = false;
|
||||
#endif
|
||||
|
||||
rawMode = false;
|
||||
@ -1032,6 +1045,7 @@ bool CvCapture_FFMPEG::open( const char* _filename )
|
||||
frame.cn = 3;
|
||||
frame.step = 0;
|
||||
frame.data = NULL;
|
||||
get_rotation_angle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1290,7 +1304,6 @@ bool CvCapture_FFMPEG::grabFrame()
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn)
|
||||
{
|
||||
if (!video_st)
|
||||
@ -1376,7 +1389,6 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int*
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
double CvCapture_FFMPEG::getProperty( int property_id ) const
|
||||
{
|
||||
if( !video_st ) return 0;
|
||||
@ -1400,9 +1412,9 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const
|
||||
case CV_FFMPEG_CAP_PROP_FRAME_COUNT:
|
||||
return (double)get_total_frames();
|
||||
case CV_FFMPEG_CAP_PROP_FRAME_WIDTH:
|
||||
return (double)frame.width;
|
||||
return (double)((rotation_auto && rotation_angle%180) ? frame.height : frame.width);
|
||||
case CV_FFMPEG_CAP_PROP_FRAME_HEIGHT:
|
||||
return (double)frame.height;
|
||||
return (double)((rotation_auto && rotation_angle%180) ? frame.width : frame.height);
|
||||
case CV_FFMPEG_CAP_PROP_FPS:
|
||||
return get_fps();
|
||||
case CV_FFMPEG_CAP_PROP_FOURCC:
|
||||
@ -1446,6 +1458,15 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const
|
||||
break;
|
||||
case CV_FFMPEG_CAP_PROP_BITRATE:
|
||||
return static_cast<double>(get_bitrate());
|
||||
case CV_FFMPEG_CAP_PROP_ORIENTATION_META:
|
||||
return static_cast<double>(rotation_angle);
|
||||
case CV_FFMPEG_CAP_PROP_ORIENTATION_AUTO:
|
||||
#if ((LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)) && \
|
||||
(LIBAVUTIL_BUILD >= CALC_FFMPEG_VERSION(52, 94, 100)))
|
||||
return static_cast<double>(rotation_auto);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1524,6 +1545,17 @@ double CvCapture_FFMPEG::dts_to_sec(int64_t dts) const
|
||||
r2d(ic->streams[video_stream]->time_base);
|
||||
}
|
||||
|
||||
void CvCapture_FFMPEG::get_rotation_angle()
|
||||
{
|
||||
rotation_angle = 0;
|
||||
#if ((LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)) && \
|
||||
(LIBAVUTIL_BUILD >= CALC_FFMPEG_VERSION(52, 94, 100)))
|
||||
AVDictionaryEntry *rotate_tag = av_dict_get(video_st->metadata, "rotate", NULL, 0);
|
||||
if (rotate_tag != NULL)
|
||||
rotation_angle = atoi(rotate_tag->value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CvCapture_FFMPEG::seek(int64_t _frame_number)
|
||||
{
|
||||
_frame_number = std::min(_frame_number, get_total_frames());
|
||||
@ -1619,6 +1651,16 @@ bool CvCapture_FFMPEG::setProperty( int property_id, double value )
|
||||
if (value == -1)
|
||||
return setRaw();
|
||||
return false;
|
||||
case CV_FFMPEG_CAP_PROP_ORIENTATION_AUTO:
|
||||
#if ((LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)) && \
|
||||
(LIBAVUTIL_BUILD >= CALC_FFMPEG_VERSION(52, 94, 100)))
|
||||
rotation_auto = static_cast<bool>(value);
|
||||
return true;
|
||||
#else
|
||||
rotation_auto = 0;
|
||||
return false;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -636,5 +636,57 @@ const ffmpeg_cap_properties_param_t videoio_ffmpeg_properties[] = {
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(videoio, ffmpeg_cap_properties, testing::ValuesIn(videoio_ffmpeg_properties));
|
||||
|
||||
// related issue: https://github.com/opencv/opencv/issues/15499
|
||||
TEST(videoio, mp4_orientation_meta_auto)
|
||||
{
|
||||
string video_file = string(cvtest::TS::ptr()->get_data_path()) + "video/big_buck_bunny_rotated.mp4";
|
||||
|
||||
VideoCapture cap;
|
||||
EXPECT_NO_THROW(cap.open(video_file, CAP_FFMPEG));
|
||||
ASSERT_TRUE(cap.isOpened()) << "Can't open the video: " << video_file << " with backend " << CAP_FFMPEG << std::endl;
|
||||
|
||||
cap.set(CAP_PROP_ORIENTATION_AUTO, true);
|
||||
if (cap.get(CAP_PROP_ORIENTATION_AUTO) == 0)
|
||||
throw SkipTestException("FFmpeg frame rotation metadata is not supported");
|
||||
|
||||
Size actual;
|
||||
EXPECT_NO_THROW(actual = Size((int)cap.get(CAP_PROP_FRAME_WIDTH),
|
||||
(int)cap.get(CAP_PROP_FRAME_HEIGHT)));
|
||||
EXPECT_EQ(384, actual.width);
|
||||
EXPECT_EQ(672, actual.height);
|
||||
|
||||
Mat frame;
|
||||
|
||||
cap >> frame;
|
||||
|
||||
ASSERT_EQ(384, frame.cols);
|
||||
ASSERT_EQ(672, frame.rows);
|
||||
}
|
||||
|
||||
// related issue: https://github.com/opencv/opencv/issues/15499
|
||||
TEST(videoio, mp4_orientation_no_rotation)
|
||||
{
|
||||
string video_file = string(cvtest::TS::ptr()->get_data_path()) + "video/big_buck_bunny_rotated.mp4";
|
||||
|
||||
VideoCapture cap;
|
||||
EXPECT_NO_THROW(cap.open(video_file, CAP_FFMPEG));
|
||||
cap.set(CAP_PROP_ORIENTATION_AUTO, 0);
|
||||
ASSERT_TRUE(cap.isOpened()) << "Can't open the video: " << video_file << " with backend " << CAP_FFMPEG << std::endl;
|
||||
ASSERT_FALSE(cap.get(CAP_PROP_ORIENTATION_AUTO));
|
||||
|
||||
Size actual;
|
||||
EXPECT_NO_THROW(actual = Size((int)cap.get(CAP_PROP_FRAME_WIDTH),
|
||||
(int)cap.get(CAP_PROP_FRAME_HEIGHT)));
|
||||
EXPECT_EQ(672, actual.width);
|
||||
EXPECT_EQ(384, actual.height);
|
||||
|
||||
Mat frame;
|
||||
|
||||
cap >> frame;
|
||||
|
||||
ASSERT_EQ(672, frame.cols);
|
||||
ASSERT_EQ(384, frame.rows);
|
||||
}
|
||||
|
||||
#endif
|
||||
}} // namespace
|
||||
|
||||
Loading…
Reference in New Issue
Block a user