How to extract duration time from ffmpeg output?
LinuxBashFfmpegLinux Problem Overview
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?
Linux Solutions
Solution 1 - Linux
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
Solution 2 - Linux
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 ,
Solution 3 - Linux
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
Solution 4 - Linux
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
Solution 5 - Linux
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
Solution 6 - Linux
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",
...
...
Solution 7 - Linux
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: https://stackoverflow.com/questions/20502298/how-to-crop-last-n-seconds-from-a-ts-video/20551848#20551848
Solution 8 - Linux
ffmpeg -i abc.mp4 2>&1 | grep Duration | cut -d ' ' -f 4 | sed s/,//
gives output
HH:MM:SS.milisecs
Solution 9 - Linux
# 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")
Solution 10 - Linux
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
Solution 11 - Linux
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)`
Solution 12 - Linux
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.
Solution 13 - Linux
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
Solution 14 - Linux
Best Solution: cut the export do get something like 00:05:03.22
ffmpeg -i input 2>&1 | grep Duration | cut -c 13-23
Solution 15 - Linux
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;
Solution 16 - Linux
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 !!