134

To get a lot of information about a media file one can do

ffmpeg -i <filename> 

where it will output a lot of lines, one in particular

Duration: 00:08:07.98, start: 0.000000, bitrate: 2080 kb/s 

I would like to output only 00:08:07.98, so I try

ffmpeg -i file.mp4 | grep Duration| sed 's/Duration: \(.*\), start/\1/g' 

But it prints everything, and not just the length.

Even ffmpeg -i file.mp4 | grep Duration outputs everything.

How do I get just the duration length?

1
  • 1
    IMHO MediaInfo would certainly offer you a much easier to parse output. Commented Sep 5, 2012 at 18:33

19 Answers 19

287

You can use ffprobe:

ffprobe -i <file> -show_entries format=duration -v quiet -of csv="p=0" 

It will output the duration in seconds, such as:

154.12 

Adding the -sexagesimal option will output duration as hours:minutes:seconds.microseconds:

00:02:34.12 
Sign up to request clarification or add additional context in comments.

5 Comments

This is the way to go. ffmpeg -i always wanted to transcode a new file after printing the data. Way cleaner solution right here.
Careful though. ffprobe reads metadata. Depending on the file source this could be inaccurate.
@PirkkaEsko nowadays ffmpeg -i does not always decode the input file, but will show Duration from metadata. However ffmpeg -i inputfile -f null - will decode and give you strict answer, but with performance cost. trac.ffmpeg.org/wiki/FFprobeTips#Getdurationbydecoding
ffprobe will return 6 digits for microseconds if -sexagesimal option is present. To have 2 digits you can excute: ffprobe -i <file> -show_entries format=duration -v quiet -of csv="p=0" | rev | cut -c 5- | rev, due to the fact that real format of duration is h:mm:ss.ms. So, hour have only one digit for hours, not two. My example stands for any video duration and returns 2 digits for microseconds.
Duration is contained in format and stream, so it's possible to select the duration of a certain stream ffprobe -loglevel error -select_streams a:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 file.mp4
73

ffmpeg is writing that information to stderr, not stdout. Try this:

ffmpeg -i file.mp4 2>&1 | grep Duration | sed 's/Duration: \(.*\), start/\1/g' 

Notice the redirection of stderr to stdout: 2>&1

EDIT:

Your sed statement isn't working either. Try this:

ffmpeg -i file.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d , 

11 Comments

Grep is unnecessary,sed -n 's/Duration: \(.*\), start/\1/gp' is suffice.
Actually, sed is unnecessary: ffmpeg -i file.mp4 2>&1 | grep -o -P "(?<=Duration: ).*?(?=,)"
What's the context for this if I want to store the duration as a variable to be used within the same PHP script?
Using ffprobe as instructed in other answers seems a way cleaner and hassle-free-er approach :)
@PirkkaEsko ffmpeg will report the correct duration in some cases when using ffprobe gives you incorrect or missing duration due to corrupt, truncated, or damaged files.
|
21

From my experience many tools offer the desired data in some kind of a table/ordered structure and also offer parameters to gather specific parts of that data. This applies to e.g. smartctl, nvidia-smi and ffmpeg/ffprobe, too. Simply speaking - often there's no need to pipe data around or to open subshells for such a task.

As a consequence I'd use the right tool for the job - in that case ffprobe would return the raw duration value in seconds, afterwards one could create the desired time format on his own:

$ ffmpeg --version ffmpeg version 2.2.3 ... 

The command may vary dependent on the version you are using.

#!/usr/bin/env bash input_file="/path/to/media/file" # Get raw duration value ffprobe -v quiet -print_format compact=print_section=0:nokey=1:escape=csv -show_entries format=duration "$input_file" 

An explanation:

"-v quiet": Don't output anything else but the desired raw data value

"-print_format": Use a certain format to print out the data

"compact=": Use a compact output format

"print_section=0": Do not print the section name

":nokey=1": do not print the key of the key:value pair

":escape=csv": escape the value

"-show_entries format=duration": Get entries of a field named duration inside a section named format

Reference: ffprobe man pages

2 Comments

Excellent. Machine readable answer!
Adding the -sexagesimal option outputs the duration as hh:mm:ss:microsecs
11

I recommend using json format, it's easier for parsing

ffprobe -i your-input-file.mp4 -v quiet -print_format json -show_format -show_streams -hide_banner { "streams": [ { "index": 0, "codec_name": "aac", "codec_long_name": "AAC (Advanced Audio Coding)", "profile": "HE-AACv2", "codec_type": "audio", "codec_time_base": "1/44100", "codec_tag_string": "[0][0][0][0]", "codec_tag": "0x0000", "sample_fmt": "fltp", "sample_rate": "44100", "channels": 2, "channel_layout": "stereo", "bits_per_sample": 0, "r_frame_rate": "0/0", "avg_frame_rate": "0/0", "time_base": "1/28224000", "duration_ts": 305349201, "duration": "10.818778", "bit_rate": "27734", "disposition": { "default": 0, "dub": 0, "original": 0, "comment": 0, "lyrics": 0, "karaoke": 0, "forced": 0, "hearing_impaired": 0, "visual_impaired": 0, "clean_effects": 0, "attached_pic": 0 } } ], "format": { "filename": "your-input-file.mp4", "nb_streams": 1, "nb_programs": 0, "format_name": "aac", "format_long_name": "raw ADTS AAC (Advanced Audio Coding)", "duration": "10.818778", "size": "37506", "bit_rate": "27734", "probe_score": 51 } } 

you can find the duration information in format section, works both for video and audio

Comments

8

In case of one request parameter it is simplier to use mediainfo and its output formatting like this (for duration; answer in milliseconds)

mediainfo --Output="General;%Duration%" ~/work/files/testfiles/+h263_aac.avi 

outputs

24840 

4 Comments

This should be 'mediainfo --Inform="General;%Duration%" ~/work/files/testfiles/+h263_aac.avi'
Both forms work identically within mediainfo v18.05 (and seems to be with previous versions).
Very fast compared to ffmpeg or ffprobe.
--Inform is the way told in the manual page.
4

If you want to retrieve the length (and possibly all other metadata) from your media file with ffmpeg by using a python script you could try this:

import subprocess import json input_file = "< path to your input file here >" metadata = subprocess.check_output(f"ffprobe -i {input_file} -v quiet -print_format json -show_format -hide_banner".split(" ")) metadata = json.loads(metadata) print(f"Length of file is: {float(metadata['format']['duration'])}") print(metadata) 

Output:

Length of file is: 7579.977143 { "streams": [ { "index": 0, "codec_name": "mp3", "codec_long_name": "MP3 (MPEG audio layer 3)", "codec_type": "audio", "codec_time_base": "1/44100", "codec_tag_string": "[0][0][0][0]", "codec_tag": "0x0000", "sample_fmt": "fltp", "sample_rate": "44100", "channels": 2, "channel_layout": "stereo", "bits_per_sample": 0, "r_frame_rate": "0/0", "avg_frame_rate": "0/0", "time_base": "1/14112000", "start_pts": 353600, "start_time": "0.025057", "duration_ts": 106968637440, "duration": "7579.977143", "bit_rate": "320000", ... ... 

3 Comments

This code doesn't work: Traceback (most recent call last): File "ffprobe.py", line 9, in <module> print("Length of file is: {}".format(float(length["format"]["duration"]))) NameError: name 'length' is not defined This should do the job: import subprocess import json input_file = "out.mp4" metadata = subprocess.check_output(f"ffprobe -i {input_file} -v quiet -print_format json -show_format -hide_banner".split(" ")) metadata = json.loads(metadata) print("Length of file is: {}".format(float(metadata["format"]["duration"]))) print(metadata)
@RabindranathAndujar I rechecked. You are right. The code works, but the line for the printout had an error in it. I corrected the code and now it runs fine. Thanks for pointing it out.
This script will fail for filenames with special characters on both linux and windows
4

No grepping or anything like that required. Just put this one command and you will get precise time with microsecond accuracy!

ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 file.mp4 

From ffmpeg docs https://trac.ffmpeg.org/wiki/FFprobeTips

2 Comments

Time is shown in seconds, but with one microsecond accuracy. It is good to use file: prefix for the input file, in case the file name contains a colon. This ffprobe is fast but not quite as fast as the mediainfo way shown in another answer.
It is good that you show the reference. Though similar (and most popular) answer has already been posted years ago (stackoverflow.com/a/22243834/4414935)
3

This is slow as it decodes the input, but will show correct duration even if there is wrong/missing information in metadata:

ffmpeg -i <filename> -f null - 2>&1 | awk -F= 'BEGIN{RS=" "}/^time=/{t=$2}END{print t}' 

4 Comments

I did something similar by looking at time= and I ran into a timezone issue with DST. Have you run into that before?
@JohnPollard no, I have not tested that. What kind of output did ffmpeg give then?
We noticed that the time was off by an hour. It's no longer a problem but was a problem on the Sunday DST went into effect. I changed our duration calculation back to the old way because of this.
@JohnPollard the answer is based on the wiki. It seems like there is a bug in ffmpeg. What do you mean by the old way?
2

For those who want to perform the same calculations with no additional software in Windows, here is the script for command line script:

set input=video.ts ffmpeg -i "%input%" 2> output.tmp rem search " Duration: HH:MM:SS.mm, start: NNNN.NNNN, bitrate: xxxx kb/s" for /F "tokens=1,2,3,4,5,6 delims=:., " %%i in (output.tmp) do ( if "%%i"=="Duration" call :calcLength %%j %%k %%l %%m ) goto :EOF :calcLength set /A s=%3 set /A s=s+%2*60 set /A s=s+%1*60*60 set /A VIDEO_LENGTH_S = s set /A VIDEO_LENGTH_MS = s*1000 + %4 echo Video duration %1:%2:%3.%4 = %VIDEO_LENGTH_MS%ms = %VIDEO_LENGTH_S%s 

Same answer posted here: How to crop last N seconds from a TS video

1 Comment

Alternately ffprobe -i "input.mp4" -show_entries format=duration -v quiet -of csv="p=0" -sexagesimal
1
ffmpeg -i abc.mp4 2>&1 | grep Duration | cut -d ' ' -f 4 | sed s/,// 

gives output

HH:MM:SS.milisecs

3 Comments

grep, cut, and sed are unecessary. See Ivan's answer.
why unnecessary i don't understand it gives the result
Because you can just use ffprobe alone. Also, the output of ffmpeg is for informational purposes only and not for parsing: it is not guaranteed to always about the same structure, format, and information with various ffmpeg versions and various input formats.
1

This is my really simple solution using ffmpeg and awk. The output of ffmpeg -i file.mp3 contain a string Duration: 00:00:04.80, bitrate: 352 kb/s. Just simply using awk:

ffmpeg -i file.mp3 |& awk '/Duration:/ {print $2}' 

I can print the expected result: 00:00:04.80

Comments

0
# Returns duration (in seconds) of a video $1 (uses ffmpeg). get_video_duration() { OUTPUT=$(ffmpeg -i "$1" -vframes 1 -f rawvideo -y /dev/null 2>&1) || { debug -e "get_video_duration: error running ffmpeg:\n$OUTPUT"; return 1; } DURATION=$(echo "$OUTPUT" | grep -m1 "^[[:space:]]*Duration:" | cut -d":" -f2- | cut -d"," -f1 | sed "s/[:\.]/ /g") || { debug -e "get_video_duration: error parsing duration:\n$OUTPUT"; return 1; } read HOURS MINUTES SECONDS DECISECONDS <<< "$DURATION" echo $((10#$HOURS * 3600 + 10#$MINUTES * 60 + 10#$SECONDS)) } 

Usage:

DURATION=$(get_video_duration "$VIDEO") 

Comments

0

I tried the top answers, but none worked because my audio didn't have any metadata. I finally found an answer that worked on this website.

ffmpeg -i "${file}" -f null /dev/null 2>&1 | grep -oE "[0-9]{1}:[0-9]{2}:[0-9]{2}" | tail -n 1 

Comments

-1

Best Solution: cut the export do get something like 00:05:03.22

ffmpeg -i input 2>&1 | grep Duration | cut -c 13-23 

Comments

-1

Argh. Forget that. It looks like I have to get the cobwebs out of my C and C++ programming and use that instead. I do not know all the shell tricks to get it to work.

This is how far I got.

ffmpeg -i myfile 2>&1 | grep "" > textdump.txt 

and then I would probably extract the duration with a C++ app instead by extracting tokens.

I am not posting the solution because I am not a nice person right now


Update - I have my approach to getting that duration time stamp

Step 1 - Get the media information on to a text file

ffprobe -i myfile 2>&1 | grep "" > textdump.txt 

OR

ffprobe -i myfile 2>&1 | awk '{ print }' > textdump.txt 

Step 2 - Home in on the information needed and extract it

cat textdump.txt | grep "Duration" | awk '{ print $2 }' | ./a.out 

Notice the a.out. That is my C code to chop off the resulting comma because the output is something like 00:00:01.331,

Here is the C code that takes stdin and outputs the correct information needed. I had to take the greater and less than signs out for viewing.

#include stdio.h #include string.h void main() { //by Admiral Smith Nov 3. 2016 char time[80]; int len; char *correct; scanf("%s", &time); correct = (char *)malloc(strlen(time)); if (!correct) { printf("\nmemory error"); return; } memcpy(correct,&time,strlen(time)-1); correct[strlen(time)]='/0'; printf("%s", correct); free(correct); } 

Now the output formats correctly like 00:00:01.33

1 Comment

calling strlen everytime is a bad idea, and correct[strlen(time)]='/0'; is definitely wrong. It should be '\0' instead of '/0'
-1

I would just do this in C++ with a text file and extract the tokens. Why? I am not a linux terminal expert like the others.

To set it up I would do this in Linux

ffmpeg -i <file> 2>&1 | grep "" > mytext.txt 

and then run some C++ app to get the data needed. Maybe extract all the important values and reformat it for further processing by using tokens. I will just have to work on my own solution and people will just make fun of me because I am a Linux newbie and I do not like scripting too much.

Comments

-1

use ffprobe which is used to extract metadata from media files

install ffprobe with pip

pip install ffprobe-python

`from subprocess import check_output

file_name = "video1.mp4"

command = str(check_output('ffprobe -i "'+file_name+'" 2>&1 |grep "Duration"',shell=True))
#output: b' Duration: 00:17:56.62, start: 0.000000, bitrate: 397 kb/s\n'

#split the duration in hh:mm:ss format co = a.split(",")[0].split("Duration:")[1].strip()

h, m, s = a.split(':') duration = int(h) * 3600 + int(m) * 60 + float(s)

print(duration)`

Comments

-5

You could try this:

/* * Determine video duration with ffmpeg * ffmpeg should be installed on your server. */ function mbmGetFLVDuration($file){ //$time = 00:00:00.000 format $time = exec("ffmpeg -i ".$file." 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//"); $duration = explode(":",$time); $duration_in_seconds = $duration[0]*3600 + $duration[1]*60+ round($duration[2]); return $duration_in_seconds; } $duration = mbmGetFLVDuration('/home/username/webdir/video/file.mov'); echo $duration; 

Comments

-5

ffmpeg has been substituted by avconv: just substitute avconb to Louis Marascio's answer.

avconv -i file.mp4 2>&1 | grep Duration | sed 's/Duration: \(.*\), start.*/\1/g' 

Note: the aditional .* after start to get the time alone !!

1 Comment

The counterfeit "ffmpeg" from Libav (a fork of the FFmpeg project) has been replaced by avconv from Libav. ffmpeg from FFmpeg is under very active development.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.