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 07 Python
使用Python脚本将Bing的每日图片作为桌面的教程
May 04 Python
Python下载懒人图库JavaScript特效
May 28 Python
Python实现递归遍历文件夹并删除文件
Apr 18 Python
python3.6 实现AES加密的示例(pyCryptodome)
Jan 10 Python
python 将md5转为16字节的方法
May 29 Python
在PyCharm中实现关闭一个死循环程序的方法
Nov 29 Python
深入学习python多线程与GIL
Aug 26 Python
Python如何访问字符串中的值
Feb 09 Python
python实现秒杀商品的微信自动提醒功能(代码详解)
Apr 27 Python
python使用正则表达式匹配txt特定字符串(有换行)
Dec 09 Python
python如何读取.mtx文件
Apr 22 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
实现在同一方法中获取当前方法中新赋值的session值解决方法
2014/06/26 PHP
PHP结合jQuery实现找回密码
2015/07/22 PHP
Yii2框架RESTful API 格式化响应,授权认证和速率限制三部分详解
2016/11/10 PHP
js 单引号 传递方法
2009/06/22 Javascript
JQuery index()方法使用代码
2010/06/02 Javascript
jtable列中自定义button示例代码
2013/11/21 Javascript
js常用自定义公共函数汇总
2014/01/15 Javascript
JS回调函数的应用简单实例
2014/09/17 Javascript
js+css实现的圆角边框TAB选项卡滑动门代码分享(2款)
2015/08/26 Javascript
如何防止JavaScript自动插入分号
2015/11/05 Javascript
jquery及js实现动态加载js文件的方法
2016/01/21 Javascript
jQuery使用serialize()表单序列化时出现中文乱码问题的解决办法
2016/07/27 Javascript
详解AngularJS中ng-src指令的使用
2016/09/07 Javascript
详解vue-router基本使用
2017/04/18 Javascript
Angularjs 与 bower安装和使用详解
2017/05/11 Javascript
Angular通过angular-cli来搭建web前端项目的方法
2017/07/27 Javascript
Angular 多级路由实现登录页面跳转(小白教程)
2019/11/19 Javascript
Vue循环中多个input绑定指定v-model实例
2020/08/31 Javascript
在vue中使用eslint,配合vscode的操作
2020/11/09 Javascript
[01:28:56]2014 DOTA2华西杯精英邀请赛 5 24 CIS VS DK
2014/05/26 DOTA
[05:45]Ti4观战指南(下)
2014/07/07 DOTA
[01:31:03]DOTA2完美盛典全回顾 见证十五项大奖花落谁家
2017/11/28 DOTA
Python实现批量将word转html并将html内容发布至网站的方法
2015/07/14 Python
数据清洗--DataFrame中的空值处理方法
2018/07/03 Python
numpy.meshgrid()理解(小结)
2019/08/01 Python
python性能测量工具cProfile使用解析
2019/09/26 Python
python实点云分割k-means(sklearn)详解
2020/05/28 Python
什么是python的自省
2020/06/21 Python
美国男士内衣品牌:Tommy John
2017/12/22 全球购物
微软中国官方旗舰店:销售Surface、Xbox One、笔记本电脑、Office
2018/07/23 全球购物
《这儿真好》教学反思
2014/02/22 职场文书
企业家王石演讲稿:坚持与放下
2014/04/27 职场文书
病人慰问信范文
2015/02/15 职场文书
销售员自我评价
2015/03/11 职场文书
2015年店长工作总结范文
2015/04/08 职场文书
python对文档中元素删除,替换操作
2022/04/02 Python