Does converting .mp4 to .mkv change data fidelity? - ffmpeg

I am wondering when I convert a .mp4 to .mkv using the following command if the quality changes.
ffmpeg -i in.mp4 out.mkv
The input file, in.mp4 has a file size of 297 megabytes, while the out.mkv file has a size of 249 megabytes, ~15% lower. Upon manual inspection, the resolution, video, and audio streams are the same before/after (as I would have expected given my (limited) knowledge of ffmpeg).
Is the 15% size decrease by simply converting to mkv actually not affect the quality of the video? If so this seems like a very reasonable way of freeing up some space on my computer.

The quality gets worse
This is due to generation loss because you are re-encoding the video and audio to lossy formats. But you may not notice the difference.
The output file size will vary depending on the input format, if it was encoded well or badly, your output format, and the settings you use.
MP4 to MKV without quality loss
You can just re-mux and avoid re-encoding by using stream copy mode:
ffmpeg -i input.mp4 -c copy output.mkv
You can think of it like a copy and paste. The video and audio is untouched and just put into a new container.

Related

ffmpeg output file smaller than input file

I am using ffmpeg to rotate videos 90 or 180 degrees in a Python script. It works great. But, I am curious as to why the output file would be a smaller amount of bytes than the input file.
Here are the commands I use:
180 degrees:
ffmpeg -i ./input.mp4 -preset veryslow -vf "transpose=2,transpose=2,format=yuv420p" -metadata:s:v rotate=0 -codec:v libx264 -codec:a copy ./output.mp4
90 degrees:
ffmpeg -i ./input.mp4 -vf "transpose=2" ./output.mp4
For example, a GoPro Hero 3 MP4 file was originally 2.0 GB. The resulting output file was 480.9 MB. Another GoPro file was 2.0 and its resulting file was 671.5 MB. Is this maybe because the GoPro files were 2.0 but contains empty space, sort of like how some NTFS filesystems make a minimal 4k file, even when there is less bytes in it?
If this isn't the GoPro Hero 3, how do I rotate the files 90 or 180 degrees but ensure the output file size is the same? Or, is data loss expected? Does the data loss have to do with the format?
Note that the quality of the video doesn't appear to be damaged, which is good. So, I am interested in learning more about why this is happening, then I can read the section of ffmpeg documentation that is relevant to this.
Thank you!
Bitrate is ignored from the start
ffmpeg fully decodes the input into uncompressed raw video and audio (except when stream copying – more about that below). The input format or bitrate does not matter: it does this for all formats. The encoder then works from these raw, decoded frames. See diagram.
H.264 vs H.264
Your input and output are both H.264. A format, such as H.264, is created by an encoder. Anyone can make an encoder. However, not all encoders are equal. Given the same input, the output from one H.264 encoder may have the same quality as an output from another H.264 encoder, but the bitrate may be several times smaller.
The GoPro H.264 encoder was made to work on a platform with limited hardware. That means bitrate (file size) is sacrificed for speed and quality. x264 is the ultimate H.264 encoder: nothing can beat its quality-to-bitrate ratio.
Rotate without re-encoding
You can stream copy (re-mux) and rotate at the same time. The rotation is handled by the metadata/sidedata:
ffmpeg -i input.mp4 -metadata:s:v rotate=90 -c copy output.mp4
Downside is your player/device may ignore the rotation, so you may have to physically rotate with filters which requires re-encoding, and therefore stream copy can't be used.
I had the same rotation issue once...
I fixed it by "resetting" the rotation instead...
ffmpeg ...... -metadata:s:v rotate="0" ......

FFMPEG change fps of audio and subtitles and merge 2 files

I have 30 mkv files which have multiple audio streams and multiple subtitles.
For each file I am trying to: extract the dutch audio and subtitles from that file (25fps)
And merge it with another mkv file (23.976216fps)
With this command it seems like I extract the dutch audio and subtitles into a mkv:
ffmpeg -y -r 23.976216 -i "S01E01 - Example.mkv" -c copy -map 0:m:language:dut S01E01.mkv
But it does not adjust the fps from 25 to 23.976216.
I think I am going to use mkvmerge to merge the two mkv's, but they need to be the same framerate
Anyone knows how I could make this work? Thanks! :)
The frame rate of the video has nothing to do with the frame rate of audio. They are totally independent. In fact there is really no such thing as audio frame rate (well, there is, but that’s a byproduct of the codecs). If you are changing the video frame rate by dropping frames, you are not changing the videos duration, hence you should not change the audios duration. If you are slowing down the video, you must decode the audio, slow it down (likely with pitch correction) and re-encode it.
Something like this would change the audio pitch from standard PAL to NTSC framerate (example valid if your audio track is the 2nd in list, -check with ffmpeg -i video.mkv and see-)
ffmpeg -i video.mkv -vn -map 0:1 -filter:a atempo=0.95904 -y slowed-down-audio-to-23.976-fps.ac3
(23976/25000 = 0.95904 so this is the converted frame rate needed for NTSC films)
Conversely, you can figure out how to speed up NTSC standard frame rate audio to the PAL system (1.0427094).
This trick works, for example, should you want to add a better quality audio track obtained from a different source.

How can I concatenate two very different mp3 files(diff bitrate, channels, samplerate, bitdeph)?

As input I get one mp3 file(input.mp3), then I need to split it into two separate parts(done that) and insert between those parts another mp3(second.mp3).
The problem:
I tried using every single command for concatenating files, converting them to .ts etc etc.
But I always get only the sound of the first mp3 file and the sound of the second is lost. I guess I have to transform my mp3 file into the exact same format as the input.mp3(bitrates, sample rates number of channels) file before I can concatenate it to it.
I could concatenate the two parts of the input.mp3, but no matter what I do I cannot concatenate with second.mp3.
I am using php with exec and ffmpeg.exe file. Is it possible to code it so no matter the input, I can transform second.mp3 into suitable for concatenating mp3?
How can I concatenate two very different mp3 files(diff bitrate, channels, samplerate, bitdeph)?
Let's start with each component...
bitrate
This one doesn't matter. MP3 streams can (and do!) change bitrate mid-stream. As long as you join on a frame header, you're fine.
bitdepth
The concept of sample bit depth doesn't exist within MP3. You can capture at 24-bit, encode to MP3, and the decoder will decode to 16-bit. (Or, with some command line switches, vice versa!) It's not a problem because bit depth doesn't apply.
sample rates
This is usually a problem. Most players don't assume they're going to change output sample rate mid-stream. Most players don't attempt to resample to stick to the rate they were already outputting at. I'm not surprised that you'd have some trouble with a changing sample rate.
channels
This is similar to the sample rate problem in that it requires changing the configuration of the output device. Even if the player supports it, it isn't going to be seamless. (Unless you were going from stereo to mono, where the mono could be easily upmixed to stereo.)
As input I get one mp3 file(input.mp3), then I need to split it into two separate parts(done that) and insert between those parts another mp3(second.mp3).
This actually presents another problem you haven't asked about... timing. MP3 works in relatively large frames (typically 576 samples), which becomes the resolution at which you can splice. Not good. Also, the starts of tracks often have a frame or two of initialization.
A third issue is the bit reservoir. This is where content from one frame is stored in a different frame that might have extra space.
At the end of the day, you're going to have to decode everything to regular PCM samples, do your splicing, and re-encode to MP3. You'll also have to re-sample everything to a common clock rate, and mix to a particular channel count. Fortunately, once decoded to PCM, this is all trivial and standard. Once your input streams are compatible, you an arbitrarily splice on a PCM frame which is the most granular possible.
If you want to concatenate or merge different bit rate and Mono and Stereo mp3 files into one mp3 file use ffmpeg libmp3lame library.
Command :
ffmpeg -i "concat:'url1.mp3'|'mono_url2.mp3'|'stereo_url3.mp3'" -c:a libmp3lame output_file.mp3
Use the atrim, asetpts, and concat filters:
ffmpeg -i input.mp3 -i second.mp3 -filter_complex "[0:a]atrim=end=10,asetpts=N/SR/TB[begin];[0:a]atrim=start=10,asetpts=N/SR/TB[end];[begin][1:a][end]concat=n=3:v=0:a=1[a]" -map "[a]" output
Note: All corresponding streams must have the same parameters in all segments; the filtering system will automatically select a common sample format, sample rate, and channel layout for audio streams. These common parameters will vary depending on the input parameters, so add the aformat filter (or equivalent) if you want consistent results:
ffmpeg -i input.mp3 -i second.mp3 -filter_complex "[0:a]atrim=end=10,aformat=sample_rates=44100:channel_layouts=stereo,asetpts=N/SR/TB[begin];[1:a]aformat=sample_rates=44100:channel_layouts=stereo[middle];[0:a]atrim=start=10,aformat=sample_rates=44100:channel_layouts=stereo,asetpts=N/SR/TB[end];[begin][middle][end]concat=n=3:v=0:a=1[a]" -map "[a]" output

What codec/format to use for fastest possible decoding?

I'm using an ffmpeg script (in Windows) that extracts all the keyframes from a video and pastes them into a folder. I've made sure that my drive speed, CPU, and RAM are not causing a bottleneck.
The quality of the video is actually not important at all in this case. I need to encode the video that the script extracts frames from so that it has the fastest possible decoding speed. File size and quality are not important, only read speed. The video does not have audio. What would work best for me?
If it matters, here's the script I'm working with:
ffmpeg -i input.mp4 -vf "select=eq(pict_type\,I)" -vsync 1 %%3d.bmp
Sorry if sound like I don't know what I'm talking about, this is not a topic I am super familiar with. I appreciate your help!
The below will be much faster for a codec like H.264
ffmpeg -discard nokey -i input.mp4 -vsync 0 %%3d.bmp
Your present approach decodes all frames and then the select filter gets to do gating, but the above command discards everything but keyframes at the demuxer level. It only works with MP4/MOV like containers.

ffmpeg split into frames

Hey, I want to split a video which is one second long (25fps)into 25 seperate video files. I know I can split it up into jpegs but I need to retain the audio. So when I recompile audio is still there.
This is what I tried to grab the first frame only (with audio):
ffmpeg -i 1.mov -vcodec mjpeg -qscale 1 -an -ss 00:00:00:00 -t 00:00:00:1 frame1.mov
But it doesn't seem to work. Am I wrong in assuming ffmpeg supports time stamps in this format? hh:mm:ss:f?
Thanks
You are wrong in assuming ffmpeg supports timestamps in that format, but that's not the only problem
ffmpeg does not support the time format you're using. Options are either the time in seconds, or hh:mm:ss[.xxx] (two colons and a dot instead of three colons).
Your example code specifically strips the audio. That's what -an does.
Splitting by time when you actually want frames is not a great idea. Though since the audio frames are unlikely to match 1:1 with the video frames, it might be the best option.
Most importantly, most video and audio codecs are lossy and thus do not take well to being broken up into lots of pieces and then put back together. To do this without horribly mangling the quality, you need to first convert both video and audio into raw formats, manipulate those, and then re-transcode to compressed formats once you've done whatever you want to do with the pieces. You'll still lose some quality, but not as much as otherwise.

Resources