1

What I am trying to do is to compare the quality of transcoded x265 video with the original high bit rate x264. For that, I am taking a frame as png and zooming to find the pixel differences in https://gitlab.gnome.org/YaLTeR/identity .

Original Video

$ ffprobe Original.mkv 2>&1 | egrep 'Duration|Stream'
  Duration: 00:45:29.08, start: 0.000000, bitrate: 7156 kb/s
  Stream #0:0: Video: h264 (High), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn (default)
  Stream #0:1(eng): Audio: eac3, 48000 Hz, 5.1(side), fltp, 640 kb/s (default)
  Stream #0:2(eng): Subtitle: subrip

I am converting a part of the video to x265

$ ffmpeg -ss 00:40:00 -i Original.mkv -t 00:10:00 -c:v libx265 -crf 20 -c:a copy Original-x265.mkv

Now I am trying to fetch the same frame from both videos

ffmpeg -ss 00:40:09 -i Original.mkv -frames:v 1 -q 1 original.png
ffmpeg -ss 00:00:09 -i Original-x265.mkv -frames:v 1 -q 1 original-x265.png

But both images are different. How can I get the same image from both videos to compare quality?

2 Answers 2

2

Using -c:a copy prevents accurate cutting.
Replace -c:a copy with -c:a aac, or ignore the audio stream by adding -an argument.

-c:a copy forces FFmpeg to copy the audio stream without re-encoding.
When using "stream copy", FFmpeg can't split an audio packet in the middle, and it can't start the input at an exact time.

Each audio packet is 1024 samples per audio channel.
At 48000 samples per second, audio packet duration is 1024/48000 = 21.3msec
We are having seeking inaccuracy of about 21msec.
The duration of a video frame is about 1/25 = 40msec.
When using -c:a copy the inaccuracy of the video is at least half of the period of a frame (inaccuracy of about 1 frame).
For a reason I don't know the inaccuracy is larger than 1 frame.


Reproducing the issue using a synthetic video with a frame counter:

Building the synthetic video and audio (used as input for testing):

ffmpeg -y -r 23.976 -f lavfi -i testsrc=size=192x108:rate=1:duration=65432 -f lavfi -i sine=frequency=500 -vf "setpts=N/23.976/TB" -c:v libx264 -g 117 -acodec aac -ar 48000 -pix_fmt yuv420p -t 2729 Original.mkv

Extracting the frames with -c:a copy:

ffmpeg -y -ss 00:40:00 -i Original.mkv -t 00:10:00 -c:v libx265 -crf 20 -c:a copy Original-x265.mkv

ffmpeg -y -ss 00:40:09 -i Original.mkv -frames:v 1 -update 1 original.png
ffmpeg -y -ss 00:00:09 -i Original-x265.mkv -frames:v 1 -update 1 original-x265.png

Output:

original.png:
enter image description here

original-x265.png:
enter image description here

That there is a difference of 4 frames!


Extracting the frames with -c:a aac (re-encoding the audio):

ffmpeg -y -ss 00:40:00 -i Original.mkv -t 00:10:00 -c:v libx265 -crf 20 -c:a aac Original-x265.mkv

ffmpeg -y -ss 00:40:09 -i Original.mkv -frames:v 1 -update 1 original.png
ffmpeg -y -ss 00:00:09 -i Original-x265.mkv -frames:v 1 -update 1 original-x265.png

Output:

original.png:
enter image description here

original-x265.png:
enter image description here

The frame is the same frame!


Note, that I didn't test the effect of the subtitles stream.
We may disable the subtitles stream by adding -sn argument.

1
  • Nailed it. Thanks man explaining it :+1:
    – Unni
    Commented Jun 26, 2023 at 18:50
0

Try this:

ffmpeg -hide_banner -ss 00:00:00 -i input.mkv -t 1 -vf "select='eq(pict_type,I)'" -vsync vfr out-%02d.png

This will extract only key frames from 00:00:00 to 00:00:01. Change the timestamps to the ones you need.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .