Django 中使用流响应处理视频的方法
时间:2018-07-20
这篇文章主要介绍了Django 中使用流响应处理视频的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
起步
利用 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
是一些大文件的下载等,利用它还能完成断点续传的功能。
视频流
使用视频流时可以从请求头部中获得起始字节数。
这字段似乎是浏览器自动提供的,因为html代码中,我只需要改下视频的 src
的从静态地址变成路由方式而已。对于响应体而言,也要提供响应体返回的块的一个范围:
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'bytess*=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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
- 数据库中间件 Sharding-JDBC 源码分析 —— SQL 解析(三)之查询SQL
- zephir-(11)流程控制语句
- phalcon-入门篇7(Model层基础使用)
- Sharding-JDBC 源码分析 —— SQL 解析(二)之SQL解析
- zephir-(1)开篇介绍
- phalcon-入门篇6(控制器)
- phalcon-入门篇5(请求与返回)
- phalcon-入门篇2(HelloWord与PhalconTools)
- 数据库中间件 Sharding-JDBC 源码分析 —— SQL 解析(一)之语法解析
- phalcon-入门篇4(log日志和session缓存)
- zephir-(5)类型
- zephir-(10)内置函数
- zephir-(9)类和对象2
- 深度学习中的动手实践:在CIFAR-10上进行图像分类
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- C语言入门系列之9.预处理
- Python爬虫常见异常及解决办法
- 理解nodejs中js和c++的通信原理
- 如何使用FFmpeg将互联网直播点播平台内直播视频流转化为HLS流?
- 记一次nodejs问题排查
- 使用Go语言编译互联网视频直播点播平台EasyDSS出现ld returned 1 exit status错误
- c/c++补完计划(四): 字节对齐和虚继承
- Python 不用selenium 带你高效爬取京东商品评论
- 《闲扯Redis六》Redis五种数据类型之Hash型
- rocketmq学习2
- Python全栈(八)Flask项目实战之1.项目搭建
- 一起来读开源项目的代码-Agar.io为例
- C语言入门系列之11.文件和文件操作
- 自己动手改造 Jetpack LiveData
- FastDFS基于Docker安装