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


Posted in Python onJuly 20, 2018

起步

利用 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 是一些大文件的下载等,利用它还能完成断点续传的功能。

视频流

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

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

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

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

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'bytes\s*=\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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python函数返回多个值的示例方法
Dec 04 Python
Python程序设计入门(5)类的使用简介
Jun 16 Python
跟老齐学Python之编写类之一创建实例
Oct 11 Python
Django URL传递参数的方法总结
Aug 28 Python
新手常见6种的python报错及解决方法
Mar 09 Python
python如何派生内置不可变类型并修改实例化行为
Mar 21 Python
Python SMTP发送邮件遇到的一些问题及解决办法
Oct 24 Python
django 简单实现登录验证给你
Nov 06 Python
pymysql的简单封装代码实例
Jan 08 Python
python时间日期操作方法实例小结
Feb 06 Python
opencv python 图片读取与显示图片窗口未响应问题的解决
Apr 24 Python
django restframework serializer 增加自定义字段操作
Jul 15 Python
Python实现手写一个类似django的web框架示例
Jul 20 #Python
python 实现求解字符串集的最长公共前缀方法
Jul 20 #Python
python实现求两个字符串的最长公共子串方法
Jul 20 #Python
Django基础知识与基本应用入门教程
Jul 20 #Python
opencv python 2D直方图的示例代码
Jul 20 #Python
Linux下python制作名片示例
Jul 20 #Python
Python爬虫的两套解析方法和四种爬虫实现过程
Jul 20 #Python
You might like
探讨捕获php错误信息方法的详解
2013/06/09 PHP
使用PHP Socket写的POP3类
2013/10/30 PHP
php自定义的格式化时间示例代码
2013/12/05 PHP
PHP实现基于状态的责任链审批模式详解
2019/05/31 PHP
thinkphp5.1框架中容器(Container)和门面(Facade)的实现方法分析
2019/08/05 PHP
PHP实现批量修改文件名的方法示例
2019/09/18 PHP
用js实现的一个Flash滚动轮换显示图片代码生成器
2007/03/14 Javascript
IE的有条件注释判定IE版本详解(附实例代码)
2012/01/04 Javascript
javascript实现自动输出文本(打字特效)
2015/08/27 Javascript
表格展示利器 Bootstrap Table实例代码
2017/09/06 Javascript
elementUI中Table表格问题的解决方法
2018/12/04 Javascript
jQuery基于随机数解决中午吃什么去哪吃问题示例
2018/12/29 jQuery
jquery实现有过渡效果的tab切换
2020/07/17 jQuery
[02:47]3.19DOTA2发布会 国服成长历程回顾
2014/03/25 DOTA
Python爬取附近餐馆信息代码示例
2017/12/09 Python
《Python学习手册》学习总结
2018/01/17 Python
python pandas 对时间序列文件处理的实例
2018/06/22 Python
python tornado微信开发入门代码
2018/08/24 Python
python实现的按要求生成手机号功能示例
2019/10/08 Python
python实现按关键字筛选日志文件
2019/12/24 Python
Django后台管理系统的图文使用教学
2020/01/20 Python
Tensorflow 多线程与多进程数据加载实例
2020/02/05 Python
Python 解决相对路径问题:&quot;No such file or directory&quot;
2020/06/05 Python
Django中使用Celery的方法步骤
2020/12/07 Python
一款纯css3实现的响应式导航
2014/10/31 HTML / CSS
微软瑞士官方网站:Microsoft瑞士
2018/04/20 全球购物
运动会广播稿300字
2014/01/10 职场文书
计算机毕业生自荐信范文
2014/03/23 职场文书
大学竞选班长演讲稿
2014/04/24 职场文书
物资采购方案
2014/06/12 职场文书
篮球社团活动总结
2014/06/27 职场文书
开展批评与自我批评心得体会
2014/10/17 职场文书
优秀班主任推荐材料
2014/12/17 职场文书
2015年教师节演讲稿范文
2015/03/19 职场文书
活着观后感
2015/06/03 职场文书
2016中秋节月饼促销广告语
2016/01/28 职场文书