From 24fac5f56d61e0caa757a99c0bbfbc9239d6ce7d Mon Sep 17 00:00:00 2001
From: Alexander Smorkalov <alexander.smorkalov@xperience.ai>
Date: Mon, 30 Nov 2020 11:54:51 +0300
Subject: [PATCH] Added test for VideoCapture CAP_PROP_FRAME_MSEC option.

- Suppressed FFMPEG + h264, h265 as it does not pass tests with CI configuration.
- Suppressed MediaFoundation backend as it always returns zero for now.
---
 modules/videoio/src/cap_mjpeg_decoder.cpp |  2 ++
 modules/videoio/test/test_video_io.cpp    | 30 +++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/modules/videoio/src/cap_mjpeg_decoder.cpp b/modules/videoio/src/cap_mjpeg_decoder.cpp
index 116f118d28..a3c87812ac 100644
--- a/modules/videoio/src/cap_mjpeg_decoder.cpp
+++ b/modules/videoio/src/cap_mjpeg_decoder.cpp
@@ -116,6 +116,8 @@ double MotionJpegCapture::getProperty(int property) const
     {
         case CAP_PROP_POS_FRAMES:
             return (double)getFramePos();
+        case CAP_PROP_POS_MSEC:
+            return (double)getFramePos() * (1000. / m_fps);
         case CAP_PROP_POS_AVI_RATIO:
             return double(getFramePos())/m_mjpeg_frames.size();
         case CAP_PROP_FRAME_WIDTH:
diff --git a/modules/videoio/test/test_video_io.cpp b/modules/videoio/test/test_video_io.cpp
index 97b43ab68c..3f5617d8ce 100644
--- a/modules/videoio/test/test_video_io.cpp
+++ b/modules/videoio/test/test_video_io.cpp
@@ -231,6 +231,34 @@ public:
         else
             std::cout << "Frames counter is not available. Actual frames: " << count_actual << ". SKIP check." << std::endl;
     }
+
+    void doTimestampTest()
+    {
+        if (!isBackendAvailable(apiPref, cv::videoio_registry::getStreamBackends()))
+            throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
+
+        if ((apiPref == CAP_MSMF) || ((apiPref == CAP_FFMPEG) && ((ext == "h264") || (ext == "h265"))))
+            throw SkipTestException(cv::String("Backend ") +  cv::videoio_registry::getBackendName(apiPref) +
+                    cv::String(" does not support CAP_PROP_POS_MSEC option"));
+
+        VideoCapture cap;
+        EXPECT_NO_THROW(cap.open(video_file, apiPref));
+        if (!cap.isOpened())
+            throw SkipTestException(cv::String("Backend ") +  cv::videoio_registry::getBackendName(apiPref) +
+                    cv::String(" can't open the video: ")  + video_file);
+
+        Mat img;
+        for(int i = 0; i < 10; i++)
+        {
+            double timestamp = 0;
+            ASSERT_NO_THROW(cap >> img);
+            EXPECT_NO_THROW(timestamp = cap.get(CAP_PROP_POS_MSEC));
+            const double frame_period = 1000.f/bunny_param.getFps();
+            // NOTE: eps == frame_period, because videoCapture returns frame begining timestamp or frame end
+            // timestamp depending on codec and back-end. So the first frame has timestamp 0 or frame_period.
+            EXPECT_NEAR(timestamp, i*frame_period, frame_period);
+        }
+    }
 };
 
 //==================================================================================================
@@ -367,6 +395,8 @@ TEST_P(Videoio_Bunny, read_position) { doTest(); }
 
 TEST_P(Videoio_Bunny, frame_count) { doFrameCountTest(); }
 
+TEST_P(Videoio_Bunny, frame_timestamp) { doTimestampTest(); }
+
 INSTANTIATE_TEST_CASE_P(videoio, Videoio_Bunny,
                           testing::Combine(
                               testing::ValuesIn(bunny_params),