加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Django 中使用流响应处理视频的方法

发布时间:2020-12-15 17:13:53 所属栏目:大数据 来源:网络整理
导读:背景 利用 html5 的 video 标签可以播放: video?width="320"?height="240"?controls?source?src="/static/video/demo.mp4"?type="video/mp4"?您的浏览器不支持Video标签。/video 但是这样的方式,视频中的进度条无法使用,而且以静态文件方式返回的话,后台

背景

利用 html5 的 <video> 标签可以播放:

<video?width="320"?height="240"?controls>
?<source?src="/static/video/demo.mp4"?type="video/mp4">
?您的浏览器不支持Video标签。
</video>

但是这样的方式,视频中的进度条无法使用,而且以静态文件方式返回的话,后台的程序会占用大量的内存。

使用响应流的方式能很好的解决这两个问题。

StreamingHttpResponse

大多数 Django 响应使用 HttpResponse 。这意味着响应的主体内置在内存中,并以单件形式发送到 HTTP 客户端。而如果用 StreamingHttpResponse 的方式则可以以 chunks (部分块)的方式返回。一个很简单的例子就是:

from?django.http?import?StreamingHttpResponse
?
def?hello():
??yield?'Hello,'
??yield?'there!'
?
def?test(request):
??return?StreamingHttpResponse(hello)

根据 WSGI 协议中的,当服务器调用时,应用程序对象必须返回一个可迭代的,产生零个或多个字节串。因此我们可以通过给服务器提供生成器来完成流响应的功能。

常见的使用 StreamingHttpResponse 是一些大文件的下载等,利用它还能完成断点续传的功能。

视频流

使用视频流时可以从请求头部中获得起始字节数。

201807201003158.png

这字段似乎是浏览器自动提供的,因为html代码中,我只需要改下视频的 src 的从静态地址变成路由方式而已。对于响应体而言,也要提供响应体返回的块的一个范围:

201807201003159.png

Content-Range 分别表示了 起始字节号-终止字节号/文件总字节 ,该响应体的内容包含了文件该范围内的内容。处理视频流的代码如下:

import?re
import?os
from?wsgiref.util?import?FileWrapper
from?django.http?import?StreamingHttpResponse
?
def?file_iterator(file_name,?chunk_size=8192,?offset=0,?length=None):
??with?open(file_name,?"rb")?as?f:
????f.seek(offset,?os.SEEK_SET)
????remaining?=?length
????while?True:
??????bytes_length?=?chunk_size?if?remaining?is?None?else?min(remaining,?chunk_size)
??????data?=?f.read(bytes_length)
??????if?not?data:
????????break
??????if?remaining:
????????remaining?-=?len(data)
??????yield?data
?
def?stream_video(request,?path):
??"""将视频文件以流媒体的方式响应"""
??range_header?=?request.META.get('HTTP_RANGE',?'').strip()
??range_re?=?re.compile(r'bytess*=s*(d+)s*-s*(d*)',?re.I)
??range_match?=?range_re.match(range_header)
??size?=?os.path.getsize(path)
??content_type,?encoding?=?mimetypes.guess_type(path)
??content_type?=?content_type?or?'application/octet-stream'
??if?range_match:
????first_byte,?last_byte?=?range_match.groups()
????first_byte?=?int(first_byte)?if?first_byte?else?0
????last_byte?=?first_byte?+?1024?*?1024?*?8????#?8M?每片,响应体最大体积
????if?last_byte?>=?size:
??????last_byte?=?size?-?1
????length?=?last_byte?-?first_byte?+?1
????resp?=?StreamingHttpResponse(file_iterator(path,?offset=first_byte,?length=length),?status=206,?content_type=content_type)
????resp['Content-Length']?=?str(length)
????resp['Content-Range']?=?'bytes?%s-%s/%s'?%?(first_byte,?last_byte,?size)
??else:
????#?不是以视频流方式的获取时,以生成器方式返回整个文件,节省内存
????resp?=?StreamingHttpResponse(FileWrapper(open(path,?'rb')),?content_type=content_type)
????resp['Content-Length']?=?str(size)
??resp['Accept-Ranges']?=?'bytes'
??return?resp



(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读