6

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.

matteo
  • 2,934
  • 7
  • 44
  • 59
  • 2
    ffprobe returns information about a video file, including codec. You could have a program or script parse its output to detect the original codec and conditionally use the same one for transcoding. – cantelope Dec 23 '15 at 19:14
  • 2
    See ticket [#5081: A wish for ffmpeg to be able to reference input properties](https://trac.ffmpeg.org/ticket/5081). How do you know that the bitrate and other options are not suboptimal? How do you know whoever made the files knew what they were doing or were using a sane encoder implementation? – llogan Dec 23 '15 at 19:34
  • @LordNeckbeard you may want to reproduce input properties for its own sake for a number of reasons regardless of whether they are optimal or even good. A use case: I have a video file that triggers an issue in some software, I want to provide the example file but it's either too long or contains private stuff so I can't share it as-is, hence I need to produce a modified version with the same properties (because I don't know which is the relevant one that produces the issue) – matteo Dec 24 '15 at 11:00
  • and another use case: you want to do some simple modifications on a video file (e.g. trimming) and you know its properties are "good enough" (because the quality looks good and the file is not huge), so you know that by maintaining the same properties it will be just fine, even if not optimal, and you don't have to figure out the best parameters for everything. – matteo Dec 24 '15 at 11:03
  • @cantelope if you can share an example script (can it be a one-liner?) for transcoding a single file using, for example, the same codec and bitrate from the input, I'll accept that as answer :) – matteo Dec 24 '15 at 11:20

2 Answers2

5

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.

llogan
  • 121,796
  • 28
  • 232
  • 243
1

This seems to work

file="input.mp4"
ffmpeg -re -y -i "$file"  -c:v `ffprobe $file |& grep 'Video:' | awk -v N=4 '{print $N}'`  -b:v `ffprobe $file |& grep 'Video:' | awk -v N=15 '{print $N}'`k -f flv output.mp4

The key here is this part, which grabs the video codec from the input file. You'll notice this appears twice in the statement, the second time it grabs the bitrate.

`ffprobe $file |& grep 'Video:' | awk -v N=4 '{print $N}'`
cantelope
  • 1,147
  • 7
  • 9
  • 1
    You're on the right track, but this will break if the input contains multiple video streams. Your `ffprobe` example for bitrate returns `DAR` for me because the output order may vary. You can eliminate `grep` and `awk`: `ffprobe -loglevel error -select_streams v:0 -show_entries stream=codec_name,bitrate -of default=nk=1:nw=1 input.mp4` (see [FFprobe Tips](http://trac.ffmpeg.org/wiki/FFprobeTips)). The stream `bit_rate` won't always be available (try a mkv input), so that will have to be acquired by dividing the *video stream size/duration*. What's the `-f flv` for when the output is mp4? – llogan Dec 24 '15 at 19:25
  • 1
    @lordneckbeard The word retrieved corresponds to the value of N. On my system the codec is word 4 and the bitrate is word 15, but you're right, that could easily be different on other systems. Op will need to test it to verify that it works with his configuration. The script fails on my system without the -f flv for some reason. – cantelope Dec 24 '15 at 19:41