FFmpeg append Audio duration to File Name - audio

I'm working on processing some audio files, I'm to get the audio duration and append the duration to the file name i.e audio-lecture-02.30.05.mp3.I have able to get the audio duration using FFmpeg using ffmpeg -i lecture.mp3 2>&1 | grep Duration and the output is Duration: 01:27:25.70, start: 0.000000, bitrate: 64 kb/s is there a way to extract this duration and append the file name?
Thanks in advance.

The output from ffmpeg is not meant to be machine parsed. Use ffprobe instead.
Append duration in seconds
#!/bin/bash
input="input.mp3"
duration=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$input")
mv "$input" "${input%.*}-$duration.${input##*.}"
Results in input-5025.670000.mp3.
Append duration in HH.MM.SS.ms
#!/bin/bash
input="input.mp3"
duration=$(ffprobe -v error -show_entries format=duration -sexagesimal -of csv=p=0 "$input")
mv "$input" "${input%.*}-${duration//:/.}.${input##*.}"
Results in input-1.23.45.670000.mp3.

Related

Using android FFMPEG library for limited video frames [duplicate]

I need to create multiple thumbnails (ex. 12) from a video at equal times using ffmpeg.
So for example if the video is 60 seconds - I need to extract a screenshot every 5 seconds.
Im using the following command to get the frame in the 5ths second.
ffmpeg -ss 5 -i video.webm -frames:v 1 -s 120x90 thumbnail.jpeg
Is there a way to get multiple thumbnails with one command?
Get duration (optional)
Get duration using ffprobe. This is an optional step but is helpful if you will be scripting or automating the next commands.
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4
Example result:
60.000000
Output one frame every 5 seconds
Using the select filter:
ffmpeg -i input.mp4 -vf "select='not(mod(t,5))',setpts=N/FRAME_RATE/TB" output_%04d.jpg
or
ffmpeg -i input.mp4 -vf "select='not(mod(t,5))'" -vsync vfr output_%04d.jpg
Files will be named output_0001.jpg, output_0002.jpg, output_0003.jpg, etc. See image muxer documentation for more info and options.
To adjust JPEG quality see How can I extract a good quality JPEG image from a video with ffmpeg?
Output specific number of equally spaced frames
This will output 12 frames from a 60 second duration input:
ffmpeg -i input.mp4 -vf "select='not(mod(t,60/12))'" -vsync vfr output_%04d.jpg
You must manually enter the duration of the input (shown as 60 in the example above). See an automatic method immediately below.
Using ffprobe to automatically provide duration value
Bash example:
input=input.mp4; ffmpeg -i "$input" -vf "select='not(mod(t,$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 $input)/12))'" -vsync vfr output_%04d.jpg
With scale filter
Example using the scale filter:
ffmpeg -i input.mp4 -vf "select='not(mod(t,60/12))',scale=120:-1" -vsync vfr output_%04d.jpg
$ffmpegPath = exec('which ffmpeg'); $ffprobePath = exec('which ffprobe');
$command = "$ffprobePath -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 $input_video"; $video_duration = shell_exec($command);
$thumbnails_output = 'output%02d.png'; $command = "$ffmpegPath -i $input_video -vf fps=3/$video_duration $thumbnails_output";
shell_exec($command);

display only lines from output that contains a specified word

I'm looking for a way to get only the lines that contains a specified word, in this case all lines that contains the word Stream from an output
I've tried;
streams=$(ffprobe -i "movie.mp4" | grep "Stream")
but that didn't get any results..
or do I need to output it to a file and then try to extract the lines I'm looking for?
#paulsm4 was spot on ... the output goes to STDERR.
streams=$(ffprobe -i "movie.mp4" |& grep "Stream")
Note the &
No need for grep. Just use ffprobe directly to get whatever info you need.
Output all info
ffprobe -loglevel error -show_format -show_streams input.mp4
Video info only
ffprobe -loglevel error -show_streams -select_streams v input.mp4
Audio info only
ffprobe -loglevel error -show_streams -select_streams a input.mp4
Width x height
See Getting video dimension / resolution / width x height from ffmpeg
Duration
See How to get video duration?
Format / codec
Is there a way to use ffmpeg to determine the encoding of a file before transcoding?
Using ffprobe to check audio-only files
Info on frames
See Get video frames information with ffmpeg
More info and examples
See FFmpeg Wiki: ffprobe

How make video and audio duration the same with ffmpeg?

I am merging a few user-generated videos together with ffmpeg-concat and sometimes run into an audio sync issue. I figured that it fails when audio and video duration mismatch. E.g.:
ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 IMG_7679.mov
16.666016
ffprobe -v error -select_streams a:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 IMG_7679.mov
16.670998
Question is — how do make audio and video duration equal prior to concat, without loosing the content?
Or maybe classic ffmpeg's concat solves this issue somehow and I should use it?
you can use the trim and or atrim filter to cut a part of the audio or video.
[v]trim=0:3.23,setpts=START-PTS[vout]
[a]atrim=0:3.23,asetpts=START-PTS[aout]
setpts and asetpts fixes the timestamps

Extract every audio and subtitles from a video with ffmpeg

I have multiple audio tracks and subtitles to extract in a single .mkv file. I'm new to ffmpeg commands, this is what I've tried (audio):
ffmpeg -i VIDEO.mkv -vn -acodec copy AUDIO.aac
It just extract 1 audio. What I want is tell ffmpeg to extract every single audio files and subtitle files to a destination, and keep the original name of each files and extensions. (Because I don't know which extension does the audio files are, sometimes maybe .flac or .aac).
I'm not sure about the solutions I'd found online, because it's quite complicated, and I need explanations to know how it's works, so that I can manipulate the command in the future. By the way, I planned to run the code from Windows CMD. Thanks.
There is no option yet in ffmpeg to automatically extract all streams into an appropriate container, but it is certainly possible to do manually.
You only need to know the appropriate containers for the formats you want to extract.
Default stream selection only chooses one stream per stream type, so you have to manually map each stream with the -map option.
1. Get input info
Using ffmpeg or ffprobe you can get the info in each individual stream, and there is a wide variety of formats (xml, json, cvs, etc) available to fit your needs.
ffmpeg example
ffmpeg -i input.mkv
The resulting output (I cut out some extra stuff, the stream numbers and format info are what is important):
Input #0, matroska,webm, from 'input.mkv':
Metadata:
Duration: 00:00:05.00, start: 0.000000, bitrate: 106 kb/s
Stream #0:0: Video: h264 (High 4:4:4 Predictive), yuv444p, 320x240 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 1k tbn, 50 tbc (default)
Stream #0:1: Audio: vorbis, 44100 Hz, mono, fltp (default)
Stream #0:2: Audio: aac, 44100 Hz, mono, fltp (default)
Stream #0:3: Audio: flac, 44100 Hz, mono, fltp (default)
Stream #0:4: Subtitle: ass (default)
ffprobe example
ffprobe -v error -show_entries stream=index,codec_name,codec_type input.mkv
The resulting output:
[STREAM]
index=0
codec_name=h264
codec_type=video
[/STREAM]
[STREAM]
index=1
codec_name=vorbis
codec_type=audio
[/STREAM]
[STREAM]
index=2
codec_name=aac
codec_type=audio
[/STREAM]
[STREAM]
index=3
codec_name=flac
codec_type=audio
[/STREAM]
[STREAM]
index=4
codec_name=ass
codec_type=subtitle
[/STREAM]
2. Extract the streams
Using the info from one of the commands above:
ffmpeg -i input.mkv \
-map 0:v -c copy video_h264.mkv \
-map 0:a:0 -c copy audio0_vorbis.oga \
-map 0:a:1 -c copy audio1_aac.m4a \
-map 0:a:2 -c copy audio2.flac \
-map 0:s -c copy subtitles.ass
In this case, the example above is the same as:
ffmpeg -i input.mkv \
-map 0:0 -c copy video_h264.mkv \
-map 0:1 -c copy audio0_vorbis.oga \
-map 0:2 -c copy audio1_aac.m4a \
-map 0:3 -c copy audio2.flac \
-map 0:4 -c copy subtitles.ass
I prefer the first example because the input file index:stream specifier:stream index is more flexible and efficient; it is also less prone to incorrect mapping.
See documentation on stream specifiers and the -map option to fully understand the syntax. Additional info is in the answer to FFmpeg mux video and audio (from another video) - mapping issue.
These examples will stream copy (re-mux) so no re-encoding will occur.
Container formats
A partial list to match the stream with the output extension for some common formats:
Video Format
Extensions
H.264
.mp4, .m4v, .mov, .h264, .264
H.265/HEVC
.mp4, .h265, .265
VP8/VP9
.webm
AV1
.mp4
MPEG-4
.mp4, .avi
MPEG-2
.mpg, .vob, .ts
DV
.dv, .avi, .mov
Theora
.ogv/.ogg
FFV1
.mkv
Almost anything
.mkv, .nut
Audio Format
Extensions
AAC
.m4a, .aac
MP3
.mp3
PCM
.wav
Vorbis
.oga/.ogg
Opus
.opus, .oga/.ogg, .mp4
FLAC
.flac, .oga/.ogg
Almost anything
.mka, .nut
Subtitle Format
Extensions
Subrip/SRT
.srt
SubStation Alpha/ASS
.ass
You would first list all the audio streams:
ffmpeg -i VIDEO.mkv
and then based on the output you can compile the command to extract the audio tracks individually.
Using some shell script you can then potentially automate this in a script file so that you can do it generically for any mkv file.
Subtitles are pretty much the same. The subtitles will be printed in the info and then you can extract them, similar to:
ffmpeg -threads 4 -i VIDEO.mkv -vn -an -codec:s:0.2 srt myLangSubtitle.srt
0.2 is the identifier that you have to read from the info.
I solved it like this:
ffprobe -show_entries stream=index,codec_type:stream_tags=language -of compact $video1 2>&1 | { while read line; do if $(echo "$line" | grep -q -i "stream #"); then echo "$line"; fi; done; while read -d $'\x0D' line; do if $(echo "$line" | grep -q "time="); then echo "$line" | awk '{ printf "%s\r", $8 }'; fi; done; }
Output:
Only set $video1 var before command.
Enjoy it!.
If someone steps in this question with a modern version of ffmpeg, it looks like they added the option there.
I needed to convert a file by maintaining all tracks:
ffmpeg -i "${input_file}" -vcodec hevc -crf 28 -map 0 "${output_file}"
To achieve what the original question asked, probably this could be used:
mappings="`ffmpeg -i \"${filein}\" |& awk 'BEGIN { i = 1 }; /Stream.*Audio/ {gsub(/^ *Stream #/, \"-map \"); gsub(/\(.*$/, \" -acodec mp3 audio\"i\".mp3\"); print; i +=1}'`"
ffmpeg -i "${input_file}" ${mappings}
The 1st line (mappings=...) extracts the existing audio streams and converts them in "-map X:Y -acodec mp3 FILENAME", while the 2nd one executes the extraction
The following script extracts all audio streams from files in current directory
ls |parallel "ffmpeg -i {} 2>&1 |\
sed -n 's/.*Stream \#\(.\+\)\:\(.\+\)\: Audio\: \([a-zA-Z0-9]\+\).*$/-map \1:\2 -c copy \"{.}.\1\2.\3\"/p' |\
xargs -n5 ffmpeg -i {} "

ffmpeg modify audio length/size ( stretch or shrink)

I am developing a web app, where people can record videos. I have been able to send chunks of audio n video to server successfully, where I am trying to combine them and return as single proper file.
my problem is if the recording is for one hour, after merging the chunks
video length : 1:00:00 , audio length : 00:59:30,
now, this is not a issue of audio not getting recorded( I have checked that), the problem is, somehow, when i merge the chunks of audio, it shrinks,
I find that it is progressive sync issue where it gets worse and worse as time increases.
I have searched the net for the solution, most places say async, I have tried using it, but to no avail, is the below usage correct?
ffmpeg -i audio.wav -async 1 -i video.webm -y -strict -2 v.mp4
(v.mp4 is the final file that I provide to the users.)
found a solution(or a temp fix, depends of how you look at it),
it involves combination of ffmpeg and ffprobe ... i have done audio streching( ratio<1)
ffprobe -i a.mp3 -show_entries format=duration -v quiet -print_format json
ffprobe -i v.mp4 -show_entries format=duration -v quiet -print_format json
ffmpeg -i a.mp3 -filter:a atempo="0.9194791304347826" aSync.mp3 // audio is being stretched.
ffmpeg -i aSync.mp3 -i v.mp4 final.mp4

Resources