Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ffmpeg/avconv: transcode using same codec and params as input

Tags:

ffmpeg

Is there a way to tell ffmpeg and/or avconv to use for the output the same codec as the one the input is encoded with, but do the transcoding?

I'm looking for something like:

ffmpeg -i input.mp4 -vcodec same_as_input output.mp4

Note that I'm not looking for -vcodec copy, as that would copy the stream without transcoding. I want it to do the transcoding but use the same codec the input file is encoded with.

Also, if possible, I'd like to have the same for every possible parameter, that is: use the same bitrate, frame size, etc, take the value for every possible parameter from one given input file, rather than using any other defaults.

The above example may seem stupid because it's oversimplified (the result would be the same as copying), but imagine I add some processing, e.g. a start time and length, or even something more complex such as adding an overlay image, but I want to make sure it's encoded with the same encoder (and possibly the same parameters) as the input file.

like image 325
matteo Avatar asked Dec 23 '15 19:12

matteo


1 Answers

ffmpeg doesn't have a feature to copy the same bitrate, but it will automatically copy the frame rate, width, height, pixel format, aspect ratio, audio channel count, audio sample rate, etc, (encoder dependent).

I don't recommend copying the same bitrate for a variety of reasons that would end up as several paragraphs. In short, let the encoder deal with that automatically.

However, here is a simple bash script. You'll need to adapt it to include audio stream info and whatever other parameters you want.

#!/bin/bash
# Copies the same video codec and bitrate: usually this is not a good idea.
# Usage: ./vidsame input output

echo "Calculating video bitrate. This can take a while for long videos."

# Alternatively you could just use ffprobe to get video stream bitrate,
# but not all inputs will show stream bitrate info, so ffmpeg is used instead.

size="$(ffmpeg -i "$1" -f null -c copy -map 0:v:0 - |& awk -F'[:|kB]' '/video:/ {print $2}')"
codec="$(ffprobe -loglevel error -select_streams v:0 -show_entries stream=codec_name -of default=nk=1:nw=1 "$1")"
duration="$(ffprobe -loglevel error -select_streams v:0 -show_entries format=duration -of default=nk=1:nw=1 "$1")"
bitrate="$(bc -l <<< "$size"/"$duration"*8.192)"

ffmpeg -i "$1" -c:v "$codec" -b:v "$bitrate"k "$2"

echo
echo "Duration: $duration seconds"
echo "Video stream size: $size KiB"
echo "Video bitrate: $bitrate kb/s"
echo "Video codec: $codec"

If you want additional parameters use ffprobe to view a list of what's available:

ffprobe -loglevel error -show_streams input.mkv

Then use -select_entries as shown in the script.

Note that codec_name won't always match up with an encoder name, but usually it will Just Work. See ffmpeg -encoders.

like image 95
llogan Avatar answered Oct 04 '22 13:10

llogan