I need to get the video duration in Python. The video formats that I need to get are MP4, Flash video, AVI, and MOV... I have a shared hosting solution, so I have no FFmpeg support.
I need to get the video duration in Python. The video formats that I need to get are MP4, Flash video, AVI, and MOV... I have a shared hosting solution, so I have no FFmpeg support.
(year 2020 answer)
Solutions:
opencv 0.0065 sec āffprobe 0.0998 secmoviepy 2.8239 secā OpenCV method:
def with_opencv(filename):
import cv2
video = cv2.VideoCapture(filename)
duration = video.get(cv2.CAP_PROP_POS_MSEC)
frame_count = video.get(cv2.CAP_PROP_FRAME_COUNT)
return duration, frame_count
Usage: print(with_opencv('my_video.webm'))
Other:
ffprobe method:
def with_ffprobe(filename):
import subprocess, json
result = subprocess.check_output(
f'ffprobe -v quiet -show_streams -select_streams v:0 -of json "{filename}"',
shell=True).decode()
fields = json.loads(result)['streams'][0]
duration = fields['tags']['DURATION']
fps = eval(fields['r_frame_rate'])
return duration, fps
moviepy method:
def with_moviepy(filename):
from moviepy.editor import VideoFileClip
clip = VideoFileClip(filename)
duration = clip.duration
fps = clip.fps
width, height = clip.size
return duration, fps, (width, height)
Use a modern method with https://github.com/kkroening/ffmpeg-python (pip install ffmpeg-python --user). Don't forget to install ffmpeg too.
Get video info:
import ffmpeg
info=ffmpeg.probe(filename)
print(f"duration={info['format']['duration']}")
print(f"framerate={info['streams'][0]['avg_frame_rate']}")
Use ffmpeg-python package to also easily create, edit and apply filters to videos.
from subprocess import check_output
file_name = "movie.mp4"
#For Windows
a = str(check_output('ffprobe -i "'+file_name+'" 2>&1 |findstr "Duration"',shell=True))
#For Linux
#a = str(check_output('ffprobe -i "'+file_name+'" 2>&1 |grep "Duration"',shell=True))
a = a.split(",")[0].split("Duration:")[1].strip()
h, m, s = a.split(':')
duration = int(h) * 3600 + int(m) * 60 + float(s)
print(duration)
A function I came up with. This is basically using only ffprobe arguments
from subprocess import check_output, CalledProcessError, STDOUT
def getDuration(filename):
command = [
'ffprobe',
'-v',
'error',
'-show_entries',
'format=duration',
'-of',
'default=noprint_wrappers=1:nokey=1',
filename
]
try:
output = check_output( command, stderr=STDOUT ).decode()
except CalledProcessError as e:
output = e.output.decode()
return output
fn = '/app/648c89e8-d31f-4164-a1af-034g0191348b.mp4'
print( getDuration( fn ) )
Outputs duration like this:
7.338000
As reported here https://www.reddit.com/r/moviepy/comments/2bsnrq/is_it_possible_to_get_the_length_of_a_video/
you could use the moviepy module
from moviepy.editor import VideoFileClip clip = VideoFileClip("my_video.mp4") print( clip.duration )
If you're trying to get the duration of many videos in a folder it'll crash giving the error: AttributeError: 'AudioFileClip' object has no attribute 'reader'
So, in order to avoid that you'll need to add
clip.close()
Based on this: https://zulko.github.io/moviepy/_modules/moviepy/video/io/VideoFileClip.html
So the code would look like this:
from moviepy.editor import VideoFileClip
clip = VideoFileClip("my_video.mp4")
print( clip.duration )
clip.close()
Cheers! :)
The above pymediainfo answer really helped me. Thank you.
As a beginner, it did take a while to find out what was missing (sudo apt install mediainfo) and how to also address attributes in other ways (see below).
Hence this additional example:
# sudo apt install mediainfo
# pip3 install pymediainfo
from pymediainfo import MediaInfo
media_info = MediaInfo.parse('/home/pi/Desktop/a.mp4')
for track in media_info.tracks:
#for k in track.to_data().keys():
# print("{}.{}={}".format(track.track_type,k,track.to_data()[k]))
if track.track_type == 'Video':
print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
print("{} width {}".format(track.track_type,track.to_data()["width"]))
print("{} height {}".format(track.track_type,track.to_data()["height"]))
print("{} duration {}s".format(track.track_type,track.to_data()["duration"]/1000.0))
print("{} duration {}".format(track.track_type,track.to_data()["other_duration"][3][0:8]))
print("{} other_format {}".format(track.track_type,track.to_data()["other_format"][0]))
print("{} codec_id {}".format(track.track_type,track.to_data()["codec_id"]))
print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
elif track.track_type == 'Audio':
print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
print("{} format {}".format(track.track_type,track.to_data()["format"]))
print("{} codec_id {}".format(track.track_type,track.to_data()["codec_id"]))
print("{} channel_s {}".format(track.track_type,track.to_data()["channel_s"]))
print("{} other_channel_s {}".format(track.track_type,track.to_data()["other_channel_s"][0]))
print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
print("********************************************************************")
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Video width 1920
Video height 1080
Video duration 383.84s
Video duration 00:06:23
Video other_format AVC
Video codec_id avc1
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Audio format AAC
Audio codec_id mp4a-40-2
Audio channel_s 2
Audio other_channel_s 2 channels
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Open cmd terminal and install python package:mutagen using this command
python -m pip install mutagen
then use this code to get the video duration and its size:
import os
from mutagen.mp4 import MP4
audio = MP4("filePath")
print(audio.info.length)
print(os.path.getsize("filePath"))
Here is what I use in prod today, using cv2 way work well for mp4, wmv and flv which is what I needed:
try:
import cv2 # opencv-python - optional if using ffprobe
except ImportError:
cv2 = None
import subprocess
def get_playback_duration(video_filepath, method='cv2'): # pragma: no cover
"""
Get video playback duration in seconds and fps
"This epic classic car collection centres on co.webm"
:param video_filepath: str, path to video file
:param method: str, method cv2 or default ffprobe
"""
if method == 'cv2': # Use opencv-python
video = cv2.VideoCapture(video_filepath)
fps = video.get(cv2.CAP_PROP_FPS)
frame_count = video.get(cv2.CAP_PROP_FRAME_COUNT)
duration_seconds = frame_count / fps if fps else 0
else: # ffprobe
result = subprocess.check_output(
f'ffprobe -v quiet -show_streams -select_streams v:0 -of json "{video_filepath}"', shell=True).decode()
fields = json.loads(result)['streams'][0]
duration_seconds = fields['tags'].get('DURATION')
fps = eval(fields.get('r_frame_rate'))
return duration_seconds, fps
ffprobe does not work for flv and I couldn't get anything to work for webm. Otherwise, this works great and is being used in prod today.
Referring to the answer of @Nikolay Gogol using opencv-python (cv2):
His method did not work for me (Python 3.8.10, opencv-python==4.5.5.64) and the comments say that opencv can not be used in this case which is also not true.
CAP_PROP_POS_MSEC gives you the millisecond of the current frame that the VideoCapture is at and not the total milliseconds of the video, so when just loading the video this is obviously 0.
But we can actually get the frame rate and the number of total frames to calculate the total number of milliseconds of the video:
import cv2
video = cv2.VideoCapture("video.mp4")
# the frame rate or frames per second
frame_rate = video.get(cv2.CAP_PROP_FPS)
# the total number of frames
total_num_frames = video.get(cv2.CAP_PROP_FRAME_COUNT)
# the duration in seconds
duration = total_num_frames / frame_rate
for anyone that like using the mediainfo program:
import json
import subprocess
#===============================
def getMediaInfo(mediafile):
cmd = "mediainfo --Output=JSON %s"%(mediafile)
proc = subprocess.Popen(cmd, shell=True,
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
stdout, stderr = proc.communicate()
data = json.loads(stdout)
return data
#===============================
def getDuration(mediafile):
data = getMediaInfo(mediafile)
duration = float(data['media']['track'][0]['Duration'])
return duration
Using ffprobe in a function it returns the duration of a video in seconds.
def video_duration(filename):
import subprocess
secs = subprocess.check_output(f'ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 "{filename}"', shell=True).decode()
return secs