Skip to content

Commit f0271e5

Browse files
Alexey Lapshinasmorkalov
authored andcommitted
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
1 parent 8de1769 commit f0271e5

File tree

4 files changed

+67
-29
lines changed

4 files changed

+67
-29
lines changed

modules/videoio/include/opencv2/videoio.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ enum VideoCaptureProperties {
177177
CAP_PROP_WB_TEMPERATURE=45, //!< white-balance color temperature
178178
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
179179
CAP_PROP_BITRATE =47, //!< (read-only) Video bitrate in kbits/s
180+
CAP_PROP_ORIENTATION_META=48, //!< (read-only) Frame rotation defined by stream meta (applicable for FFmpeg back-end only)
181+
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)
180182
#ifndef CV_DOXYGEN
181183
CV__CAP_PROP_LATEST
182184
#endif

modules/videoio/src/cap_ffmpeg.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -229,13 +229,12 @@ class CvCapture_FFMPEG_proxy CV_FINAL : public cv::IVideoCapture
229229
}
230230
virtual bool retrieveFrame(int, cv::OutputArray frame) CV_OVERRIDE
231231
{
232-
unsigned char* data = 0;
233-
int step=0, width=0, height=0, cn=0;
234-
232+
cv::Mat mat;
235233
if (!ffmpegCapture ||
236-
!icvRetrieveFrame_FFMPEG_p(ffmpegCapture, &data, &step, &width, &height, &cn))
234+
!icvRetrieveFrame_FFMPEG_p(ffmpegCapture, mat))
237235
return false;
238-
cv::Mat(height, width, CV_MAKETYPE(CV_8U, cn), data, step).copyTo(frame);
236+
237+
mat.copyTo(frame);
239238
return true;
240239
}
241240
virtual bool open( const cv::String& filename )
@@ -262,6 +261,8 @@ class CvCapture_FFMPEG_proxy CV_FINAL : public cv::IVideoCapture
262261

263262
protected:
264263
CvCapture_FFMPEG* ffmpegCapture;
264+
private:
265+
265266
};
266267

267268
} // namespace

modules/videoio/src/cap_ffmpeg_api.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ enum
2828
CV_FFMPEG_CAP_PROP_SAR_NUM=40,
2929
CV_FFMPEG_CAP_PROP_SAR_DEN=41,
3030
CV_FFMPEG_CAP_PROP_CODEC_PIXEL_FORMAT=46,
31-
CV_FFMPEG_CAP_PROP_BITRATE=47
31+
CV_FFMPEG_CAP_PROP_BITRATE=47,
32+
CV_FFMPEG_CAP_PROP_ORIENTATION_META=48,
33+
CV_FFMPEG_CAP_PROP_ORIENTATION_AUTO=49
3234
};
3335

3436
typedef struct CvCapture_FFMPEG CvCapture_FFMPEG;
@@ -39,8 +41,7 @@ OPENCV_FFMPEG_API int cvSetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap,
3941
int prop, double value);
4042
OPENCV_FFMPEG_API double cvGetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap, int prop);
4143
OPENCV_FFMPEG_API int cvGrabFrame_FFMPEG(struct CvCapture_FFMPEG* cap);
42-
OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG(struct CvCapture_FFMPEG* capture, unsigned char** data,
43-
int* step, int* width, int* height, int* cn);
44+
OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG(struct CvCapture_FFMPEG* capture, cv::Mat &mat);
4445
OPENCV_FFMPEG_API void cvReleaseCapture_FFMPEG(struct CvCapture_FFMPEG** cap);
4546

4647
OPENCV_FFMPEG_API struct CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG(const char* filename,
@@ -52,8 +53,7 @@ OPENCV_FFMPEG_API void cvReleaseVideoWriter_FFMPEG(struct CvVideoWriter_FFMPEG**
5253
typedef CvCapture_FFMPEG* (*CvCreateFileCapture_Plugin)( const char* filename );
5354
typedef CvCapture_FFMPEG* (*CvCreateCameraCapture_Plugin)( int index );
5455
typedef int (*CvGrabFrame_Plugin)( CvCapture_FFMPEG* capture_handle );
55-
typedef int (*CvRetrieveFrame_Plugin)( CvCapture_FFMPEG* capture_handle, unsigned char** data, int* step,
56-
int* width, int* height, int* cn );
56+
typedef int (*CvRetrieveFrame_Plugin)( CvCapture_FFMPEG* capture_handle, cv::Mat &mat);
5757
typedef int (*CvSetCaptureProperty_Plugin)( CvCapture_FFMPEG* capture_handle, int prop_id, double value );
5858
typedef double (*CvGetCaptureProperty_Plugin)( CvCapture_FFMPEG* capture_handle, int prop_id );
5959
typedef void (*CvReleaseCapture_Plugin)( CvCapture_FFMPEG** capture_handle );

modules/videoio/src/cap_ffmpeg_impl.hpp

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,8 @@ struct CvCapture_FFMPEG
481481
double getProperty(int) const;
482482
bool setProperty(int, double);
483483
bool grabFrame();
484-
bool retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn);
484+
bool retrieveFrame(int, cv::Mat &mat);
485+
void rotateFrame(cv::Mat &mat) const;
485486

486487
void init();
487488

@@ -497,6 +498,7 @@ struct CvCapture_FFMPEG
497498
double r2d(AVRational r) const;
498499
int64_t dts_to_frame_number(int64_t dts);
499500
double dts_to_sec(int64_t dts) const;
501+
void get_rotation_angle();
500502

501503
AVFormatContext * ic;
502504
AVCodec * avcodec;
@@ -512,6 +514,8 @@ struct CvCapture_FFMPEG
512514

513515
int64_t frame_number, first_frame_number;
514516

517+
bool rotation_auto;
518+
int rotation_angle; // valid 0, 90, 180, 270
515519
double eps_zero;
516520
/*
517521
'filename' contains the filename of the videosource,
@@ -560,6 +564,9 @@ void CvCapture_FFMPEG::init()
560564
frame_number = 0;
561565
eps_zero = 0.000025;
562566

567+
rotation_auto = true;
568+
rotation_angle = 0;
569+
563570
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
564571
dict = NULL;
565572
#endif
@@ -1032,6 +1039,7 @@ bool CvCapture_FFMPEG::open( const char* _filename )
10321039
frame.cn = 3;
10331040
frame.step = 0;
10341041
frame.data = NULL;
1042+
get_rotation_angle();
10351043
break;
10361044
}
10371045
}
@@ -1279,21 +1287,19 @@ bool CvCapture_FFMPEG::grabFrame()
12791287
return valid;
12801288
}
12811289

1282-
1283-
bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn)
1290+
bool CvCapture_FFMPEG::retrieveFrame(int, cv::Mat &mat)
12841291
{
12851292
if (!video_st)
12861293
return false;
12871294

12881295
if (rawMode)
12891296
{
12901297
AVPacket& p = bsfc ? packet_filtered : packet;
1291-
*data = p.data;
1292-
*step = p.size;
1293-
*width = p.size;
1294-
*height = 1;
1295-
*cn = 1;
1296-
return p.data != NULL;
1298+
if (p.data == NULL)
1299+
return false;
1300+
1301+
mat = cv::Mat(1, p.size, CV_MAKETYPE(CV_8U, 1), p.data, p.size);
1302+
return true;
12971303
}
12981304

12991305
if (!picture->data[0])
@@ -1356,15 +1362,29 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int*
13561362
rgb_picture.linesize
13571363
);
13581364

1359-
*data = frame.data;
1360-
*step = frame.step;
1361-
*width = frame.width;
1362-
*height = frame.height;
1363-
*cn = frame.cn;
1364-
1365+
mat = cv::Mat(frame.height, frame.width, CV_MAKETYPE(CV_8U, frame.cn), frame.data, frame.step);
1366+
rotateFrame(mat);
13651367
return true;
13661368
}
13671369

1370+
void CvCapture_FFMPEG::rotateFrame(cv::Mat &mat) const {
1371+
if(!rotation_auto || rotation_angle%360 == 0) {
1372+
return;
1373+
}
1374+
1375+
cv::RotateFlags flag;
1376+
if(rotation_angle == 90 || rotation_angle == -270) { // Rotate clockwise 90 degrees
1377+
flag = cv::ROTATE_90_CLOCKWISE;
1378+
} else if(rotation_angle == 270 || rotation_angle == -90) { // Rotate clockwise 270 degrees
1379+
flag = cv::ROTATE_90_COUNTERCLOCKWISE;
1380+
} else if(rotation_angle == 180 || rotation_angle == -180) { // Rotate clockwise 180 degrees
1381+
flag = cv::ROTATE_180;
1382+
} else { // Unsupported rotation
1383+
return;
1384+
}
1385+
1386+
cv::rotate(mat, mat, flag);
1387+
}
13681388

13691389
double CvCapture_FFMPEG::getProperty( int property_id ) const
13701390
{
@@ -1389,9 +1409,9 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const
13891409
case CV_FFMPEG_CAP_PROP_FRAME_COUNT:
13901410
return (double)get_total_frames();
13911411
case CV_FFMPEG_CAP_PROP_FRAME_WIDTH:
1392-
return (double)frame.width;
1412+
return (double)((rotation_auto && rotation_angle%360) ? frame.height : frame.width);
13931413
case CV_FFMPEG_CAP_PROP_FRAME_HEIGHT:
1394-
return (double)frame.height;
1414+
return (double)((rotation_auto && rotation_angle%360) ? frame.width : frame.height);
13951415
case CV_FFMPEG_CAP_PROP_FPS:
13961416
return get_fps();
13971417
case CV_FFMPEG_CAP_PROP_FOURCC:
@@ -1435,6 +1455,10 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const
14351455
break;
14361456
case CV_FFMPEG_CAP_PROP_BITRATE:
14371457
return static_cast<double>(get_bitrate());
1458+
case CV_FFMPEG_CAP_PROP_ORIENTATION_META:
1459+
return static_cast<double>(rotation_angle);
1460+
case CV_FFMPEG_CAP_PROP_ORIENTATION_AUTO:
1461+
return static_cast<double>(rotation_auto);
14381462
default:
14391463
break;
14401464
}
@@ -1513,6 +1537,14 @@ double CvCapture_FFMPEG::dts_to_sec(int64_t dts) const
15131537
r2d(ic->streams[video_stream]->time_base);
15141538
}
15151539

1540+
void CvCapture_FFMPEG::get_rotation_angle()
1541+
{
1542+
rotation_angle = 0;
1543+
AVDictionaryEntry *rotate_tag = av_dict_get(video_st->metadata, "rotate", NULL, 0);
1544+
if (rotate_tag != NULL)
1545+
rotation_angle = atoi(rotate_tag->value);
1546+
}
1547+
15161548
void CvCapture_FFMPEG::seek(int64_t _frame_number)
15171549
{
15181550
_frame_number = std::min(_frame_number, get_total_frames());
@@ -1608,6 +1640,9 @@ bool CvCapture_FFMPEG::setProperty( int property_id, double value )
16081640
if (value == -1)
16091641
return setRaw();
16101642
return false;
1643+
case CV_FFMPEG_CAP_PROP_ORIENTATION_AUTO:
1644+
rotation_auto = static_cast<bool>(value);
1645+
break;
16111646
default:
16121647
return false;
16131648
}
@@ -2635,9 +2670,9 @@ int cvGrabFrame_FFMPEG(CvCapture_FFMPEG* capture)
26352670
return capture->grabFrame();
26362671
}
26372672

2638-
int cvRetrieveFrame_FFMPEG(CvCapture_FFMPEG* capture, unsigned char** data, int* step, int* width, int* height, int* cn)
2673+
int cvRetrieveFrame_FFMPEG(CvCapture_FFMPEG* capture, cv::Mat &mat)
26392674
{
2640-
return capture->retrieveFrame(0, data, step, width, height, cn);
2675+
return capture->retrieveFrame(0, mat);
26412676
}
26422677

26432678
CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG( const char* filename, int fourcc, double fps,

0 commit comments

Comments
 (0)