FFMPEG, MKVMerge and MKVToolNix: Difference between revisions
mNo edit summary |
mNo edit summary |
||
Line 1: | Line 1: | ||
<noinclude>{{ContentArticleHeader/Linux_Server|toc=off}}{{ContentArticleHeader/Linux_Desktop}}</noinclude> | <noinclude>{{ContentArticleHeader/Linux_Server|toc=off}}{{ContentArticleHeader/Linux_Desktop}}</noinclude> | ||
__TOC__ | __TOC__ | ||
== MKVMerge and MKVToolNix == | |||
== | ====== References ====== | ||
*[http://ubuntuhandbook.org/index.php/2018/08/mkvtoolnix-26-0-0-released/ MKVToolNix 26.0.0 Released, How to Install it in Ubuntu] | *[http://ubuntuhandbook.org/index.php/2018/08/mkvtoolnix-26-0-0-released/ MKVToolNix 26.0.0 Released, How to Install it in Ubuntu] | ||
*[https://askubuntu.com/q/939821/566421 Script to merge Video and subs then delete the existing files (non recursive)] | *[https://askubuntu.com/q/939821/566421 Script to merge Video and subs then delete the existing files (non recursive)] | ||
====== Install <code>MKVToolNix</code> ====== | |||
<syntaxhighlight lang="bash"> | <syntaxhighlight lang="bash"> | ||
cd ~/Downloads | cd ~/Downloads | ||
Line 181: | Line 171: | ||
A possible way to automatically parse the audio codec and name the audio file accordingly would be: | A possible way to automatically parse the audio codec and name the audio file accordingly would be: | ||
<code>for file in *mp4 *avi; do ffmpeg -i "$file" -vn -acodec copy "$file" | <code>for file in *mp4 *avi; do ffmpeg -i "$file" -vn -acodec copy "$file"; ffprobe "$file" 2>&1 | sed -rn 's/.''Audio: (...), .''/\1/p'; done</code> | ||
Note that this command uses sed to parse output from ffprobe for each file, it assumes a 3-letter audio codec name (e.g. mp3, ogg, aac) and will break with anything different. | Note that this command uses sed to parse output from ffprobe for each file, it assumes a 3-letter audio codec name (e.g. mp3, ogg, aac) and will break with anything different. | ||
Line 188: | Line 178: | ||
You can use a Bash "for loop" to encode all files in a directory: | You can use a Bash "for loop" to encode all files in a directory: | ||
<code> | <code>mkdir newfiles</code> | ||
<code> | <code>for f in *.m4a; do ffmpeg -i "$f" -codec:v copy -codec:a libmp3lame -q:a 2 newfiles/"${f%.m4a}.mp3"; done</code> | ||
----<code>ffmpeg -i input.m4a -acodec libmp3lame -ab 128k output.mp3</code> | ----<code>ffmpeg -i input.m4a -acodec libmp3lame -ab 128k output.mp3</code> | ||
Line 200: | Line 190: | ||
===Extract Single Image from a Video at Specified Frame=== | ===Extract Single Image from a Video at Specified Frame=== | ||
<code> | <code>vf [ss][filename][outputFileName]</code> | ||
where <code>vf</code> is a custom bash script as follows: | where <code>vf</code> is a custom bash script as follows: | ||
<code> | <code>ffmpeg -ss $1 -i $2 -qmin 1 -q:v 1 -qscale:v 2 -frames:v 1 -huffman optimal $3.jpg</code> | ||
ss offset = frame number divided by FPS of video = the decimal (in milliseconds) ffmpeg needs i.e. 130.5 | ss offset = frame number divided by FPS of video = the decimal (in milliseconds) ffmpeg needs i.e. 130.5 | ||
Line 214: | Line 204: | ||
===Split a Video into Images=== | ===Split a Video into Images=== | ||
<code> | <code>ffmpeg -i video.flv image%d.jpg</code> | ||
===Convert Images into a Video=== | ===Convert Images into a Video=== | ||
<code> | <code>ffmpeg -f image2 -i image%d.jpg imagestovideo.mpg</code> | ||
===Convert mp4 to webm=== | ===Convert mp4 to webm=== | ||
<code> | <code>ffmpeg -i example.mp4 -f webm -c:v libvpx -b:v 1M -acodec libvorbis example.webm -hide_banner</code> | ||
*[https://www.bugcodemaster.com/article/convert-videos-webm-format-using-ffmpeg more info] | *[https://www.bugcodemaster.com/article/convert-videos-webm-format-using-ffmpeg more info] |
Revision as of 06:55, 25 September 2022
MKVMerge and MKVToolNix
References
- MKVToolNix 26.0.0 Released, How to Install it in Ubuntu
- Script to merge Video and subs then delete the existing files (non recursive)
Install MKVToolNix
cd ~/Downloads
sudo sh -c 'echo "deb https://mkvtoolnix.download/ubuntu/ $(lsb_release -sc) main" >> /etc/apt/sources.list.d/bunkus.org.list'
wget -q -O - https://mkvtoolnix.download/gpg-pub-moritzbunkus.txt | sudo apt-key add -
sudo apt update
sudo apt install mkvtoolnix mkvtoolnix-gui
Install a newer version of FFmpeg
sudo add-apt-repository ppa:jonathonf/ffmpeg-4
sudo apt update
sudo apt install ffmpeg
ffmpeg -version
Convert videos to MKV using FFMPEG
Convert any video supported by FFMPEG to a video file in MKV format using FFMPEG command-line tool.
MKV format is the extension file used for the Matroska Multimedia Container. This is a file format which can hold an unlimited number of video, audio, picture, or subtitle tracks or streams in one file. It is similar in its design to other container types such as MP4 or ASF but it is based in an open specification.
MKV supports many video encoded streams such as H.264, or VP8 encoded video, or AAC, or VORBIS audio streams, which are some of the most common supported stream types. The user playing one MKV file must have a player that supports the encoded streams in order to view the file properly, so if the player supports only the audio stream, the user could only hear the audio but he won't see the video.
We recommend using H.264 or VP8 for video streams and AAC or VORBIS for audio as they are widely supported. However, other encoders can be used. We will show you some of these in this article.
The WEBM format is a profile of MKV files, so when you are converting a video to WEBM format, or you are storing in WEBM format, you are actually storing in MKV format. The difference is that WEBM is a subset of MKV configuration using VP8 encoding for video and VORBIS for audio streams. (VP9 video and OPUS audio have been introduced last years). Read more about how to convert a video file to a webm file using FFMPEG in this article.
So, for converting a video to MKV format you can use the basic FFMPEG command:
ffmpeg -i input_video.avi output_video.mkv
To convert all files in certain directory (reference):
for i in *; do ffmpeg -i "$i" "${i%.*}.mkv"; done
By default this command will produce an output video file using libx264 library (which produces H.264 video stream) and libvorbis library (which produces VORBIS audio stream). You can use the command specifying this options (which will produce the same result):
ffmpeg -i input_video.avi -f matroska -vcodec libx264 -acodec libvorbis output_video.mkv
In which we are using the parameters:
-f matroska
which specifies that the output file will have Matroska format-vcodec libx264
we're telling here to use the libx264 library which encodes video in H.264 coded streams. As we have said before you can use different video encoders. You can use other codecs changing libx264 for 'vp8' if you want to use VP8 encoding through libvpx library or 'vp9' if you want to use VP9 encoding. You can use more video encoders but the most widely supported codecs are H.264 and VP8.-acodec libvorbis
which specifies to use the libvorbis library which encodes audio using VORBIS codec. You can chose another audio codec. Use 'aac' for AAC encoding or 'opus' for OPUS encoding.
Recommendations and Other considerations
- Remember that you can perform another transformations as changing resolution or the frame rate to the video, when converting the video to a new format. For example use the next command to convert a video to a VP8/VORBIS video changing video resolution to 640x360px. (See more on changing video resolution using FFMPEG)
ffmpeg -i input_file.avi -f matroska -vcodec vp8 -vf scale=640:360 -acodec libvorbis output_file.mkv
- Remember that some encoders have different base configurations, as VP8 will use some low quality configuration, or libx264 will use some basic configurations that you can change. Read more about libx264 configuration options in our article on how to convert a video to MP4 format.
- Remember also that some encoders could be very slow when converting big video files.
Merge two AVI files using FFMPEG
First you need to create a file (example mylist.txt
):
file '/path/here/file1.avi' file '/path/here/file2.avi' file '/path/here/file3.avi'
Then pass that file to ffmpeg
:
ffmpeg -f concat -i mylist.txt -c copy video_draft.avi
You can use this command to make the list:
ls *.avi | while read each; do echo "file '$each'" >> mylist.txt; done
The linked page has more advanced examples for dealing with issue like different codecs/formats.
References:
Crop a video with FFMPEG
Use the crop
filter:
ffmpeg -i in.mp4 -filter:v "crop=out_w:out_h:x:y" out.mp4
Where the options are as follows:
out_w
is the width of the output rectangleout_h
is the height of the output rectanglex
andy
specify the top left corner of the output rectangle
Example: Crop 16:9
file that contains 2.39:1
video with black margins inside:
ffmpeg -i 3.Days.to.Kill.BG.mkv -filter:v "crop=1920:804:0:138" 3.Days.to.Kill.BG_crop.mkv
GitHub protrolium/ffmpeg.md FFMPEG
Converting Audio into Different Formats / Sample Rates
Minimal example: transcode from MP3 to WMA:
ffmpeg ‑i input.mp3 output.wma
You can get the list of supported formats with:
ffmpeg ‑formats
Convert WAV to MP3, mix down to mono (use 1 audio channel), set bit rate to 64 kbps and sample rate to 22050 Hz:
ffmpeg ‑i input.wav ‑ac 1 ‑ab 64000 ‑ar 22050 output.mp3
Convert any MP3 file to WAV 16khz mono 16bit:
ffmpeg ‑i 111.mp3 ‑acodec pcm_s16le ‑ac 1 ‑ar 16000 out.wav
Convert any MP3 file to WAV 20khz mono 16bit for ADDAC WAV Player:
ffmpeg ‑i 111.mp3 ‑acodec pcm_s16le ‑ac 1 ‑ar 22050 out.wav
cd into dir for batch process:
for i in *.mp3; do ffmpeg ‑i "$i" ‑acodec pcm_s16le ‑ac 1 ‑ar 22050 "${i%.mp3}-encoded.wav"; done
Picking the 30 seconds fragment at an offset of 1 minute:
In seconds
ffmpeg ‑i input.mp3 ‑ss 60 ‑t 30 output.wav
In HH:MM:SS format
ffmpeg ‑i input.mp3 ‑ss 0:01:00 ‑t 0:00:30 output.wav
Extract Audio
ffmpeg ‑i input-video.avi ‑vn ‑acodec copy output-audio.aac
vn
is no video.
acodec
copy says use the same audio stream that's already in there.
ffmpeg ‑i video.mp4 ‑f mp3 ‑ab 192000 ‑vn music.mp3
The ‑i option in the above command is simple: it is the path to the input file. The second option ‑f mp3 tells ffmpeg that the ouput is in mp3 format. The third option i.e ‑ab 192000 tells ffmpeg that we want the output to be encoded at 192Kbps and ‑vn tells ffmpeg that we dont want video. The last param is the name of the output file.
Practical example:
ffmpeg -i Star.Wars.*.avi -f mp3 -ab 192000 -vn music.mp3
Replace Audio on a Video without re-encoding.
strip audio stream away from video
ffmpeg ‑i INPUT.mp4 ‑codec copy ‑an OUTPUT.mp4
combine the two streams together (new audio with originally exisiting video)
ffmpeg ‑i INPUT.mp4 ‑i AUDIO.wav ‑shortest ‑c:v copy ‑c:a aac ‑b:a 256k OUTPUT.mp4
You say you want to "extract audio from them (mp3 or ogg)". But what if the audio in the mp4 file is not one of those? you'd have to transcode anyway. So why not leave the audio format detection up to ffmpeg?
To convert one file:
ffmpeg ‑i videofile.mp4 ‑vn ‑acodec libvorbis audiofile.ogg
To convert many files:
for vid in *.mp4; do ffmpeg ‑i "$vid" ‑vn ‑acodec libvorbis "${vid%.mp4}.ogg"; done
You can of course select any ffmpeg parameters for audio encoding that you like, to set things like bitrate and so on.
Use -acodec libmp3lame
and change the extension from .ogg
to .mp3
for mp3 encoding.
If what you want is to really extract the audio, you can simply "copy" the audio track to a file using ‑acodec copy. Of course, the main difference is that transcoding is slow and cpu-intensive, while copying is really quick as you're just moving bytes from one file to another. Here's how to copy just the audio track (assuming it's in mp3 format):
ffmpeg ‑i videofile.mp4 ‑vn ‑acodec copy audiofile.mp3
Note that in this case, the audiofile format has to be consistent with what the container has (i.e. if the audio is AAC format, you have to say audiofile.aac). You can use the ffprobe command to see which formats you have, this may provide some information:
for file in *; do ffprobe $file 2>&1 |grep Audio; done
A possible way to automatically parse the audio codec and name the audio file accordingly would be:
for file in *mp4 *avi; do ffmpeg ‑i "$file" ‑vn ‑acodec copy "$file"; ffprobe "$file" 2>&1 | sed ‑rn 's/.Audio: (…), ./\1/p'; done
Note that this command uses sed to parse output from ffprobe for each file, it assumes a 3‑letter audio codec name (e.g. mp3, ogg, aac) and will break with anything different.
Encoding multiple files
You can use a Bash "for loop" to encode all files in a directory:
mkdir newfiles
for f in *.m4a; do ffmpeg ‑i "$f" ‑codec:v copy ‑codec:a libmp3lame ‑q:a 2 newfiles/"${f%.m4a}.mp3"; done
ffmpeg ‑i input.m4a ‑acodec libmp3lame ‑ab 128k output.mp3
m4a to mp3 conversion with ffmpeg and lame
A batch file version of the same command would be:
for f in *.m4a; do ffmpeg ‑i "$f" ‑acodec libmp3lame ‑ab 256k "${f%.m4a}.mp3"; done
Extract Single Image from a Video at Specified Frame
vf [ss][filename][outputFileName]
where vf
is a custom bash script as follows:
ffmpeg ‑ss $1 ‑i $2 ‑qmin 1 ‑q:v 1 ‑qscale:v 2 ‑frames:v 1 ‑huffman optimal $3.jpg
ss offset = frame number divided by FPS of video = the decimal (in milliseconds) ffmpeg needs i.e. 130.5
Merge Multiple Videos
file names in folder, if they contain spaces, must be properly escaped
ls * | perl ‑ne 'print "file $_"' | ffmpeg ‑f concat ‑i – ‑c copy merged.mp4
Split a Video into Images
ffmpeg ‑i video.flv image%d.jpg
Convert Images into a Video
ffmpeg ‑f image2 ‑i image%d.jpg imagestovideo.mpg
Convert mp4 to webm
ffmpeg ‑i example.mp4 ‑f webm ‑c:v libvpx ‑b:v 1M ‑acodec libvorbis example.webm ‑hide_banner
Simple FLAC convert
ffmpeg ‑i audio.xxx ‑c:a flac audio.flac
Mix Stereo to Mono
You can modify a video file directly without having to re-encode the video stream. However the audio stream will have to be re-encoded.
Left channel to mono: ffmpeg ‑i video.mp4 ‑map_channel 0.1.0 ‑c:v copy mono.mp4
Left channel to stereo:
ffmpeg ‑i video.mp4 ‑map_channel 0.1.0 ‑map_channel 0.1.0 ‑c:v copy stereo.mp4
If you want to use the right channel, write 0.1.1
instead of 0.1.0.
Trim End of file (mp3)
Here's a command line that will slice to 30 seconds without transcoding:
ffmpeg ‑t 30 ‑i inputfile.mp3 ‑acodec copy outputfile.mp3
To Encode or Re-encode ?
Do you need to cut video with re-encoding or without re-encoding mode? You can try to following below command.
Synopsis: ffmpeg ‑i [input_file] ‑ss [start_seconds] ‑t [duration_seconds] [output_file]
use ffmpeg cut mp4 video without re-encoding
Example:
ffmpeg ‑i source.mp4 ‑ss 00:00:05 ‑t 00:00:10 ‑c copy cut_video.mp4
use ffmpeg cut mp4 video with re-encoding
Example:
ffmpeg ‑i source.mp4 ‑ss 00:00:05 ‑t 00:00:10 ‑async 1 ‑strict ‑2 cut_video.mp4
If you want to cut off section from the beginning, simply drop ‑t 00:00:10 from the command
reduce filesize
Example:
ffmpeg ‑i input.avi ‑vcodec libx264 ‑crf 24 output.avi
It reduced a 100mb video to 9mb.. Very little change in video quality.
Example:
ffmpeg ‑i video.mov ‑vf eq=saturation=0 ‑s 640x480 ‑c:v libx264 ‑crf 24 output.mp4
make a grayscale version and scale to 640x480
Convert MKV to MP4
ffmpeg ‑i file.mkv
check for streams that you want (video/audio). be sure to convert/specify DTS 6 channel audio stream
ffmpeg ‑i input.mkv ‑strict experimental ‑map 0:0 ‑map 0:1 ‑c:v copy ‑c:a:1 libmp3lame ‑b:a 192k ‑ac 6 output.mp4
Add Watermark overlay (png) to the center of a video
ffmpeg ‑i source.mov ‑i watermark.png ‑filter_complex "overlay=x=(main_w-overlay_w)/2:y=(main_h-overlay_h)/2" output.mp4
More commands
- http://www.catswhocode.com/blog/19–ffmpeg–commands–for–all–needs
Cutting the videos based on start and end time using FFMPEG
Re-encoding is the default if you do not specify copy
. For example:
ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4
ffmpeg -i The.Matrix.1999.BG.EN.sub.mkv -ss 00:10:00 -t 00:00:37 -async 1 cut.mkv
When re-encoding you may also wish to include additional quality-related options or a particular AAC encoder. For details, see ffmpeg's x264 Encoding Guide for video and AAC Encoding Guide for audio.
Also, the -t
option specifies a duration, not an end time. The above command will encode 8s of video starting at 3s. To start at 3s and end at 8s use -t 5
. If you are using a current version of ffmpeg you can also replace -t
with -to
in the above command to end at the specified time.
Try using this. It is the fastest and best ffmpeg-way I have figure it out:
ffmpeg -ss 00:01:00 -i input.mp4 -to 00:02:00 -c copy output.mp4
This command trims your video in seconds!
ffmpeg -ss 00:10:00 -i The.Matrix.1999.BG.EN.sub.mkv -to 00:00:37 -c copy cut.mkv
Explanations (more details):
-i
: This specifies the input file. In that case, it is (input.mp4).
-ss
: Used with ‑i, this seeks in the input file (input.mp4) to position.
00:01:00
: This is the time your trimmed video will start with.
-to
: This specifies duration from start (00:01:40) to end (00:02:12).
00:02:00
: This is the time your trimmed video will end with.
-c copy
: This is an option to trim via stream copy. (NB: Very fast)
- The timing format is:
hh:mm:ss
Please note that the current highly upvoted answer is outdated and the trim would be extremely slow. For more information, look at this official ffmpeg article.
FFmpeg and H.265 Encoding Guide
ffmpeg has support for H.265 / HEVC encoding using the x265 encoder.
libx265
can offer around 25–50% bitrate savings compared to H.264 video encoded with libx264
, while retaining the same visual quality. These gains will be most pronounced at resolutions of 1080p and higher.
Getting ffmpeg with libx265 support
ffmpeg needs to be built with the –enable-gpl
–enable-libx265
configuration flag and requires x265
to be installed on your system. The Compilation Guides show you how to do that.
You can also download a static build, all of which bundle libx265.
Encoding
Similar to x264, the x265 encoder has multiple rate control algorithms, including:
- 1‑pass target bitrate (by setting
-b:v
) - 2‑pass target bitrate
- Constant Rate Factor (CRF)
In this guide we are going to focus on CRF and Two-Pass encoding, as 1‑pass target bitrate encoding is not recommended.
Constant Rate Factor (CRF)
Use this mode if you want to retain good visual quality and don't care about the exact bitrate or filesize of the encoded file. The mode works exactly the same as in x264, so please read the H.264 guide for more info.
As with x264, you need to make two choices:
- Choose a CRF. The default is 28, and it should visually correspond to libx264 video at CRF 23, but result in about half the file size. Other than that, CRF works just like in x264.
- Choose a preset. The default is
medium
. The preset determines how fast the encoding process will be at the expense of detail. Put differently, if you chooseultrafast
, the encoding process is going to run fast, and the file size will be smaller when compared tomedium
. The visual quality will not be as good. Slower presets use more memory. Valid presets areultrafast
,superfast
,veryfast
,faster
,fast
,medium
,slow
,slower
,veryslow
andplacebo
.
- Choose a tune. By default, this is disabled, and it is generally not required to set a tune option. x265 supports the following
-tune
options:psnr
,ssim
,grain
,zerolatency
,fastdecode
. They are rexplained in the H.264 guide.
For example:
ffmpeg -i input -c:v libx265 -crf 28 -c:a aac -b:a 128k output.mp4
This example uses AAC audio at 128 kBit/s. This uses the ffmpeg-internal encoder, but under AAC you will find info about more options.
Two-Pass Encoding
This method is generally used if you are targeting a specific output file size and output quality from frame to frame is of less importance. This is best explained with an example. Your video is 10 minutes (600 seconds) long and an output of 200 MiB is desired. Since bitrate = file size / duration
:
(200 MiB * 8192 [converts MiB to kBit]) / 600 seconds = ~2730 kBit/s total bitrate 2730 - 128 kBit/s (desired audio bitrate) = 2602 kBit/s video bitrate
You can also forgo the bitrate calculation if you already know what final (average) bitrate you need.
Two-Pass Example
For two-pass, you need to run ffmpeg
twice, with almost the same settings, except for:
- In pass 1 and 2, use the
-x265-params pass=1
and-x265-params pass=2
options, respectively. - In pass 1, output to a null file descriptor, not an actual file. (This will generate a logfile that ffmpeg needs for the second pass.)
- In pass 1, you need to specify an output format (with
-f
) that matches the output format you will use in pass 2. - In pass 1, you can leave audio out by specifying
-an
.
For libx265, the -pass
option (that you would use for libx264) is not applicable.
ffmpeg -y -i input -c:v libx265 -b:v 2600k -x265-params pass=1 -an -f mp4 /dev/null && \ ffmpeg -i input -c:v libx265 -b:v 2600k -x265-params pass=2 -c:a aac -b:a 128k output.mp4
Note: Windows users should use NUL
instead of /dev/null
and ^
instead of \
.
As with CRF, choose the slowest -preset
you can tolerate, and optionally apply a -tune
setting. Note that when using faster presets with the same target bitrate, the resulting quality will be lower and vice-versa.
Passing Options
Generally, options are passed to x265 with the -x265-params
argument. For fine-tuning the encoding process, you can therefore pass any option that is listed in the x265 documentation. Keep in mind that fine-tuning any of the options is generally not necessary, unless you absolutely know what you need to change.
Setting Profiles
Profiles can be set via the -profile:v
option, similar to libx264.
Resize and decode Video
# h265 720p
ffmpeg -i Exodus.Gods.and.Kings.2014.BG.mkv -vf scale=-1:720 -c:v libx265 -crf 0 -preset veryslow -c:a copy Exodus.Gods.and.Kings.2014.BG.720p.mkv
# h264 720p
ffmpeg -i MyMovie.mkv -vf scale=-1:720 -c:v libx264 -crf 0 -preset veryslow -c:a copy MyMovie_720p.mkv
# h264 720p visually lossless
ffmpeg -i MyMovie.mkv -vf scale=-1:720 -c:v libx264 -crf 18 -preset veryslow -c:a copy MyMovie_720p.mkv
Resize and decode Video and Copying all audio streams (Selecting streams with ‑map)
ffmpeg -i in.mkv -vf scale=-1:720 -map 0 out.720p.mkv
Fix 'Past duration X.XXX too large'
ffmpeg -i infile.avi outfile.mkv -async 1 -vsync 1
ffmpeg -i file.{avi,mkv} -async 1 -vsync 1
References:
- What does 'Past duration X.XXX too large' mean?
- How to Fix ‘Past Duration Too Large’ Error in FFmpeg?
Understanding FFMPEG Error Extracting Subtitles
ffmpeg -i in.mkv -vf scale=-1:720 -c:s copy -map 0 out.720p.mkv -async 1 -vsync 1
How do I split an audio file into multiple?
ffmpeg -i somefile.mp3 -f segment -segment_time 3 -c copy out%03d.mp3
- Where
-segment_time
is the amount of time you want per each file (in seconds
).