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打印“菱形”星号代码方法
Feb 05 Python
python中kmeans聚类实现代码
Feb 23 Python
简单介绍python封装的基本知识
Aug 10 Python
python中用logging实现日志滚动和过期日志删除功能
Aug 20 Python
用python3读取python2的pickle数据方式
Dec 25 Python
tensorflow求导和梯度计算实例
Jan 23 Python
python topk()函数求最大和最小值实例
Apr 02 Python
pycharm的python_stubs问题
Apr 08 Python
python入门教程之基本算术运算符
Nov 13 Python
Pycharm安装第三方库失败解决方案
Nov 17 Python
Python系统公网私网流量监控实现流程
Nov 23 Python
paramiko使用tail实时获取服务器的日志输出详解
Dec 06 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
德生H-501的评价与改造
2021/03/02 无线电
PHP+JS实现大规模数据提交的方法
2015/07/02 PHP
php使用PDO从数据库表中读取数据的实现方法(必看)
2017/06/02 PHP
修改Laravel自带的认证系统的User类的命名空间的步骤
2019/10/15 PHP
jquery $.ajax入门应用一
2008/11/19 Javascript
jQuery 加上最后自己的验证
2009/11/04 Javascript
jQuery validate 中文API 附validate.js中文api手册
2010/07/31 Javascript
js实现checkbox全选、不选与反选的方法
2015/02/09 Javascript
在AngularJS框架中处理数据建模的方式解析
2016/03/05 Javascript
实用又漂亮的BootstrapValidator表单验证插件
2016/05/30 Javascript
Jquery on方法绑定事件后执行多次的解决方法
2016/06/02 Javascript
JS阻止事件冒泡行为和闭包的方法
2016/06/16 Javascript
JQuery遍历元素的父辈和祖先的方法
2016/09/18 Javascript
javascript基本数据类型及类型检测常用方法小结
2016/12/14 Javascript
JavaScript实现大图轮播效果
2017/01/11 Javascript
微信小程序 页面跳转如何实现传值
2017/04/05 Javascript
原生JS实现旋转轮播图+文字内容切换效果【附源码】
2018/09/29 Javascript
浅谈小程序 setData学问多
2019/02/20 Javascript
JavaScript数据结构与算法之二叉树遍历算法详解【先序、中序、后序】
2019/02/21 Javascript
详解Vue中组件的缓存
2019/04/20 Javascript
解决vue elementUI中table里数字、字母、中文混合排序问题
2020/01/07 Javascript
javascript实现拼图游戏
2021/01/29 Javascript
Python和Perl绘制中国北京跑步地图的方法
2016/03/03 Python
对python 中class与变量的使用方法详解
2019/06/26 Python
在OpenCV里实现条码区域识别的方法示例
2019/12/04 Python
flask框架渲染Jinja模板与传入模板变量操作详解
2020/01/25 Python
把Anaconda中的环境导入到Pycharm里面的方法步骤
2020/10/30 Python
详解使用python爬取抖音app视频(appium可以操控手机)
2021/01/26 Python
美国女士内衣在线折扣商店:One Hanes Place
2019/03/24 全球购物
质检部经理岗位职责
2014/02/19 职场文书
促销活动总结报告
2014/04/26 职场文书
爱岗敬业事迹材料
2014/12/24 职场文书
2019年励志签名:致拼搏路上的自己
2019/10/11 职场文书
python函数指定默认值的实例讲解
2021/03/29 Python
浅谈redis缓存在项目中的使用
2021/05/20 Redis
Redis配置外网可访问(redis远程连接不上)的方法
2022/12/24 Redis