FFmpeg实战系列--第二讲、获取视频帧

599 阅读3分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

AVPacket结构是解码之前的数据,视频一个packet是一个frame,音频一个packet一般是1024个采样 AVFrame结构是解码之后的数据,视频的frame就是yuv图像

查看packet信息

ffprobe -loglevel error -print_format csv -select_streams v:0 -show_packets   input.mp4
packet,video,0,5940,0.066000,-60,-0.000667,3000,0.033333,4020,48,K_
packet,video,0,14940,0.166000,2940,0.032667,3000,0.033333,742,4097,__
packet,video,0,8940,0.099333,5940,0.066000,3000,0.033333,180,4845,__
packet,video,0,11940,0.132667,8940,0.099333,3000,0.033333,215,5037,__
packet,video,0,20940,0.232667,11940,0.132667,3000,0.033333,1143,5258,__
packet,video,0,17940,0.199333,14940,0.166000,3000,0.033333,270,6413,__
packet,video,0,26940,0.299333,17940,0.199333,3000,0.033333,1186,6691,__
packet,video,0,23940,0.266000,20940,0.232667,3000,0.033333,297,8237,__
packet,video,0,38940,0.432667,23940,0.266000,3000,0.033333,1747,8739,__

从左到右依次为

  • packet 代表一个packet
  • codec_type 编码类型 video audio
  • stream_index stream 索引
  • pts 展示时间戳,按time_base计算,time_base为时间基,代表1s有多少份,这里是90000
  • pts_time 展示时间戳,按秒为单位
  • dts 编码时间戳,按time_base计算
  • dts_time 编码时间戳,按秒为单位
  • duration packet持续时长,按time_base计算
  • duration_time packet持续时长,,按秒为单位
  • size packet大小
  • pos packet文件位置
  • flags 是否关键帧
解释下pts和dts

视频帧有I/B/P帧,I帧一般代表关键帧,可独立编码压缩,P帧参考前面的I帧进行编码,B帧则可以前后参考,由于是前后参考,需要后面的帧先编码再编码当前的B帧,因此需要后面的帧DTS要大于PTS, P帧需要延迟展示

image.png

查看frame信息

ffprobe -loglevel error -print_format csv -select_streams v:0  -show_frames   input.mp4
frame,video,0,1,5940,0.066000,5940,0.066000,5940,0.066000,3000,0.033333,48,4020,854,480,yuv420p,1280:1281,I,0,0,0,0,0,unknown,unknown,unknown,unknown,left
frame,video,0,0,8940,0.099333,8940,0.099333,8940,0.099333,3000,0.033333,4845,180,854,480,yuv420p,1280:1281,B,2,0,0,0,0,unknown,unknown,unknown,unknown,left
frame,video,0,0,11940,0.132667,11940,0.132667,11940,0.132667,3000,0.033333,5037,215,854,480,yuv420p,1280:1281,B,3,0,0,0,0,unknown,unknown,unknown,unknown,left
frame,video,0,0,14940,0.166000,14940,0.166000,14940,0.166000,3000,0.033333,4097,742,854,480,yuv420p,1280:1281,P,1,0,0,0,0,unknown,unknown,unknown,unknown,left
frame,video,0,0,17940,0.199333,17940,0.199333,17940,0.199333,3000,0.033333,6413,270,854,480,yuv420p,1280:1281,B,5,0,0,0,0,unknown,unknown,unknown,unknown,left
frame,video,0,0,20940,0.232667,20940,0.232667,20940,0.232667,3000,0.033333,5258,1143,854,480,yuv420p,1280:1281,P,4,0,0,0,0,unknown,unknown,unknown,unknown,left

从左到右依次为

  • frame 代表一个frame
  • media_type 媒体类型 video audio
  • stream_index stream 索引
  • key_frame 是否为关键帧
  • pkt_pts 展示时间戳,按time_base计算,time_base为时间基,代表1s有多少份,这里是90000
  • pkt_pts_time 展示时间戳,按秒为单位
  • pkt_dts 编码时间戳,按time_base计算
  • pkt_dts_time 编码时间戳,按秒为单位
  • best_effort_timestamp
  • best_effort_timestamp_time
  • pkt_duration packet持续时长,按time_base计算
  • pkt_duration_time packet持续时长,,按秒为单位
  • pkt_pos packet文件位置
  • pkt_size packet大小
  • width 帧的宽
  • height 帧的高
  • pix_fmt 图片的像素格式
  • sample_aspect_ratio 像素的宽高比例
  • pict_type 帧的类型 I/B/P
  • coded_picture_number 压缩的帧序号
  • display_picture_number 展示图片的序号
  • interlaced_frame 图像的扫描方式:隔行 逐行

获取视频首帧第一个frame

 ffmpeg -i input.mp4 -v:frame 1 -q:v 2 outframe.jpg
 或
 ffmpeg -i input.mp4 -vframes 1 -q:v 2 outframe1.jpg
 选择有代表性的
 ffmpeg -i input.mp4  -vf thumbnail -vframes 1 -q:v 2 outframe1.jpg

获取视频帧序列

51张
ffmpeg -i input.mp4 -r 1/5 -q:v 2 outframe-%04d.jpg

获取视频中的关键帧

 ffmpeg -i input.mp4 -vf "select='eq(pict_type\,I)'" -q:v 2 outframe1-%04d.jpg

获取视频中的关键帧以及时间戳

ffmpeg -i input.mp4 -vf "select='eq(pict_type\,I)'" -q:v 2  outframe1-%04d.jpg -loglevel debug 2>&1 | grep 'pict_type:I'
[Parsed_select_0 @ 0x7ff4ffb00000] n:0.000000 pts:5940.000000 t:0.066000 key:1 interlace_type:P pict_type:I scene:nan -> select:1.000000 select_out:0
[Parsed_select_0 @ 0x7ff4ffb00000] n:60.000000 pts:185940.000000 t:2.066000 key:1 interlace_type:P pict_type:I scene:nan -> select:1.000000 select_out:0
[Parsed_select_0 @ 0x7ff4ffb00000] n:120.000000 pts:365940.000000 t:4.066000 key:1 interlace_type:P pict_type:I scene:nan -> select:1.000000 select_out:0
获取t的值即可