ffmpeg 使用 H265 vcopy 寻找关键帧不准确
ffmpeg inaccurate seeking keyframes with H265 vcopy
我有一个 H265 4K MP4 29.97fps 视频,其 GOP 大小恰好是 30 帧。
当我尝试从头开始使用 :
ffmpeg -ss 1 -i INPUT.MP4 -vcodec copy OUTPUT_1SEC.MP4
ffmpeg -ss 2 -i INPUT.MP4 -vcodec copy OUTPUT_2SEC.MP4
ffmpeg -ss 3 -i INPUT.MP4 -vcodec copy OUTPUT_3SEC.MP4
ffmpeg -ss 4 -i INPUT.MP4 -vcodec copy OUTPUT_4SEC.MP4
ffmpeg -ss 5 -i INPUT.MP4 -vcodec copy OUTPUT_5SEC.MP4
ffmpeg -ss 6 -i INPUT.MP4 -vcodec copy OUTPUT_6SEC.MP4
ffmpeg -ss 7 -i INPUT.MP4 -vcodec copy OUTPUT_7SEC.MP4
ffmpeg -ss 8 -i INPUT.MP4 -vcodec copy OUTPUT_8SEC.MP4
ffmpeg -ss 9 -i INPUT.MP4 -vcodec copy OUTPUT_9SEC.MP4
输出视频从 0 (-ss 1~4)、4 (-ss 5~8) 或 8 秒 (-ss 9) 开始,如下所示:
所以 ffmpeg 似乎以某种方式检测到 4 秒而不是 1 秒的 GOP。正常吗?
另外,如何在输出视频中刻录正确的时间码?
例如,我尝试了很多组合如:
ffmpeg -ss 5 -i INPUT.MP4 -vcodec copy -timecode 00:00:05:00 OUTPUT_5SEC.MP4
ffmpeg -ss 5 -i INPUT.MP4 -vcodec copy -copyts OUTPUT_5SEC.MP4
ffmpeg -start_at_zero -ss 5 -i INPUT.MP4 -vcodec copy -copyts OUTPUT_5SEC.MP4
但它要么给我输入的确切时间码(第一行),要么从零开始(最后两行)
最初,我正在考虑在精确的秒(或几帧之后)寻找,所以我知道我会得到一个关键帧,这样我就可以猜测输出将开始的确切时间码,但似乎 ffmpeg -ss 是不完全基于关键帧?也许我在这里遗漏了什么?感谢您的帮助。
其他信息
我想编写剪辑过程的脚本,这就是为什么我想知道这 4 秒 "keyframe interval" 的来源。
这是我输入的 ffprobe 输出:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'INPUT.MP4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2mp41
encoder : Lavf57.72.101
comment : DE=None, Mode=M, DSW=0001
location-{ : +XX.4914-0XX.5164+XX.000000/
location : +XX.4914-0XX.5164+XX.000000/
Duration: 00:01:45.31, start: 0.000000, bitrate: 100065 kb/s
Stream #0:0(eng): Video: hevc (Main) (hev1 / 0x31766568), yuv420p(tv, bt709), 4096x2160 [SAR 1:1 DAR 256:135], 100062 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 29.97 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(eng): Subtitle: mov_text (tx3g / 0x67337874), 2 kb/s (default)
Metadata:
handler_name : SubtitleHandler
这是我用来检查 gop-size 的命令('I' 在 1,31,61,... 和 'P' 之间输入):
ffprobe -i INPUT.MP4 -select_streams v -show_frames -show_entries frame=pict_type -of csv > OUTPUT.CSV
ffmpeg 版本 N-86330-gbd1179e 和 ffmpeg 版本 N-86330-gbd1179e
虽然每秒有一个关键帧,但是在MOOV框中,只有三帧被设置为同步样本
/moov/trak/mdia/minf/stbl/stss @ 0x77e8515
Box size: 0x1c version: 0x0 flags: 0x0
entry_count: 0x3
sample_number:
0x1 0x79 0xf1
(分别是第1、121、241帧)
FFmpeg 在搜索时依赖于此信息。
解决方法是先混合为 TS,然后再混合为 MP4。
ffmpeg -i input.mp4 -c copy input.ts
然后
ffmpeg -i input.ts -c copy newinput.mp4
或在一个命令中
ffmpeg -i input.mp4 -c copy -f mpegts - | ffmpeg -f mpegts -i - -c copy newinput.mp4
MPEG-TS 文件没有索引,因此如果您想使用该文件进行提取,请在要剪切的关键帧之前指定一个搜索点。
至于为什么同步table是这样的,不知道。这取决于原始写作应用程序和那里使用的 settings/arguments。
我有一个 H265 4K MP4 29.97fps 视频,其 GOP 大小恰好是 30 帧。 当我尝试从头开始使用 :
ffmpeg -ss 1 -i INPUT.MP4 -vcodec copy OUTPUT_1SEC.MP4
ffmpeg -ss 2 -i INPUT.MP4 -vcodec copy OUTPUT_2SEC.MP4
ffmpeg -ss 3 -i INPUT.MP4 -vcodec copy OUTPUT_3SEC.MP4
ffmpeg -ss 4 -i INPUT.MP4 -vcodec copy OUTPUT_4SEC.MP4
ffmpeg -ss 5 -i INPUT.MP4 -vcodec copy OUTPUT_5SEC.MP4
ffmpeg -ss 6 -i INPUT.MP4 -vcodec copy OUTPUT_6SEC.MP4
ffmpeg -ss 7 -i INPUT.MP4 -vcodec copy OUTPUT_7SEC.MP4
ffmpeg -ss 8 -i INPUT.MP4 -vcodec copy OUTPUT_8SEC.MP4
ffmpeg -ss 9 -i INPUT.MP4 -vcodec copy OUTPUT_9SEC.MP4
输出视频从 0 (-ss 1~4)、4 (-ss 5~8) 或 8 秒 (-ss 9) 开始,如下所示:
所以 ffmpeg 似乎以某种方式检测到 4 秒而不是 1 秒的 GOP。正常吗?
另外,如何在输出视频中刻录正确的时间码? 例如,我尝试了很多组合如:
ffmpeg -ss 5 -i INPUT.MP4 -vcodec copy -timecode 00:00:05:00 OUTPUT_5SEC.MP4
ffmpeg -ss 5 -i INPUT.MP4 -vcodec copy -copyts OUTPUT_5SEC.MP4
ffmpeg -start_at_zero -ss 5 -i INPUT.MP4 -vcodec copy -copyts OUTPUT_5SEC.MP4
但它要么给我输入的确切时间码(第一行),要么从零开始(最后两行)
最初,我正在考虑在精确的秒(或几帧之后)寻找,所以我知道我会得到一个关键帧,这样我就可以猜测输出将开始的确切时间码,但似乎 ffmpeg -ss 是不完全基于关键帧?也许我在这里遗漏了什么?感谢您的帮助。
其他信息
我想编写剪辑过程的脚本,这就是为什么我想知道这 4 秒 "keyframe interval" 的来源。
这是我输入的 ffprobe 输出:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'INPUT.MP4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2mp41
encoder : Lavf57.72.101
comment : DE=None, Mode=M, DSW=0001
location-{ : +XX.4914-0XX.5164+XX.000000/
location : +XX.4914-0XX.5164+XX.000000/
Duration: 00:01:45.31, start: 0.000000, bitrate: 100065 kb/s
Stream #0:0(eng): Video: hevc (Main) (hev1 / 0x31766568), yuv420p(tv, bt709), 4096x2160 [SAR 1:1 DAR 256:135], 100062 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 29.97 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(eng): Subtitle: mov_text (tx3g / 0x67337874), 2 kb/s (default)
Metadata:
handler_name : SubtitleHandler
这是我用来检查 gop-size 的命令('I' 在 1,31,61,... 和 'P' 之间输入):
ffprobe -i INPUT.MP4 -select_streams v -show_frames -show_entries frame=pict_type -of csv > OUTPUT.CSV
ffmpeg 版本 N-86330-gbd1179e 和 ffmpeg 版本 N-86330-gbd1179e
虽然每秒有一个关键帧,但是在MOOV框中,只有三帧被设置为同步样本
/moov/trak/mdia/minf/stbl/stss @ 0x77e8515
Box size: 0x1c version: 0x0 flags: 0x0
entry_count: 0x3
sample_number:
0x1 0x79 0xf1
(分别是第1、121、241帧)
FFmpeg 在搜索时依赖于此信息。
解决方法是先混合为 TS,然后再混合为 MP4。
ffmpeg -i input.mp4 -c copy input.ts
然后
ffmpeg -i input.ts -c copy newinput.mp4
或在一个命令中
ffmpeg -i input.mp4 -c copy -f mpegts - | ffmpeg -f mpegts -i - -c copy newinput.mp4
MPEG-TS 文件没有索引,因此如果您想使用该文件进行提取,请在要剪切的关键帧之前指定一个搜索点。
至于为什么同步table是这样的,不知道。这取决于原始写作应用程序和那里使用的 settings/arguments。