美文网首页Python WebFlaskFLASK入门
使用flask构建直播服务。

使用flask构建直播服务。

作者: 彩色系 | 来源:发表于2017-08-18 13:39 被阅读419次

    流是什么?

    一种处理实时数据的方法。还有一种使用场景是当前要处理的数据很大,无法一次放入内存,使用流能够使用很小的内存完成处理。python中主要是靠
    生成器来解决。即在调用时才处理。而不是预先要加载全部数据。

    def gen():
        yield 1
        yield 2
        yield 3
    

    只有使用next调用才执行。

    在flask中的response是支持流的。

    实现视频流需要的格式是

    multipart/x-mixed-replace

    这是每一帧需要包含的信息。

    b'--frame\r\n'
            b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n'
    

    程序的基本结构如下。

    index绑定到 / 路由上。返回一个界面。
    gen方法使用生成器产生实时数据
    video_feed 进行响应
    #!/usr/bin/env python
    from flask import Flask, render_template, Response
    from camera import Camera
    
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        return render_template('index.html')
    
    def gen(camera):
        while True:
            frame = camera.get_frame()
            yield (b'--frame\r\n'
                   b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
    
    @app.route('/video_feed')
    def video_feed():
        return Response(gen(Camera()),
                        mimetype='multipart/x-mixed-replace; boundary=frame')
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', debug=True,threaded=True)
    

    这是index.html模板,可以看到src指向上面的viedofeed函数,返回流响应。

    <html>
      <head>
        <title>Video Streaming Demonstration</title>
      </head>
      <body>
        <h1>flask Video Streaming</h1>
        ![]({{ url_for('video_feed') }})
      </body></html>
    
    下一步就是获取帧了。首先使用三个图片来替代。
    from time import time
    
    class Camera(object):
        def __init__(self):
            self.frames = [open(f + '.jpg', 'rb').read() for f in ['1', '2', '3']]
    
        def get_frame(self):
            return self.frames[int(time()) % 3]
    

    这样实现的效果是三幅图片持续循环。

    下一步是获取真正的直播流。
    使用opencv的python模块就可以。

    def frames():
        camera = cv2.VideoCapture(0)
        if not camera.isOpened():
            raise RuntimeError('Could not start camera.')
    
        while True:
            # read current frame
            _, img = camera.read()
    
            # encode as a jpeg image and return it
            yield cv2.imencode('.jpg', img)[1].tobytes()
    

    一直捕获数据,然后通过生成器产生。将这个函数接入到上面的gen函数是可以直接执行的。

    性能提升

    这种不做任何处理的方式会消耗大量的cpu资源,其中一个原因是因为后台捕获的线程和向
    客户端发送的线程不同步。这就导致后台一直在大量获取数据,但并不是所有的数据都被传送了出去。
    为了提高性能将两者进行同步。只把后台获取的原始帧进行发送。
    使用线程的threading.event能够实现。

    class CameraEvent(object):
        # ...
    
    class BaseCamera(object):
        # ...
    event = CameraEvent()
    
        # ...
    
    def get_frame(self):
        """Return the current camera frame."""
        BaseCamera.last_access = time.time()
    
        # 阻塞 等待相机线程来唤醒
        BaseCamera.event.wait()
        BaseCamera.event.clear()# 将标志位设置为阻塞
    
        return BaseCamera.frame
    
    @classmethod
    def _thread(cls):
        # ...
        for frame in frames_iterator:
            BaseCamera.frame = frame
            BaseCamera.event.set()  # 唤醒上面阻塞的地方
          #判断最后查看时间,来决定是否关闭。
          if time.time() - BaseCamera.last_access > 10:
              frames_iterator.close()
    

    上面的wait方法会阻塞直到标志位变为true,clear方法将标志位重置为false
    set方法重置为true 通过这个机制实现同步。首先是等待唤醒,然后再将标志位
    变为flase,然后继续进行。

    在电脑上开启服务,然后在手机上查看如下:


    直播直播

    原作者
    code下载地址
    www.yunxcloud.cn

    相关文章

      网友评论

        本文标题:使用flask构建直播服务。

        本文链接:https://www.haomeiwen.com/subject/shharxtx.html