利用python多进程控制流视频的切割与图片转换

Posted by echo069 on September 8, 2018

之前已经讲过摄像头视频,文件视频的切割与合成,因为大多数情况下,我们需要进行处理的都是远程发来的视频信号,所以本次要用到之前已经写过的经ffserver和ffmpeg搭建好的流媒体服务。

获取流视频

首先启动ffserver

ffserver -f ~/ffserver/ffserver.conf

然后启动ffmpeg,从摄像头(模拟机器人视角)拿到数据

ffmpeg -i /dev/video0 http://localhost:8090/feed1.ffm

这条命令就是把数据从摄像头传输到ffserver,即http://localhost:8090/feed1.ffm进入ffserver,然后经ffserver输出为http://127.0.0.1:8090/test1.mpg 我们要切割的就是http://127.0.0.1:8090/test1.mpg这个流视频

我们将接收到的客户端套接字对象保存到client变量中,将远程连接的细节保存到addr变量中。接着。我们以handle_client函数为回调函数创建了一个新的线程对象,将客户端套接字作为一个句柄传递给它。然后我们启动线程开始处理客户端的连接。handle_client函数执行recv()函数之后将一段信息发送给客户端。

python总进程控制三个子进程

  • 第一个进程:流视频切割 这里依然用到gst-launch-1.0的命令行形式 sudo gst-launch-1.0 -v http://127.0.0.1:8090/test1.mpg ! decodebin ! videoconvert ! jpegenc ! multifilesink location=”/home/echo/TEST/test4/pictures/frame%06d.jpg” 将这条命令放在split.sh的shell脚本中,后面直接通过python调用这个脚本

  • 第二个进程:监视器设置 视频切割成图片保存的过程中,因为存在一个切割时间问题,所以我们在转换阶段可能转换的是一个半成品图片,这样后期的转换也就毫无意义。 所以我们需要用到一个监视器来监测每一张切割的的图片是否写入成功,只要写入成功就会返回该图片的名称放在队列里用于后期的查找和转换。 这里要用到的是python的pyinotify。

  • 第三个进程:图片转换处理 这里要设置一个不停止的循环(即while Ture),可以每时每刻去循环队列,只要队列不为空,就get到图片名称进行查找,转换,删除操作。

文件代码如下:

#coding=utf8
import multiprocessing
import os
import datetime
import pyinotify
from PIL import Image, ImageFilter
import shutil
from time import sleep

    
# watch 进程
# 监视图片产生过程,防止产生半成品,干扰转换结果
# 并且将已经切割好的图片名称放进队列
def send(name):
    q.put(name[:-7:])
    print name[:-7:]

class MyEventHandler(pyinotify.ProcessEvent):

     
    def process_IN_ACCESS(self, event):
        print "ACCESS event:", event.pathname
    
     
    def process_IN_ATTRIB(self, event):
        print "ATTRIB event:", event.pathname
    
    def process_IN_CLOSE_NOWRITE(self, event):
        print "CLOSE_NOWRITE event:", event.pathname
        
    def process_IN_CLOSE_WRITE(self, event):
        print "CLOSE_WRITE event:", event.pathname
        print "================================="
        try:
            send(event.pathname)

        except Exception,e:
            print str(e)

         
    def process_IN_CREATE(self, event):
        print "CREATE event:", event.pathname
     
    def process_IN_DELETE(self, event):
        print "DELETE event:", event.pathname
    
    def process_IN_MODIFY(self, event):
        print "MODIFY event:", event.pathname
    
    def process_IN_OPEN(self, event):
        print "OPEN event:", event.pathname
   
     
def watch():
    # watch manager
    wm = pyinotify.WatchManager()
    wm.add_watch('/home/echo/TEST/test4/pictures', pyinotify.ALL_EVENTS, rec=True)
    #/tmp是可以自己修改的监控的目录
    # event handler
    eh = MyEventHandler()
    # notifier
    notifier = pyinotify.Notifier(wm, eh)
    notifier.loop()

# watch 进程结束 


# split进程
#源源不断的产生图片

def split():
    os.system("./split.sh") 
    
# split 进程结束

# convert进程
# 转换队列里图片名称相对应的图片
def convert():
    while True:
        while not q.empty():
            image_path = q.get()
            save_folder = "/home/echo/TEST/test4/pictures_conv/"

            im = Image.open(image_path)
            try:
                im.filter(ImageFilter.EMBOSS).save(save_folder+image_path.replace('/','-'))
                os.remove(image_path)
            except IOError:
                print("Cannot convert", image_path)
#convert进程结束


q=multiprocessing.Queue() #全局定义一个q进程队列,在产生子进程时候会在子进程里生成,可以指定最大数,限制队列长度
if __name__ == '__main__':
    #初始化3个子进程
    convert=multiprocessing.Process(target=convert,args=()) 
    watch=multiprocessing.Process(target=watch,args=())
    split=multiprocessing.Process(target=split,args=()) 
    #启动子进程
    convert.start()
    watch.start()
    split.start()