35

I can only get the number of frames CAP_PROP_FRAME_COUNT using OpenCV.

However, I cannot find the parameter to get the duration of the video using OpenCV.

How to do that?

Thank you very much.

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
Frankie
  • 744
  • 1
  • 9
  • 14

6 Answers6

57

In OpenCV 3, the solution is:

import cv2 as cv

cap = cv.VideoCapture("./video.mp4")
fps = cap.get(cv.CAP_PROP_FPS)      # OpenCV v2.x used "CV_CAP_PROP_FPS"
frame_count = int(cap.get(cv.CAP_PROP_FRAME_COUNT))
duration = frame_count/fps

print('fps = ' + str(fps))
print('number of frames = ' + str(frame_count))
print('duration (S) = ' + str(duration))
minutes = int(duration/60)
seconds = duration%60
print('duration (M:S) = ' + str(minutes) + ':' + str(seconds))

cap.release()
Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
Ryan Loggerythm
  • 2,877
  • 3
  • 31
  • 39
  • 1
    Why do you import `cv2` when you begin your answer by saying that you are using OpenCV 3? Doesn't `cv2` mean OpenCV 2, or have I got this wrong? – HelloGoodbye Oct 29 '19 at 11:46
  • 3
    @HelloGoodbye, this page should explain it: https://stackoverflow.com/questions/44102738/why-cant-i-import-opencv3-even-though-the-package-is-installed – Ryan Loggerythm Oct 29 '19 at 17:14
37

OpenCV is not designed to explore video metadata, so VideoCapture doesn't have API to retrieve it directly.

You can instead "measure" the length of the stream: seek to the end, then get the timestamp:

>>> import cv2 as cv
>>> v = cv.VideoCapture('sample.avi')
>>> v.set(cv.CAP_PROP_POS_AVI_RATIO, 1)
True
>>> v.get(cv.CAP_PROP_POS_MSEC)
213400.0

Checking shows that this sets the point after the last frame (not before it), so the timestamp is indeed the exact total length of the stream:

>>> v.get(cv.CAP_PROP_POS_FRAMES)
5335.0
>>>> v.get(cv.CAP_PROP_FRAME_COUNT)
5335.0

>>> v.set(cv.CAP_PROP_POS_AVI_RATIO, 0)
>>> v.get(cv.CAP_PROP_POS_FRAMES)
0.0        # the 1st frame is frame 0, not 1, so "5335" means after the last frame
Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
  • 1
    The call to `v.get(cv2.CAP_PROP_POS_MSEC)` might not return correct value unless `v.read()` is called after setting a position, including seeking to the end. See https://github.com/opencv/opencv/issues/15749 – kfx Jun 29 '20 at 19:31
  • @kfx I see. So this is new behavior in `4.1.2`. [When I'm at the end, I get wrong number even after `read()`](https://github.com/opencv/opencv/issues/15749#issuecomment-651399016); from [the code](https://github.com/opencv/opencv/blob/master/modules/videoio/src/cap_ffmpeg_impl.hpp#L1590-L1609), it looks like it's not supposed to require calling `read()` because it sets `picture_pts`. So this is a bug in my book. – ivan_pozdeev Jun 29 '20 at 22:25
  • It seems like seeking to the end of the stream with `CAP_PROP_POS_AVI_RATIO` doesn't work all the time depending on the video type (e.g. doesn't work with QuickTime .mov files). I'd use this with caution. – Jack Jan 06 '22 at 22:40
7

Capture the video and output the duration is seconds

import cv2 as cv
vidcapture = cv.VideoCapture('myvideo.mp4')
fps = vidcapture.get(cv.CAP_PROP_FPS)
totalNoFrames = vidcapture.get(cv.CAP_PROP_FRAME_COUNT)
durationInSeconds = totalNoFrames / fps

print("durationInSeconds:", durationInSeconds, "s")
Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
4

First calculate frame per second like this

import cv2 as cv
# cap = cv.VideoCapture...
fps = cap.get(cv.CAP_PROP_FPS)

Then duration can be calculated as (number of frames) / (frames per second)

 duration = float(num_frames) / float(fps) # in seconds
Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
Mitiku
  • 5,337
  • 3
  • 18
  • 35
  • 3
    Unfortunately, this does not always work. CAP_PROP_FPS comes from header data, it is not reliably calculated – Connor May 21 '19 at 05:53
2

In my personal experience I've been using the OpenCV method. Try this code:

import cv2 as cv

def get_dur(filename):
    video = cv.VideoCapture(filename)
    fps = video.get(cv.CAP_PROP_FPS)
    frame_count = video.get(cv.CAP_PROP_FRAME_COUNT)
    seconds = frame_count / fps
    minutes = int(seconds / 60)
    rem_sec = int(seconds % 60)
    return f"{minutes}:{rem_sec}"

print(get_dur("dafuck.mp4"))
Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
  • You can use python's divmod function to calculate the quotient (minutes) and remainder (seconds) at once. For example for 100 s: minutes, seconds = divmod(100, 60) – Michael S. May 06 '23 at 21:35
1

I noticed a weird phenomenon that many video DO NOT HAVE as much frames as the vid.get(cv.CAP_PROP_FRAME_COUNT) gets.

I suppose that the video duration should be the divided value of TOTAL FRAMES by FPS, but it always mismatch. The video duration would be longer than we calculated. Considering what FFMPEG does, the original video might has some empty frames.

Hope this help.

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
FantasyJXF
  • 754
  • 7
  • 14