用Flask实现视频数据流传输
admin
2023-07-31 01:43:21
0

Flask 是一个 Python 实现的 Web 开发微框架。这篇文章是一个讲述如何用它实现传送视频数据流的详细教程。

我敢肯定,现在你已经知道我在O’Reilly Media上发布了有关Flask的一本书和一些视频资料。在这些上面,Flask框架介绍的覆盖面是相当完整的,出于某种原因,也有一小部分的功能没有太多的提到,因此我认为在这里写一篇介绍它们的文章是一个好主意。

这篇文章是专门介绍流媒体的,这个有趣的功能让Flask应用拥有这样一种能力,以分割成小数据块的方式,高效地为大型请求提供数据,这可能要花费较长的时间。为了说明这个主题,我将告诉你如何构建一个实时视频流媒体服务器!

什么是流媒体?

流媒体是一种技术,其中,服务器以数据块的形式响应请求。我能想到一个原因来解释为什么这个技术可能是有用的:

  • 非常大的响应 。对于非常大的响应而言,内存中收集的响应只返回给客户端,这是很低效的。另一种方法是将响应写入磁盘,然后使用flask.send_file()返回文件,但是这增加了I/O的组合。假设数据可以分块生成,以小块数据的方式给请求提供响应是一种更好的解决方案。
  • 实时数据 。对于一些应用,需要请求返回的数据来自实时数据源。在这个方面一个非常好的例子就是提供一个实时视频或音频。很多安全摄像机使用这种技术将视频数据流传输给Web浏览器。

使用Flask实现流式传输

Flask通过使用生成器函数对流式响应提供本机支持。生成器是一个特别的函数,它可以中断和恢复。考虑一下下面的函数:

1234 def gen():        yield 1        yield 2        yield 3

这是一个运行三步的函数,其中每步返回一个值。描述生成器如何实现超出了本文的范围,但如果你有点好奇,下面的shell会话将给你说明生成器是如何被使用的:

12345678910111213 ; htmlscript: false ]>>> x = gen()>>> x<generator object gen at 0x7f06f3059c30>>>> x.next()1>>> x.next()2>>> x.next()3>>> x.next()Traceback (most recent call last):  File \”\”, line 1, in <module>StopIteration

在这个简单的例子中你能看到,一个生成器函数可以顺序得返回多个结果。Flask使用生成器 函数这一特性来实现流式传输。

下面的例子说明了如何使用流式传输能够产生大的数据表,而不必将整个表放入内存中:

123456789101112 from flask import Response, render_templatefrom app.models import Stock def generate_stock_table():    yield render_template(\’stock_header.html\’)    for stock in Stock.query.all():        yield render_template(\’stock_row.html\’, stock=stock)    yield render_template(\’stock_footer.html\’) @app.route(\’/stock-table\’)def stock_table():    return Response(generate_stock_table())

在这个例子中,你能看到Flask和生成器函数是如何一起工作的。返回流式响应的路由(route)需要返回一个由生成器函数初始化的Response对象。Flask然后采取调用生成器,并以分块的方式吧结果发送给客户端。

对于这个特殊的例子,如果你假设Stock.query.all()返回的数据库查询结果是一个迭代器,那么你能一次生成一个潜在大表的一行,因此无论查询中的字符数量有多少,Python过程中的内存消耗不会因为较大的响应字符串而越来越大。

多部分响应

上文提到了表的例子以小块的形式生成一个传统网页,各个的部分连接成最后的结果。对于如何生成较大的响应这是一个很好的例子,但更令人激动的事情是处理实时数据。

使用流式传输的一个有趣的应用是使用每个块来替换原来页面中的地方,这能使流在浏览器窗口中形成动画。利用这种技术,你可以让流中每个数据块成为一个图像,这给你提供了一个运行在浏览器中的很酷的视频输入信号!

实现就地更新的秘密是使用多部分响应。多部分响应由一个报头(header)和很多部分(parts)组成。报头包括多部分中的一种内容类型,后面的部分由边界标记分隔,每个部分中含有自身部分中的特定内容类型。

对于不同的需求,这里有一些多部分内容类型。对于具有流式传输的,每个部分替换先前部分必须使用multipart/x-mixed-replace内容类型。为了帮助你了解它到底是什么样子的,这里有一个多部分视频流传输的响应结构:

123456789101112 ; htmlscript: false ]HTTP/1.1 200 OKContentType: multipart/xmixedreplace; boundary=frame frameContentType: image/jpeg &lt;jpeg data here&gt;frameContentType: image/jpeg &lt;jpeg data here&gt;...

正如你上面看到的,这个结构非常简单。主要的Content-Type头被设为multipart/x-mixed-replace,同时边界标记也被定义。然后每个部分中包括,有两个短横线的前缀,及这行上的边界字符串。每个部分有自己的Content-Type头,并且每个部分可以可选地包括一个说明所在部分有效载荷的字节长度的Content-Length头,但至少对图像浏览器而言,能够处理没有长度的流。

建立一个实时视频流媒体服务器

这篇文章中已经有足够的理论,现在是时候来建立一个将实时视频流式传输到Web浏览器的完整应用。

这里有很多方法将视频流式传输到浏览器,并且每个方法都有其优点和缺点。与Flask流特征协同工作的一个好方法是流式传输独立的JPEG图片序列。这就是动态JPEG。这被用于许多IP监控摄像机。这种方法具有较短的延迟时间,但传输质量并不是最好的,因为对于动态影像而言,JPEG压缩不是非常有效。

下面你可以看到一个非常简单但完整的Web应用。它可以提供一个动态JPEG流传输:

123456789101112131415rayon-num\” data-line=\”crayon-581272c6719bb087176618-11\”>1112131415߻译组。

Flask 是一个 Python 实现的 Web 开发微框架。这篇文章是一个讲述如何用它实现传送视频数据流的详细教程。

我敢肯定,现在你已经知道我在O’Reilly Media上发布了有关Flask的一本书和一些视频资料。在这些上面,Flask框架介绍的覆盖面是相当完整的,出于某种原因,也有一小部分的功能没有太多的提到,因此我认为在这里写一篇介绍它们的文章是一个好主意。

这篇文章是专门介绍流媒体的,这个有趣的功能让Flask应用拥有这样一种能力,以分割成小数据块的方式,高效地为大型请求提供数据,这可能要花费较长的时间。为了说明这个主题,我将告诉你如何构建一个实时视频流媒体服务器!

什么是流媒体?

流媒体是一种技术,其中,服务器以数据块的形式响应请求。我能想到一个原因来解释为什么这个技术可能是有用的:

  • 非常大的响应 。对于非常大的响应而言,内存中收集的响应只返回给客户端,这是很低效的。另一种方法是将响应写入磁盘,然后使用flask.send_file()返回文件,但是这增加了I/O的组合。假设数据可以分块生成,以小块数据的方式给请求提供响应是一种更好的解决方案。
  • 实时数据 。对于一些应用,需要请求返回的数据来自实时数据源。在这个方面一个非常好的例子就是提供一个实时视频或音频。很多安全摄像机使用这种技术将视频数据流传输给Web浏览器。

使用Flask实现流式传输

Flask通过使用生成器函数对流式响应提供本机支持。生成器是一个特别的函数,它可以中断和恢复。考虑一下下面的函数:

1234 def gen():        yield 1        yield 2        yield 3

这是一个运行三步的函数,其中每步返回一个值。描述生成器如何实现超出了本文的范围,但如果你有点好奇,下面的shell会话将给你说明生成器是如何被使用的:

12345678910111213 ; htmlscript: false ]>>> x = gen()>>> x<generator object gen at 0x7f06f3059c30>>>> x.next()1>>> x.next()2>>> x.next()3>>> x.next()Traceback (most recent call last):  File \”\”, line 1, in <module>StopIteration

在这个简单的例子中你能看到,一个生成器函数可以顺序得返回多个结果。Flask使用生成器 函数这一特性来实现流式传输。

下面的例子说明了如何使用流式传输能够产生大的数据表,而不必将整个表放入内存中:

123456789101112 from flask import Response, render_templatefrom app.models import Stock def generate_stock_table():    yield render_template(\’stock_header.html\’)    for stock in Stock.query.all():        yield render_template(\’stock_row.html\’, stock=stock)    yield render_template(\’stock_footer.html\’) @app.route(\’/stock-table\’)def stock_table():    return Response(generate_stock_table())

在这个例子中,你能看到Flask和生成器函数是如何一起工作的。返回流式响应的路由(route)需要返回一个由生成器函数初始化的Response对象。Flask然后采取调用生成器,并以分块的方式吧结果发送给客户端。

对于这个特殊的例子,如果你假设Stock.query.all()返回的数据库查询结果是一个迭代器,那么你能一次生成一个潜在大表的一行,因此无论查询中的字符数量有多少,Python过程中的内存消耗不会因为较大的响应字符串而越来越大。

多部分响应

上文提到了表的例子以小块的形式生成一个传统网页,各个的部分连接成最后的结果。对于如何生成较大的响应这是一个很好的例子,但更令人激动的事情是处理实时数据。

使用流式传输的一个有趣的应用是使用每个块来替换原来页面中的地方,这能使流在浏览器窗口中形成动画。利用这种技术,你可以让流中每个数据块成为一个图像,这给你提供了一个运行在浏览器中的很酷的视频输入信号!

实现就地更新的秘密是使用多部分响应。多部分响应由一个报头(header)和很多部分(parts)组成。报头包括多部分中的一种内容类型,后面的部分由边界标记分隔,每个部分中含有自身部分中的特定内容类型。

对于不同的需求,这里有一些多部分内容类型。对于具有流式传输的,每个部分替换先前部分必须使用multipart/x-mixed-replace内容类型。为了帮助你了解它到底是什么样子的,这里有一个多部分视频流传输的响应结构:

123456789101112 ; htmlscript: false ]HTTP/1.1 200 OKContentType: multipart/xmixedreplace; boundary=frame frameContentType: image/jpeg &lt;jpeg data here&gt;frameContentType: image/jpeg &lt;jpeg data here&gt;...

正如你上面看到的,这个结构非常简单。主要的Content-Type头被设为multipart/x-mixed-replace,同时边界标记也被定义。然后每个部分中包括,有两个短横线的前缀,及这行上的边界字符串。每个部分有自己的Content-Type头,并且每个部分可以可选地包括一个说明所在部分有效载荷的字节长度的Content-Length头,但至少对图像浏览器而言,能够处理没有长度的流。

建立一个实时视频流媒体服务器

这篇文章中已经有足够的理论,现在是时候来建立一个将实时视频流式传输到Web浏览器的完整应用。

这里有很多方法将视频流式传输到浏览器,并且每个方法都有其优点和缺点。与Flask流特征协同工作的一个好方法是流式传输独立的JPEG图片序列。这就是动态JPEG。这被用于许多IP监控摄像机。这种方法具有较短的延迟时间,但传输质量并不是最好的,因为对于动态影像而言,JPEG压缩不是非常有效。

下面你可以看到一个非常简单但完整的Web应用。它可以提供一个动态JPEG流传输:

123456789101112131415k (most recent call last):  File \”\”, line 1

相关内容

热门资讯

500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...