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的Scrapy爬虫框架使用代理进行采集的方法
Feb 18 Python
简单讲解Python中的字符串与字符串的输入输出
Mar 13 Python
Python 自动刷博客浏览量实例代码
Jun 14 Python
pytorch构建网络模型的4种方法
Apr 13 Python
详解Django中间件执行顺序
Jul 16 Python
Python3匿名函数用法示例
Jul 25 Python
详解Python Matplotlib解决绘图X轴值不按数组排序问题
Aug 05 Python
Python测试模块doctest使用解析
Aug 10 Python
Spring实战之使用util:命名空间简化配置操作示例
Dec 09 Python
Python HTTP下载文件并显示下载进度条功能的实现
Apr 02 Python
python 用Matplotlib作图中有多个Y轴
Nov 28 Python
Python字符串对齐方法使用(ljust()、rjust()和center())
Apr 26 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程序之die调试法 快速解决错误
2009/09/17 PHP
PHP设计模式之策略模式原理与用法实例分析
2019/04/04 PHP
ThinkPHP 5 AJAX跨域请求头设置实现过程解析
2020/10/28 PHP
HR vs ForZe BO3 第二场 2.13
2021/03/10 DOTA
jquery 字符串切割函数substring的用法说明
2014/02/11 Javascript
jQuery写fadeTo示例代码
2014/02/21 Javascript
轻量级jQuery插件slideBox实现带底栏轮播(焦点图)代码
2016/03/28 Javascript
window.onload绑定多个事件的两种解决方案
2016/05/15 Javascript
AngularJS 依赖注入详解和简单实例
2016/07/28 Javascript
Vuex简单入门
2017/04/19 Javascript
原生js简单实现放大镜特效
2017/05/16 Javascript
一次围绕setTimeout的前端面试经验分享
2017/06/15 Javascript
Express + Node.js实现登录拦截器的实例代码
2017/07/01 Javascript
使用jQuery实现页面定时弹出广告效果
2017/08/24 jQuery
Angular4学习笔记之根模块与Ng模块
2017/09/09 Javascript
JavaScript正则表达式和级联效果
2017/09/14 Javascript
vue通过点击事件读取音频文件的方法
2018/05/30 Javascript
使用VueCli3+TypeScript+Vuex一步步构建todoList的方法
2019/07/25 Javascript
Vue + Element UI图片上传控件使用详解
2019/08/20 Javascript
Vue插件之滑动验证码
2019/09/21 Javascript
基于JavaScript实现大文件上传后端代码实例
2020/08/18 Javascript
js绘制一条直线并旋转45度
2020/08/21 Javascript
区分vue-router的hash和history模式
2020/10/03 Javascript
uni-app使用countdown插件实现倒计时
2020/11/01 Javascript
Python多进程机制实例详解
2015/07/02 Python
详解Python发送邮件实例
2016/01/10 Python
Python的包管理器pip更换软件源的方法详解
2016/06/20 Python
python实现浪漫的烟花秀
2019/01/30 Python
Python mutiprocessing多线程池pool操作示例
2019/01/30 Python
详解python3安装pillow后报错没有pillow模块以及没有PIL模块问题解决
2019/04/17 Python
浅谈对python中if、elif、else的误解
2020/08/20 Python
英国浴室洗脸盆购物网站:Click Basin
2018/06/08 全球购物
优乐美广告词
2014/03/14 职场文书
2014法院干警廉洁警示教育思想汇报
2014/09/13 职场文书
董事会决议范本
2015/07/01 职场文书
ORACLE数据库对long类型字段进行模糊匹配的解决思路
2021/04/07 Oracle