提交 f0271e54 编写于 作者: A Alexey Lapshin 提交者: Alexander Smorkalov

Autorotation for mp4 streams with metadata

- Add VideoCapture camera orientation property for mp4 videos with camera orientation meta.
- Add auto rotation for 90, 180, 270 degrees using cv::rotate
上级 8de17698
...@@ -177,6 +177,8 @@ enum VideoCaptureProperties { ...@@ -177,6 +177,8 @@ enum VideoCaptureProperties {
CAP_PROP_WB_TEMPERATURE=45, //!< white-balance color temperature 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_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_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 #ifndef CV_DOXYGEN
CV__CAP_PROP_LATEST CV__CAP_PROP_LATEST
#endif #endif
......
...@@ -229,13 +229,12 @@ public: ...@@ -229,13 +229,12 @@ public:
} }
virtual bool retrieveFrame(int, cv::OutputArray frame) CV_OVERRIDE virtual bool retrieveFrame(int, cv::OutputArray frame) CV_OVERRIDE
{ {
unsigned char* data = 0; cv::Mat mat;
int step=0, width=0, height=0, cn=0;
if (!ffmpegCapture || if (!ffmpegCapture ||
!icvRetrieveFrame_FFMPEG_p(ffmpegCapture, &data, &step, &width, &height, &cn)) !icvRetrieveFrame_FFMPEG_p(ffmpegCapture, mat))
return false; return false;
cv::Mat(height, width, CV_MAKETYPE(CV_8U, cn), data, step).copyTo(frame);
mat.copyTo(frame);
return true; return true;
} }
virtual bool open( const cv::String& filename ) virtual bool open( const cv::String& filename )
...@@ -262,6 +261,8 @@ public: ...@@ -262,6 +261,8 @@ public:
protected: protected:
CvCapture_FFMPEG* ffmpegCapture; CvCapture_FFMPEG* ffmpegCapture;
private:
}; };
} // namespace } // namespace
......
...@@ -28,7 +28,9 @@ enum ...@@ -28,7 +28,9 @@ enum
CV_FFMPEG_CAP_PROP_SAR_NUM=40, CV_FFMPEG_CAP_PROP_SAR_NUM=40,
CV_FFMPEG_CAP_PROP_SAR_DEN=41, CV_FFMPEG_CAP_PROP_SAR_DEN=41,
CV_FFMPEG_CAP_PROP_CODEC_PIXEL_FORMAT=46, 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; typedef struct CvCapture_FFMPEG CvCapture_FFMPEG;
...@@ -39,8 +41,7 @@ OPENCV_FFMPEG_API int cvSetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap, ...@@ -39,8 +41,7 @@ OPENCV_FFMPEG_API int cvSetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap,
int prop, double value); int prop, double value);
OPENCV_FFMPEG_API double cvGetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap, int prop); OPENCV_FFMPEG_API double cvGetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap, int prop);
OPENCV_FFMPEG_API int cvGrabFrame_FFMPEG(struct CvCapture_FFMPEG* cap); OPENCV_FFMPEG_API int cvGrabFrame_FFMPEG(struct CvCapture_FFMPEG* cap);
OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG(struct CvCapture_FFMPEG* capture, unsigned char** data, OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG(struct CvCapture_FFMPEG* capture, cv::Mat &mat);
int* step, int* width, int* height, int* cn);
OPENCV_FFMPEG_API void cvReleaseCapture_FFMPEG(struct CvCapture_FFMPEG** cap); OPENCV_FFMPEG_API void cvReleaseCapture_FFMPEG(struct CvCapture_FFMPEG** cap);
OPENCV_FFMPEG_API struct CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG(const char* filename, OPENCV_FFMPEG_API struct CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG(const char* filename,
...@@ -52,8 +53,7 @@ OPENCV_FFMPEG_API void cvReleaseVideoWriter_FFMPEG(struct CvVideoWriter_FFMPEG** ...@@ -52,8 +53,7 @@ OPENCV_FFMPEG_API void cvReleaseVideoWriter_FFMPEG(struct CvVideoWriter_FFMPEG**
typedef CvCapture_FFMPEG* (*CvCreateFileCapture_Plugin)( const char* filename ); typedef CvCapture_FFMPEG* (*CvCreateFileCapture_Plugin)( const char* filename );
typedef CvCapture_FFMPEG* (*CvCreateCameraCapture_Plugin)( int index ); typedef CvCapture_FFMPEG* (*CvCreateCameraCapture_Plugin)( int index );
typedef int (*CvGrabFrame_Plugin)( CvCapture_FFMPEG* capture_handle ); typedef int (*CvGrabFrame_Plugin)( CvCapture_FFMPEG* capture_handle );
typedef int (*CvRetrieveFrame_Plugin)( CvCapture_FFMPEG* capture_handle, unsigned char** data, int* step, typedef int (*CvRetrieveFrame_Plugin)( CvCapture_FFMPEG* capture_handle, cv::Mat &mat);
int* width, int* height, int* cn );
typedef int (*CvSetCaptureProperty_Plugin)( CvCapture_FFMPEG* capture_handle, int prop_id, double value ); typedef int (*CvSetCaptureProperty_Plugin)( CvCapture_FFMPEG* capture_handle, int prop_id, double value );
typedef double (*CvGetCaptureProperty_Plugin)( CvCapture_FFMPEG* capture_handle, int prop_id ); typedef double (*CvGetCaptureProperty_Plugin)( CvCapture_FFMPEG* capture_handle, int prop_id );
typedef void (*CvReleaseCapture_Plugin)( CvCapture_FFMPEG** capture_handle ); typedef void (*CvReleaseCapture_Plugin)( CvCapture_FFMPEG** capture_handle );
......
...@@ -481,7 +481,8 @@ struct CvCapture_FFMPEG ...@@ -481,7 +481,8 @@ struct CvCapture_FFMPEG
double getProperty(int) const; double getProperty(int) const;
bool setProperty(int, double); bool setProperty(int, double);
bool grabFrame(); bool grabFrame();
bool retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn); bool retrieveFrame(int, cv::Mat &mat);
void rotateFrame(cv::Mat &mat) const;
void init(); void init();
...@@ -497,6 +498,7 @@ struct CvCapture_FFMPEG ...@@ -497,6 +498,7 @@ struct CvCapture_FFMPEG
double r2d(AVRational r) const; double r2d(AVRational r) const;
int64_t dts_to_frame_number(int64_t dts); int64_t dts_to_frame_number(int64_t dts);
double dts_to_sec(int64_t dts) const; double dts_to_sec(int64_t dts) const;
void get_rotation_angle();
AVFormatContext * ic; AVFormatContext * ic;
AVCodec * avcodec; AVCodec * avcodec;
...@@ -512,6 +514,8 @@ struct CvCapture_FFMPEG ...@@ -512,6 +514,8 @@ struct CvCapture_FFMPEG
int64_t frame_number, first_frame_number; int64_t frame_number, first_frame_number;
bool rotation_auto;
int rotation_angle; // valid 0, 90, 180, 270
double eps_zero; double eps_zero;
/* /*
'filename' contains the filename of the videosource, 'filename' contains the filename of the videosource,
...@@ -560,6 +564,9 @@ void CvCapture_FFMPEG::init() ...@@ -560,6 +564,9 @@ void CvCapture_FFMPEG::init()
frame_number = 0; frame_number = 0;
eps_zero = 0.000025; eps_zero = 0.000025;
rotation_auto = true;
rotation_angle = 0;
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0) #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
dict = NULL; dict = NULL;
#endif #endif
...@@ -1032,6 +1039,7 @@ bool CvCapture_FFMPEG::open( const char* _filename ) ...@@ -1032,6 +1039,7 @@ bool CvCapture_FFMPEG::open( const char* _filename )
frame.cn = 3; frame.cn = 3;
frame.step = 0; frame.step = 0;
frame.data = NULL; frame.data = NULL;
get_rotation_angle();
break; break;
} }
} }
...@@ -1279,8 +1287,7 @@ bool CvCapture_FFMPEG::grabFrame() ...@@ -1279,8 +1287,7 @@ bool CvCapture_FFMPEG::grabFrame()
return valid; return valid;
} }
bool CvCapture_FFMPEG::retrieveFrame(int, cv::Mat &mat)
bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn)
{ {
if (!video_st) if (!video_st)
return false; return false;
...@@ -1288,12 +1295,11 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int* ...@@ -1288,12 +1295,11 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int*
if (rawMode) if (rawMode)
{ {
AVPacket& p = bsfc ? packet_filtered : packet; AVPacket& p = bsfc ? packet_filtered : packet;
*data = p.data; if (p.data == NULL)
*step = p.size; return false;
*width = p.size;
*height = 1; mat = cv::Mat(1, p.size, CV_MAKETYPE(CV_8U, 1), p.data, p.size);
*cn = 1; return true;
return p.data != NULL;
} }
if (!picture->data[0]) if (!picture->data[0])
...@@ -1356,15 +1362,29 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int* ...@@ -1356,15 +1362,29 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int*
rgb_picture.linesize rgb_picture.linesize
); );
*data = frame.data; mat = cv::Mat(frame.height, frame.width, CV_MAKETYPE(CV_8U, frame.cn), frame.data, frame.step);
*step = frame.step; rotateFrame(mat);
*width = frame.width;
*height = frame.height;
*cn = frame.cn;
return true; return true;
} }
void CvCapture_FFMPEG::rotateFrame(cv::Mat &mat) const {
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);
}
double CvCapture_FFMPEG::getProperty( int property_id ) const double CvCapture_FFMPEG::getProperty( int property_id ) const
{ {
...@@ -1389,9 +1409,9 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const ...@@ -1389,9 +1409,9 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const
case CV_FFMPEG_CAP_PROP_FRAME_COUNT: case CV_FFMPEG_CAP_PROP_FRAME_COUNT:
return (double)get_total_frames(); return (double)get_total_frames();
case CV_FFMPEG_CAP_PROP_FRAME_WIDTH: case CV_FFMPEG_CAP_PROP_FRAME_WIDTH:
return (double)frame.width; return (double)((rotation_auto && rotation_angle%360) ? frame.height : frame.width);
case CV_FFMPEG_CAP_PROP_FRAME_HEIGHT: case CV_FFMPEG_CAP_PROP_FRAME_HEIGHT:
return (double)frame.height; return (double)((rotation_auto && rotation_angle%360) ? frame.width : frame.height);
case CV_FFMPEG_CAP_PROP_FPS: case CV_FFMPEG_CAP_PROP_FPS:
return get_fps(); return get_fps();
case CV_FFMPEG_CAP_PROP_FOURCC: case CV_FFMPEG_CAP_PROP_FOURCC:
...@@ -1435,6 +1455,10 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const ...@@ -1435,6 +1455,10 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const
break; break;
case CV_FFMPEG_CAP_PROP_BITRATE: case CV_FFMPEG_CAP_PROP_BITRATE:
return static_cast<double>(get_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:
return static_cast<double>(rotation_auto);
default: default:
break; break;
} }
...@@ -1513,6 +1537,14 @@ double CvCapture_FFMPEG::dts_to_sec(int64_t dts) const ...@@ -1513,6 +1537,14 @@ double CvCapture_FFMPEG::dts_to_sec(int64_t dts) const
r2d(ic->streams[video_stream]->time_base); r2d(ic->streams[video_stream]->time_base);
} }
void CvCapture_FFMPEG::get_rotation_angle()
{
rotation_angle = 0;
AVDictionaryEntry *rotate_tag = av_dict_get(video_st->metadata, "rotate", NULL, 0);
if (rotate_tag != NULL)
rotation_angle = atoi(rotate_tag->value);
}
void CvCapture_FFMPEG::seek(int64_t _frame_number) void CvCapture_FFMPEG::seek(int64_t _frame_number)
{ {
_frame_number = std::min(_frame_number, get_total_frames()); _frame_number = std::min(_frame_number, get_total_frames());
...@@ -1608,6 +1640,9 @@ bool CvCapture_FFMPEG::setProperty( int property_id, double value ) ...@@ -1608,6 +1640,9 @@ bool CvCapture_FFMPEG::setProperty( int property_id, double value )
if (value == -1) if (value == -1)
return setRaw(); return setRaw();
return false; return false;
case CV_FFMPEG_CAP_PROP_ORIENTATION_AUTO:
rotation_auto = static_cast<bool>(value);
break;
default: default:
return false; return false;
} }
...@@ -2635,9 +2670,9 @@ int cvGrabFrame_FFMPEG(CvCapture_FFMPEG* capture) ...@@ -2635,9 +2670,9 @@ int cvGrabFrame_FFMPEG(CvCapture_FFMPEG* capture)
return capture->grabFrame(); return capture->grabFrame();
} }
int cvRetrieveFrame_FFMPEG(CvCapture_FFMPEG* capture, unsigned char** data, int* step, int* width, int* height, int* cn) int cvRetrieveFrame_FFMPEG(CvCapture_FFMPEG* capture, cv::Mat &mat)
{ {
return capture->retrieveFrame(0, data, step, width, height, cn); return capture->retrieveFrame(0, mat);
} }
CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG( const char* filename, int fourcc, double fps, CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG( const char* filename, int fourcc, double fps,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册