本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
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帧需要延迟展示
查看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
获取视频帧序列
5秒1张
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的值即可