上周一个学姐问我有没有兴趣毕业去她那做图像处理,抛给我个模式识别问题和一段4000+秒的mp4视频。大周末的我正犯五月病,就跟群里大佬问了下视频抓帧用什么合适,知道神奇的FFmpeg后顺手写了个python脚本做一下批量抓帧。至于为什么要用python不直接写shell,因为FFmpeg自带的批量抓帧命令是针对连续时间序列进行的,执行起来特别慢,用python是要做一下时间序列离散化,然后并行处理。
FFmpeg     先引用百度百科简单介绍下FFmpeg:
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多codec都是从头开发的。
 
    关于FFmpeg的业界地位,有很多视音频播放器是通过给FFmpeg加壳完成的。它是跨平台的,linux、win、mac os下都有发行版。想要安装,可以去官网 看看。关于文档,我找到的总结、教程、手册都比较零散,官方的英语文档又让新手无从看起,这次我只查到够用的资料就放着了,如果读者找到比较全面的实用手册,欢迎留言。
实现     我试着直接执行FFmpeg的批量抓帧命令时发现特别慢,几乎总要花费目标视频一半的播放时间。但是单张抓帧,不论时间点在哪里,其实都很快。于是我的思路是把视频的总时长拿出来,然后获得一个均匀分布的时间点集合,最后统统扔给gevent的pool并行抓帧。gevent是python一个著名的coroutine(协程)框架,初衷是处理高并发的网络IO,要安装pip一下就好。思路很简单,脚本也很短,life is short, I choose python!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 import  osfrom  commands import  getoutputimport  refrom  gevent.pool import  Pool as   Gpoolfrom  time import  time'' '' 1 while  True :'Vedio path: ' )if  os.path.isfile(file_path):break else :print  'Not a file.' while  True :'Output path( current directory for default ) : ' )if  ouput_path == '' :break if  os.path.exists(ouput_path) and  not  os.path.isfile(ouput_path):'/' break else :print  'Not a directory.' while  True :'Snap interval( 1 second for default ) : ' )if  s == '' :1 break if  re.match (r'^[0-9]+(.[0-9]+){0,1}$' , s) is  None :print  'Not a number.' else :float (s)break 'ffmpeg -i '  + file_path)r'(?<=Duration: ).*?(?=,)' , info).group(0 ).split(':' )int (dur[0 ])*3600  + int (dur[1 ])*60  + float (dur[2 ])print  'Vedio duration: %.2f seconds.'  % dur0 while  time_stamp < dur:'ffmpeg -ss %f -i %s -nostats -loglevel 0 -q:v 2 -f image2 %s%d.jpg'  len (time_stamp_pool)print  '%d frames to be snapped.'  % n_snapprint  'Handling...' for  i in  xrange(n_snap):print  'Done in %.2f seconds.'  % time_cost