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 分析Nginx访问日志并保存到MySQL数据库实例
Mar 13 Python
python xml.etree.ElementTree遍历xml所有节点实例详解
Dec 04 Python
python之virtualenv的简单使用方法(必看篇)
Nov 25 Python
Python方法的延迟加载的示例代码
Dec 18 Python
python实现数据预处理之填充缺失值的示例
Dec 22 Python
python被修饰的函数消失问题解决(基于wraps函数)
Nov 04 Python
Python连接SQLite数据库并进行增册改查操作方法详解
Feb 18 Python
150行Python代码实现带界面的数独游戏
Apr 04 Python
Python xpath表达式如何实现数据处理
Jun 13 Python
浅谈Python协程
Jun 17 Python
pycharm2020.1.2永久破解激活教程,实测有效
Oct 29 Python
宝塔更新Python及Flask项目的部署
Apr 11 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
给ECShop添加最新评论
2015/01/07 PHP
ThinkPHP实现简单登陆功能
2017/04/28 PHP
Google Map Api和GOOGLE Search Api整合实现代码
2009/07/18 Javascript
js 实现css风格选择器(压缩后2KB)
2012/01/12 Javascript
获取元素距离浏览器周边的位置的方法getBoundingClientRect
2013/04/17 Javascript
如何通过javascript操作web控件的自定义属性
2013/11/25 Javascript
checkbox选中与未选中判断示例
2014/08/04 Javascript
简易的投票系统以及js刷票思路和方法
2015/04/07 Javascript
基于jQuery实现Tabs选项卡自定义插件
2016/11/21 Javascript
jQuery删除当前节点元素
2016/12/07 Javascript
基于JavaScript实现幸运抽奖页面
2020/07/05 Javascript
JS监听滚动和id自动定位滚动
2018/12/18 Javascript
vue添加class样式实例讲解
2019/02/12 Javascript
layer.alert自定义关闭回调事件的方法
2019/09/27 Javascript
Vue实现商品飞入购物车效果(电商项目)
2019/11/26 Javascript
vue.js 解决v-model让select默认选中不生效的问题
2020/07/28 Javascript
[05:04]DOTA2上海特级锦标赛主赛事第二日TOP10
2016/03/04 DOTA
python如何实现excel数据添加到mongodb
2015/07/30 Python
Python 3.7新功能之dataclass装饰器详解
2018/04/21 Python
python中yield的用法详解——最简单,最清晰的解释
2019/04/04 Python
Tensorflow tf.dynamic_partition矩阵拆分示例(Python3)
2020/02/07 Python
基于pygame实现童年掌机打砖块游戏
2020/02/25 Python
python文件编写好后如何实践
2020/07/07 Python
python PyAUtoGUI库实现自动化控制鼠标键盘
2020/09/09 Python
35款精致的 CSS3 和 HTML5 网页模板 推荐
2012/08/03 HTML / CSS
施华洛世奇日本官网:SWAROVSKI日本
2018/05/04 全球购物
女子锻炼服装和瑜伽服装:Splits59
2019/03/04 全球购物
中医药大学市场营销专业自荐信
2013/09/29 职场文书
个人近期表现材料
2014/02/11 职场文书
迟到检讨书300字
2014/02/14 职场文书
群众路线党员个人剖析材料
2014/10/08 职场文书
2014年班级工作总结范文
2014/12/23 职场文书
红与黑读书笔记
2015/06/29 职场文书
导游词之上饶龟峰
2019/10/25 职场文书
Java实现房屋出租系统详解
2021/10/05 Java/Android
如何通过简单的代码描述Angular父组件、子组件传值
2022/04/07 Javascript