背景
- 工程中原先是用 py 基于 opencv 从摄像设备连续获得视频帧处理后再输出到硬盘为视频 /图片
- 但是, 发现对系统负荷过大
- 所以, 尝试用 FFmpeg 代为处理
- 但是, 通过摸索, 找到合理的指令, 并尝试用 py 进行调用时失败
env.
- macOS 10.12.6 i7 3.1Ghz 4 核, 16Gb DDR3 内存
- Python 2.7.10 (default, Oct 13 2016, 22:16:45)
- [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
- ffmpeg version N-92539-g1035206102 Copyright (c) 2000-2018 the FFmpeg developers
- built with Apple LLVM version 10.0.0 (clang-1000.11.45.5)
- GNU bash,版本 4.4.12(1)-release (x86_64-apple-darwin16.3.0)
现象
类似指令:
ffmpeg -f avfoundation -s 1920x1080 -framerate 25 -i 0: -vsync 0 -f image2 /path/2/.../wframe/%06d.jpg
直接运行:
ffmpeg version N-92539-g1035206102 Copyright (c) 2000-2018 the FFmpeg developers built with Apple LLVM version 10.0.0 (clang-1000.11.45.5) ... [avfoundation @ 0x7fa94c800000] Selected pixel format (yuv420p) is not supported by the input device. [avfoundation @ 0x7fa94c800000] Supported pixel formats: [avfoundation @ 0x7fa94c800000] uyvy422 [avfoundation @ 0x7fa94c800000] yuyv422 [avfoundation @ 0x7fa94c800000] nv12 [avfoundation @ 0x7a94c800000] 0rgb [avfoundation @ 0x7fa94c800000] bgr0 [avfoundation @ 0x7fa94c800000] Overriding selected pixel format to use uyvy422 instead. [avfoundation @ 0x7fa94c800000] Stream #0: not enough frames to estimate rate; consider increasing probesize Input #0, avfoundation, from '0:': Duration: N/A, start: 11907.278033, bitrate: N/A Stream #0:0: Video: rawvideo (UYVY / 0x59565955), uyvy422, 1920x1080, 1000k tbr, 1000k tbn, 1000k tbc Stream mapping: Stream #0:0 -> #0:0 (rawvideo (native) -> mjpeg (native)) Press [q] to stop, [?] for help [swscaler @ 0x7fa94b871600] deprecated pixel format used, make sure you did set range correctly Output #0, image2, to '/path/2/.../wframe/%06d.jpg': Metadata: encoder : Lavf58.23.100 Stream #0:0: Video: mjpeg, yuvj422p(pc), 1920x1080, q=2-31, 200 kb/s, 1000k fps, 1000k tbn, 1000k tbc Metadata: encoder : Lavc58.40.100 mjpeg Side data: cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1 frame= 55 fps= 16 q=24.8 Lsize=N/A time=00:00:03.56 bitrate=N/A speed=1.01x ... 没有问题...
核心代码:
import subprocess, time cmd = ['ffmpeg' , '-f', 'avfoundation' , '-s', '1920x1080' , '-framerate', '25' # frames per second , '-i', '{}:'.format(drivers['w']) , '-vsync', '0' , '-f', 'image2' , '{}/wframe/%06d.jpg'.format(_expath) ] p = subprocess.Popen(cmd , shell=False , stdin=subprocess.PIPE #, stdout=subprocess.PIPE # merge err>out #, stderr=subprocess.STDOUT ) time.sleep(4) p.terminate() 用 subprocess.Popen 包裹后, 在合理时机用 terminate() 来安全结束, 可是在 mac 中运行时报错:
[avfoundation @ 0x7f9f01000000] Failed to create AV capture input device: Cannot Use UNIQUESKY_CAR_CAMERA 0:: Input/output error 修订 shell=True ,或是打开其它 PIPE 都不能解决;
相同硬件, 到 win10 环境中, 用相同版本 FFmpeg 来调用, 调整好的指令类似:
ffmpeg -f dshow -s:v 1920x1080 -framerate 25 video="Integrated Webcam" -f image2 /path/2/.../wframe/%06d.jpg
一样直接在 cmd 中运行正常, 但是, 用 python 包装后, 一样出现不可用报错:
: Input/output error
[avfoundation @ 0x7fa5f7802c00] Failed to create AV capture input device: Cannot Use UNIQUESKY_CAR_CAMERA #2 0:: Input/output error : 设备争用
[dshow @ 0000014269bab740] Could not run graph (sometimes caused by a device already in use by other application) video=@device_pnp_\\?\usb#vid_05a3&pid_9230&mi_00#6&1d3a4c24&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global: I/O error 此时检查:
λ taskkill /IM ffmpeg.exe 错误: 没有找到进程 "ffmpeg.exe"。 并没有其它进程在使用硬件
PS:
用 FFmpeg 在 win10 环境中检验设备时是这样的
λ ffmpeg -list_devices true -f dshow -i dummy ffmpeg version N-92539-g1035206102 Copyright (c) 2000-2018 the FFmpeg developers built with gcc 8.2.1 (GCC) 20181017 ... [dshow @ 0000021f90a2a840] DirectShow video devices (some may be both video and audio devices) [dshow @ 0000021f90a2a840] "Integrated Webcam" [dshow @ 0000021f90a2a840] Alternative name "@device_pnp_\\?\usb#vid_1bcf&pid_0b09&mi_00#7&1bf8ceab&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global" [dshow @ 0000021f90a2a840] DirectShow audio devices [dshow @ 0000021f90a2a840] "楹椋?(4- USB PnP Sound Device)" [dshow @ 0000021f90a2a840] Alternative name "@device_cm_{33D9A762-90C8-11D0-BD43-00A0C911CE86}\wave_{25AB1848-CB77-42E5-9985-767755AA0C9C}" dummy: Immediate exit requested 即, 所有可用设备有两种指代:
- USB ID, 类似 "Integrated Webcam"
- 内部别名: 类似 "@device_pnp_\?\usb#vid_1bcf&pid_0b09&mi_00#7&1bf8ceab&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
- 之前为防止多设备 /重名设备, 用别名来引用的
- 效果和用 ID 名称没区别.
suggest
有老司机称:
其实是这样的,windows 那个 cmd,如果你给它双引号,好像也是会被 shell 吃掉的,然后程序的 argv 没有引号,跟 bash 有点类似;
- 比如你给 python a=1 b="2" "c=3"
- 然后 python 里的 sys.argv == {blah, 'a=1', 'b=2', 'c=3'} 引号就被 cmd 吃掉了
- 单引号不会被 cmd 吃掉,双引号都没了
另外,
- subprocess 运行的时候比较推荐的
- 可能还是第一个参数是个 list,
- 然后 shell=False,
- 这样可以避免若干头疼的引号问题和命令行注入的问题
但是, 按照以上建议无论怎么折腾都是无法正常通过 Python 完成 FFMpeg 的调用.
大家有什么其它思路?
参考:
- subprocess Work with additional processes - Python Module of the Week
- Read and write video frames in Python using FFMPEG - __del__( self )
- Processing Camera stream in Opencv, pushing it over RTMP (NGINX RTMP Module) using FFMPEG - Stack Overflow
- Hacking FFmpeg With Python - Part One
- python - Getting realtime output from ffmpeg to be used in progress bar (PyQt4, stdout) - Stack Overflow
- ...

