使用 ffmpeg 获取帧计数

有人知道如何使用 ffmpeg 从视频文件中获取总帧数吗?Ffmpeg 的渲染输出显示当前帧,我需要帧计数来计算百分比进度。

179247 次浏览

并非所有格式都存储它们的帧计数或总持续时间——即使存储了,文件也可能不完整——因此默认情况下,ffmpeg 无法准确地检测到其中任何一种格式。

相反,尝试寻找到文件的结尾并读取时间,然后计算当前的时间,而你去。

或者,您可以尝试 AVFormatContext->nb_index_entries或检测到的持续时间,这应该工作在良好的至少未损坏的 AVI/MOV,或者库 FFMS2,这可能是太慢,以至于没有进度条。

试试这样:

ffmpeg -i "path to file" -f null /dev/null

它将帧号写入 stderr,这样您就可以从中检索最后一个帧。

而是根据时间来计算。

这就是我所做的,它对我和其他许多人都很有效。首先,在下面的片段中找到视频的长度:

Seems stream 0 codec frame rate differs from container frame rate: 5994.00
(5994/1) -> 29.97 (30000/1001)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/stu/Movies/District9.mov':
Duration: 00:02:32.20, start: 0.000000, bitrate: 9808 kb/s
Stream #0.0(eng): Video: h264, yuv420p, 1920x1056, 29.97tbr, 2997tbn, 5994tbc
Stream #0.1(eng): Audio: aac, 44100 Hz, 2 channels, s16
Stream #0.2(eng): Data: tmcd / 0x64636D74

您应该能够一致和安全地找到 Duration: hh:mm:ss.nn来确定源视频剪辑的大小。然后,对于每个更新行(CR,没有 LF) ,您可以解析当前时间标记的文本:

frame=   84 fps= 18 q=10.0 size=       5kB time=1.68 bitrate=  26.1kbits/s
frame=   90 fps= 17 q=10.0 size=       6kB time=1.92 bitrate=  23.8kbits/s
frame=   94 fps= 16 q=10.0 size=     232kB time=2.08 bitrate= 913.0kbits/s

只是要注意,不要总是期望从这些状态行获得完美的输出。它们可以包含如下错误消息:

frame=   24 fps= 24 q=-1.0 size=       0kB time=1.42 bitrate=   0.3kbits/s
frame=   41 fps= 26 q=-1.0 size=       0kB time=2.41 bitrate=   0.2kbits/s
[h264 @ 0x1013000]Cannot parallelize deblocking type 1, decoding such frames in
sequential order
frame=   49 fps= 24 q=26.0 size=       4kB time=0.28 bitrate= 118.1kbits/s
frame=   56 fps= 22 q=23.0 size=       4kB time=0.56 bitrate=  62.9kbits/s

一旦你有时间,这是简单的数学: time / duration * 100 = % done

试试这个:

ffmpeg -i "path to file" -f null /dev/null 2>&1 | grep 'frame=' | cut -f 2 -d ' '

我使用 php _ ffmpeg 然后我可以得到一部电影的所有时间和所有帧。如下所示

$input_file='/home/strone/workspace/play/CI/abc.rmvb';
$ffmpegObj = new ffmpeg_movie($input_file);
echo $ffmpegObj->getDuration();
echo $ffmpegObj->getFrameCount();

然后细节就写在纸上了。

Http://ffmpeg-php.sourceforge.net/doc/api/ffmpeg_movie.php

在 Unix 中,这就像一个符咒:

ffmpeg -i 00000.avi -vcodec copy -acodec copy -f null /dev/null 2>&1 \
| grep 'frame=' | cut -f 2 -d ' '

以 Stu 的回答为基础。我是这样找到手机视频帧速率的。我运行了一段时间以下命令。在我失去耐心并点击 ^ C 之前,我让帧数达到大约10,000:

$ ffmpeg -i 2013-07-07\ 12.00.59.mp4 -f null /dev/null 2>&1
...
Press [q] to stop, [?] for help
[null @ 0x7fcc80836000] Encoder did not produce proper pts, making some up.
frame= 7989 fps= 92 q=0.0 Lsize=N/A time=00:04:26.30 bitrate=N/A dup=10 drop=0
video:749kB audio:49828kB subtitle:0 global headers:0kB muxing overhead -100.000042%
Received signal 2: terminating.
$

然后,我从以“ frame =”开头的行中抓取了两条信息,帧计数,7989,时间,00:04:26.30。你首先需要把时间转换成秒,然后把帧数除以秒,得到“帧率”。“帧率”是你的帧速率。

$ bc -l
0*60*60 + 4*60 + 26.3
266.3


7989/(4*60+26.3)
30.00000000000000000000
$

我视频的帧率是30fps。

我能做的唯一准确的事情是这样的:

ffprobe -i my_video.mp4 -show_frames 2>&1|grep -c '^\[FRAME'

为了确保视频能够正常工作:

ffprobe -i my_video.mp4 -show_frames 2>&1 | grep -c media_type=video

探测器

ffprobe -v error -select_streams v:0 -count_packets \
-show_entries stream=nb_read_packets -of csv=p=0 input.mp4

这实际上是计数数据包而不是帧,但是速度要快得多。结果应该是一样的。如果您想通过计数帧来验证,请将 -count_packets改为 -count_frames,将 nb_read_packets改为 nb_read_frames

探针选项意味着什么

  • -v error隐藏了“ info”输出(版本信息等) ,这使得解析变得更加容易(但是如果你寻求帮助就会变得更加困难,因为它隐藏了重要的信息)。

  • -count_frames计算每个流的数据包数量,并在相应的流部分中报告它。

  • 只选择第一个视频流。

  • 只显示 nb_read_frames的条目。

  • -of csv=p=0设置输出格式。在这种情况下,它隐藏了描述,只显示了值。有关其他格式(包括 JSON)的信息,请参见 作家

只计算关键帧

参见 检查关键帧间隔?

MP4编辑列表

在 MP4/M4V/M4A/MOV 中出现编辑列表会影响帧数。

也看到了


媒体

众所周知的 mediainfo工具可以输出帧数:

mediainfo --Output="Video;%FrameCount%" input.avi

MP4Box

用于 MP4/M4V/M4A 文件。

来自 gpac 的 MP4Box可以显示帧数:

MP4Box -info input.mp4

请参阅有关视频流输出中的 Media Info行:

Media Info: Language "Undetermined (und)" - Type "vide:avc1" - 2525 samples

在这个例子中,视频流有2525帧。


垃圾桶

适用于 MP4/M4V/M4A/MOV 文件。

boxdumper是一个简单的工具从 l 粉碎。它将输出大量的信息。在 stsz样本大小框部分参考 sample_count的帧数。在这个例子中,输入有1900个视频帧:

boxdumper input.mp4
...
[stsz: Sample Size Box]
position = 342641
size = 7620
version = 0
flags = 0x000000
sample_size = 0 (variable)
sample_count = 1900
  • 请注意,一个文件可能有多个 stsz原子。

可以使用以下命令使用 ffprobe获取帧号

  1. 第一种方法

ffprobe.exe -i video_name -print_format json -loglevel fatal -show_streams -count_frames -select_streams v

它告诉以 json格式打印数据

select_streams v会告诉 ffprobe只是给我们 video流数据,如果你删除它,它会给你的 audio信息以及

输出就像

{
"streams": [
{
"index": 0,
"codec_name": "mpeg4",
"codec_long_name": "MPEG-4 part 2",
"profile": "Simple Profile",
"codec_type": "video",
"codec_time_base": "1/25",
"codec_tag_string": "mp4v",
"codec_tag": "0x7634706d",
"width": 640,
"height": 480,
"coded_width": 640,
"coded_height": 480,
"has_b_frames": 1,
"sample_aspect_ratio": "1:1",
"display_aspect_ratio": "4:3",
"pix_fmt": "yuv420p",
"level": 1,
"chroma_location": "left",
"refs": 1,
"quarter_sample": "0",
"divx_packed": "0",
"r_frame_rate": "10/1",
"avg_frame_rate": "10/1",
"time_base": "1/3000",
"start_pts": 0,
"start_time": "0:00:00.000000",
"duration_ts": 256500,
"duration": "0:01:25.500000",
"bit_rate": "261.816000 Kbit/s",
"nb_frames": "855",
"nb_read_frames": "855",
"disposition": {
"default": 1,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0
},
"tags": {
"creation_time": "2005-10-17 22:54:33",
"language": "eng",
"handler_name": "Apple Video Media Handler",
"encoder": "3ivx D4 4.5.1"
}
}
]
}

2. 你可以利用

ffprobe -v error -show_format -show_streams video_name

它将为您提供流数据,如果您想要选定的信息,如帧速率,请使用以下命令

ffprobe -v error -select_streams v:0 -show_entries stream=avg_frame_rate -of default=noprint_wrappers=1:nokey=1 video_name

根据你的视频信息给出一个数字,问题是当你使用这种方法时,你有可能得到一个 N/A作为输出。

更多信息请查看此页 探针技巧

对于 Necro 的回答很抱歉,但是可能需要这个(因为我没有找到最近的 ffmpeg 版本的解决方案。

使用 ffmpeg 3.3.4,我发现可以通过以下方式找到:

ffprobe -i video.mp4 -show_streams -hide_banner | grep "nb_frames"

最后输出帧数。我在有音频的视频上用过。尽管它给出了两行“ nb _ frame”,但是第一行是我测试的视频的实际帧数。

Linux

ffmpeg -i "/home/iorigins/Завантаження/123.mov" -f null /dev/null

Ruby

result = `ffmpeg -i #{path} -f null - 2>&1`
r = result.match("frame=([0-9]+)")
p r[1]
Cmd ->


ffprobe.exe -v error -select_streams v:0 -show_entries stream=r_frame_rate,duration -of default=nw=1 "d:\movies\The.Matrix.1999.1080p.BrRip.x264.YIFY.dut.mp4"


Result ->


r_frame_rate=24000/1001
duration=8177.794625


Calculation ->


Frames=24000/1001*8177.794625=196071


Proof ->


ffmpeg -i "d:\movies\The.Matrix.1999.1080p.BrRip.x264.YIFY.dut.mp4" -f null /dev/null
ffmpeg version N-92938-g0aaaca25e0-ffmpeg-windows-pacman Copyright (c) 2000-2019 the FFmpeg developers
built with gcc 8.2.0 (GCC)
configuration: --pkg-config=pkg-config --pkg-config-flags=--static --extra-version=ffmpeg-windows-pacman --enable-version3 --disable-debug --disable-w32threads --arch=x86_64 --target-os=mingw32 --cross-prefix=/opt/sandbox/cross_compilers/mingw-w64-x86_64/bin/x86_64-w64-mingw32- --enable-libcaca --enable-gray --enable-libtesseract --enable-fontconfig --enable-gmp --enable-gnutls --enable-libass --enable-libbluray --enable-libbs2b --enable-libflite --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopus --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libzimg --enable-libzvbi --enable-libmysofa --enable-libaom --enable-libopenjpeg --enable-libopenh264 --enable-liblensfun --enable-nvenc --enable-nvdec --extra-libs=-lm --extra-libs=-lpthread --extra-cflags=-DLIBTWOLAME_STATIC --extra-cflags=-DMODPLUG_STATIC --extra-cflags=-DCACA_STATIC --enable-amf --enable-libmfx --enable-gpl --enable-avisynth --enable-frei0r --enable-filter=frei0r --enable-librubberband --enable-libvidstab --enable-libx264 --enable-libx265 --enable-libxvid --enable-libxavs --enable-avresample --extra-cflags='-march=core2' --extra-cflags=-O2 --enable-static --disable-shared --prefix=/opt/sandbox/cross_compilers/mingw-w64-x86_64/x86_64-w64-mingw32 --enable-nonfree --enable-decklink --enable-libfdk-aac
libavutil      56. 25.100 / 56. 25.100
libavcodec     58. 43.100 / 58. 43.100
libavformat    58. 25.100 / 58. 25.100
libavdevice    58.  6.101 / 58.  6.101
libavfilter     7. 47.100 /  7. 47.100
libavresample   4.  0.  0 /  4.  0.  0
libswscale      5.  4.100 /  5.  4.100
libswresample   3.  4.100 /  3.  4.100
libpostproc    55.  4.100 / 55.  4.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'd:\movies\The.Matrix.1999.1080p.BrRip.x264.YIFY.dut.mp4':
Metadata:
major_brand     : isom
minor_version   : 512
compatible_brands: isomiso2avc1mp41
encoder         : Lavf58.25.100
Duration: 02:16:17.91, start: 0.000000, bitrate: 2497 kb/s
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x800 [SAR 1:1 DAR 12:5], 2397 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
Metadata:
handler_name    : VideoHandler
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 93 kb/s (default)
Metadata:
handler_name    : GPAC ISO Audio Handler
Stream mapping:
Stream #0:0 -> #0:0 (h264 (native) -> wrapped_avframe (native))
Stream #0:1 -> #0:1 (aac (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
Output #0, null, to '/dev/null':
Metadata:
major_brand     : isom
minor_version   : 512
compatible_brands: isomiso2avc1mp41
encoder         : Lavf58.25.100
Stream #0:0(und): Video: wrapped_avframe, yuv420p, 1920x800 [SAR 1:1 DAR 12:5], q=2-31, 200 kb/s, 23.98 fps, 23.98 tbn, 23.98 tbc (default)
Metadata:
handler_name    : VideoHandler
encoder         : Lavc58.43.100 wrapped_avframe
Stream #0:1(und): Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s (default)
Metadata:
handler_name    : GPAC ISO Audio Handler
encoder         : Lavc58.43.100 pcm_s16le
frame=196071 fps=331 q=-0.0 Lsize=N/A time=02:16:17.90 bitrate=N/A speed=13.8x
video:102631kB audio:1408772kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

由于我的评论得到了一些赞同,我想我应该把它作为一个答案:

ffmpeg -i 00000.avi -map 0:v:0 -c copy -f null -y /dev/null 2>&1 | grep -Eo 'frame= *[0-9]+ *' | grep -Eo '[0-9]+' | tail -1

这应该很快,因为没有执行任何编码。ffmpeg只是将文件分解,并尽快读取(解码)第一个视频流。第一个 grep命令将获取显示框架的文本。第二个 grep命令将从中获取数字。tail命令只显示最后一行(最终帧计数)。

ffprobeffmpeg信息的问题 帧中的实际长度相差一定的数字。

这个脚本尝试提取最后的帧。 成功的帧号也在搅拌机内工作。 超过这个数字的帧也不能在搅拌机中提取。

#!/usr/bin/env bash
# find the number of frames in a movie clip
FMAYBE=$(ffprobe -v error -select_streams v:0 -show_entries stream=nb_frames -of default=nokey=1:noprint_wrappers=1 $1)
let FMAYBE=$FMAYBE+1
FEMPTY="-"
while [ -n "$FEMPTY" ] ; do
let FMAYBE=$FMAYBE-1
echo "Trying $FMAYBE"
FEMPTY=$(ffmpeg -i $1 -vf select="between(n\,$FMAYBE\,$FMAYBE)" -vsync 0 /tmp/fmaybe%d.png 2>&1 | grep 'empty')
done
echo "Succeeds: $FMAYBE"

获取以秒为单位的持续时间,然后乘以帧速率。(这个方法很快)

获取持续时间:

ffprobe -i input.mkv -show_entries format=duration -v quiet -of csv="p=0"

获取帧速率:

ffprobe -v 0 -of csv="p=0" -select_streams V:0 -show_entries stream=r_frame_rate input.mkv

如果答案有一个小数部分,然后只是截断它。