104

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?

Tarantula
  • 19,031
  • 12
  • 54
  • 71
Louise
  • 6,193
  • 13
  • 36
  • 36

19 Answers19

232

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
llogan
  • 121,796
  • 28
  • 232
  • 243
Ivan Neeson
  • 2,823
  • 2
  • 16
  • 11
  • 4
    This is the way to go. ffmpeg -i always wanted to transcode a new file after printing the data. Way cleaner solution right here. – Pirkka Esko Oct 13 '14 at 08:53
  • 3
    Careful though. ffprobe reads metadata. Depending on the file source this could be inaccurate. – Tovi Newman Sep 22 '20 at 20:31
  • @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. https://trac.ffmpeg.org/wiki/FFprobeTips#Getdurationbydecoding – jarno Dec 30 '22 at 12:32
  • `ffprobe` will return 6 digits for microseconds if -sexagesimal option is present. To have 2 digits you can excute: `ffprobe -i -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. – Mara Clementine May 18 '23 at 15:19
67

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 ,
Louis Marascio
  • 2,629
  • 24
  • 28
19

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

Community
  • 1
  • 1
Saucier
  • 4,200
  • 1
  • 25
  • 46
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

vivisidea
  • 445
  • 5
  • 6
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
rupinderjeet
  • 2,984
  • 30
  • 54
gemelen
  • 619
  • 10
  • 18
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",
      ...
      ...
petezurich
  • 9,280
  • 9
  • 43
  • 57
  • This code doesn't work: `Traceback (most recent call last):` `File "ffprobe.py", line 9, in ` `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)` – Rabindranath Andujar Oct 24 '19 at 10:46
  • @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. – petezurich Oct 26 '19 at 20:40
  • 1
    This script will fail for filenames with special characters on both linux and windows – agarg May 11 '20 at 03:06
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

Community
  • 1
  • 1
digitalfootmark
  • 577
  • 1
  • 5
  • 19
2

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

user3413723
  • 11,147
  • 6
  • 55
  • 64
  • 1
    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. – jarno Oct 20 '22 at 19:25
  • It is good that you show the reference. Though similar (and most popular) answer has already been posted years ago (https://stackoverflow.com/a/22243834/4414935) – jarno Dec 30 '22 at 12:18
1
ffmpeg -i abc.mp4 2>&1 | grep Duration | cut -d ' ' -f 4 | sed s/,//

gives output

HH:MM:SS.milisecs

sparsh turkane
  • 1,165
  • 12
  • 13
  • `grep`, `cut`, and `sed` are unecessary. See [Ivan's answer](http://stackoverflow.com/a/22243834/1109017). – llogan Nov 28 '16 at 18:37
  • why unnecessary i don't understand it gives the result – sparsh turkane Nov 30 '16 at 04:02
  • 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. – llogan Dec 01 '16 at 01:17
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

1

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}'
jarno
  • 787
  • 10
  • 21
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")
0

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)`

Sadhana Singh
  • 197
  • 2
  • 4
  • 12
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
Benny Jobigan
  • 5,078
  • 2
  • 31
  • 41
-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.

phuclv
  • 37,963
  • 15
  • 156
  • 475
AdmiralSmith
  • 105
  • 2
-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

phuclv
  • 37,963
  • 15
  • 156
  • 475
AdmiralSmith
  • 105
  • 2
  • calling `strlen` everytime is a bad idea, and `correct[strlen(time)]='/0';` is definitely wrong. It should be `'\0'` instead of `'/0'` – phuclv Mar 16 '21 at 06:49
-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
Mike
  • 493
  • 5
  • 14
-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 !!

muralisc
  • 16
  • 2
  • 1
    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. – llogan Sep 17 '14 at 22:51
-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;
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291