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中MYSQLdb出现乱码的解决方法
Oct 11 Python
Python的Django框架中forms表单类的使用方法详解
Jun 21 Python
Python tkinter模块弹出窗口及传值回到主窗口操作详解
Jul 28 Python
Python线性回归实战分析
Feb 01 Python
pytorch cnn 识别手写的字实现自建图片数据
May 20 Python
Python3内置模块之base64编解码方法详解
Jul 13 Python
手机使用python操作图片文件(pydroid3)过程详解
Sep 25 Python
python系统指定文件的查找只输出目录下所有文件及文件夹
Jan 19 Python
浅谈python之自动化运维(Paramiko)
Jan 31 Python
TensorFlow实现保存训练模型为pd文件并恢复
Feb 06 Python
七个Python必备的GUI库
Apr 27 Python
python读取mnist数据集方法案例详解
Sep 04 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
Linux下ZendOptimizer的安装与配置方法
2007/04/12 PHP
PHP mail 通过Windows的SMTP发送邮件失败的解决方案
2009/05/27 PHP
php 验证码制作(网树注释思想)
2009/07/20 PHP
linux下使用crontab实现定时PHP计划任务失败的原因分析
2014/07/05 PHP
PHP CodeIgniter框架的工作原理研究
2015/03/30 PHP
学习php设计模式 php实现策略模式(strategy)
2015/12/07 PHP
ThinkPHP中html:list标签用法分析
2016/01/09 PHP
php 无限分类 树形数据格式化代码
2016/10/11 PHP
Laravel框架使用monolog_mysql实现将系统日志信息保存到mysql数据库的方法
2018/08/16 PHP
几行代码轻松搞定jquery实现flash8类似的连接效果
2007/05/03 Javascript
jquery.validate使用攻略 第五步 正则验证
2010/07/01 Javascript
JQuery动态创建DOM、表单元素的实现代码
2011/08/09 Javascript
网站繁简切换的JS遇到页面卡死的解决方法
2014/03/12 Javascript
js图片自动轮播代码分享(js图片轮播)
2014/05/06 Javascript
jQuery 获取/设置/删除DOM元素的属性以a元素为例
2014/05/23 Javascript
jQuery实现ctrl+enter(回车)提交表单
2015/10/19 Javascript
利用JS轻松实现获取表单数据
2016/12/06 Javascript
vuejs开发组件分享之H5图片上传、压缩及拍照旋转的问题处理
2017/03/06 Javascript
JavaScript查看代码运行效率console.time()与console.timeEnd()用法
2019/01/18 Javascript
如何搭建一个完整的Vue3.0+ts的项目步骤
2020/10/18 Javascript
js实现缓动动画
2020/11/25 Javascript
如何在JavaScript中正确处理变量
2020/12/25 Javascript
python利用装饰器进行运算的实例分析
2015/08/04 Python
让代码变得更易维护的7个Python库
2018/10/09 Python
python仿evething的文件搜索器实例代码
2019/05/13 Python
python命令行工具Click快速掌握
2019/07/04 Python
Django项目后台不挂断运行的方法
2019/08/31 Python
Django中Q查询及Q()对象 F查询及F()对象用法
2020/07/09 Python
利用Python实现斐波那契数列的方法实例
2020/07/26 Python
欧洲领先的技术商店:eibmarkt.com
2019/05/10 全球购物
环保项目建议书
2014/08/26 职场文书
2016自主招生教师推荐信范文
2015/03/23 职场文书
2015小学教师德育工作总结
2015/05/12 职场文书
民警忠诚教育心得体会
2016/01/23 职场文书
SpringAop日志找不到方法的处理
2021/06/21 Java/Android
如何创建一个创建MySQL数据库中的datetime类型
2022/03/21 MySQL