[FFmpeg] Python 2.7 怎样合理的包裹外部指令安定调用第三方工具并安全结束? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
ZoomQuiet
V2EX    Python

[FFmpeg] Python 2.7 怎样合理的包裹外部指令安定调用第三方工具并安全结束?

  •  
  •   ZoomQuiet
    ZoomQuiet 2018-12-01 17:45:44 +08:00 3833 次点击
    这是一个创建于 2504 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    • 工程中原先是用 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 @ 0x7fa94c800000] 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-9239-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 的调用.

    大家有什么其它思路?

    参考:

    14 条回复    2018-12-06 16:16:45 +08:00
    menc
        1
    menc  
       2018-12-01 18:25:55 +08:00
    如果只是要定期杀掉,那不如用 os.system 运行 nohup 命令,然后把 pid 输出,sleep 后 kill 掉该 pid 就好
    hsfzxjy
        2
    hsfzxjy  
       2018-12-01 18:39:35 +08:00 via Android
    不明白为什么要 sleep(4)? p.communicate() 阻塞等待不好么
    Philippa
        3
    Philippa  
       2018-12-01 21:14:15 +08:00 via iPhone
    Subprocess 不能保证 terminated 能够杀死进程,你要弄一个父进程然后杀整个进程树,把这个进程挂在 setsid。不要自然堵塞,要实际监控。ffmpeg 应该重新编译确保插件完备不要用 apt。摄像头要用硬编码输出不要用软件编码,否则 Cpu 占比很高。最后用 output 输出查看情况不要用 Popen,虽说其实也是封装了它。最最后加个输出视频质量检查,用 opencv。或弄个超简单的机器学习模型也可以。我弄了一个去采集数据跑了很多了没什么问题,具体原理我也不感兴趣。如果搞不定也只是拍照,去找 v4l2capture。另外建议不要搞多平台,应该用 docker。
    e9e499d78f
        4
    e9e499d78f  
       2018-12-01 21:25:25 +08:00
    用 plumbum
    ZoomQuiet
        5
    ZoomQuiet  
    OP
       2018-12-01 23:43:11 +08:00
    @hsfzxjy 是也乎,( ̄ ̄)
    只是个样例, 实际用, 肯定是通过其它渠道影响用户 /事件, 进行异步中断的
    ZoomQuiet
        6
    ZoomQuiet  
    OP
       2018-12-01 23:48:51 +08:00
    @Philippa 是也乎,( ̄ ̄)
    多谢建议 v4l2capture , 只是这是 linux only 的?
    俺也不想折腾多平台, 只是当前被迫要先部署 win10 环境发布, 客户要求...
    所以.....

    不过, 也打开了另外的思路, FFmpeg 并不是唯一的高性能图像 /视频抓取平台...
    ZoomQuiet
        7
    ZoomQuiet  
    OP
       2018-12-01 23:49:42 +08:00
    @menc 是也乎,( ̄ ̄)
    多谢分享经验, 现在的主要问题, 不是进程无法关闭,
    而是相同的指令, 在 py 子进程中不可工作, 进程的关闭是正常的...
    ZoomQuiet
        8
    ZoomQuiet  
    OP
       2018-12-01 23:57:54 +08:00
    @e9e499d78f 是也乎,( ̄ ̄)
    plumbum got it ;-)
    以及 Pexpect 都是值得嗯哼的
    julyclyde
        9
    julyclyde  
       2018-12-02 10:37:36 +08:00
    zq 你现在做啥工作啊?咋有这么倒霉的需求要解决?
    ZoomQuiet
        10
    ZoomQuiet  
    OP
       2018-12-02 16:05:51 +08:00
    @julyclyde 是也乎,( ̄ ̄)
    被创业, 被 win10....你懂的...
    julyclyde
        11
    julyclyde  
       2018-12-02 17:47:39 +08:00
    @ZoomQuiet 还是在珠海吗?
    lolizeppelin
        12
    lolizeppelin  
       2018-12-06 14:25:08 +08:00
    这个和 python 没关系

    了解下 wait waitpid fork 父子进程 信号 相关的 linux 知识

    回头再来看你的问题就一目了然了
    ZoomQuiet
        13
    ZoomQuiet  
    OP
       2018-12-06 14:51:36 +08:00
    @lolizeppelin 是也乎,( ̄ ̄)
    问题是要解决的场景主要是 win10 中的...这就和以往 linux 进程信号机制没关系了...
    lolizeppelin
        14
    lolizeppelin  
       2018-12-06 16:16:45 +08:00
    win 的原理差不多 管道什么的 都差不多逻辑

    因为没 fork 处理起来比较复杂 subprocess 里怎么处理的详细读下就好,win 相关的代码还是蛮恶心的

    但主要是要清楚系统这部分的原理就好了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     867 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 21:44 PVG 05:44 LAX 14:44 JFK 17:44
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86