绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
Django实现媒体播放API
2019-12-11 10:43:21

MedusaSorcerer的博客


需求描述

对于一些应用产品, 有播放视频的需求时, 我们往往优先考虑的是通过 Nginx 代理静态资源实现
仅仅需要你在 nginx 配置文件中配置即可达到实现需求
而这么做的劣势在于加载庞大数据的时候, 增加了内存负载
追求完美的我们决不允许这样的事情发生, 所以我们用 API 的方式做流式响应。

依赖环境

Python: 3.7.2
Django: 2.1.7
复制代码

实现源码

#!/usr/bin/python3
# _*_ Coding: UTF-8 _*_
import mime*
import os
import re
from wsgiref.util import FileWrapper

from django.http import StreamingHttpResponse
from rest_framework.views import APIView


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


class StreamVideoPlayViewSet(APIView):
    def get(self, request, *args, **kwargs):
        """ 将视频文件以 流媒体 的方式响应 """
        path = r'这是你动态构建的媒体文件路径'
        range_re = re.compile(r'bytes\s*=\s*(\d+)\s*-\s*(\d*)', re.I)
        range_match = range_re.match(request.META.get('HTTP_RANGE', '').strip())
        size, (content_type, encoding) = os.path.getsize(path), mime*.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
            response = StreamingHttpResponse(file_iterator(path, offset=first_byte, length=length), status=206, content_type=content_type)
            response['Content-Length'], response['Content-Range'] = str(length), 'bytes %s-%s/%s' % (first_byte, last_byte, size)
        else:
            # 不是以视频流方式的获取时,以生成器方式返回整个文件,节省内存
            response = StreamingHttpResponse(FileWrapper(open(path, 'rb')), content_type=content_type)
            response['Content-Length'] = str(size)
        response['Accept-Ranges'] = 'bytes'
        return response

复制代码
分享好友

分享这个小栈给你的朋友们,一起进步吧。

MedusaSorcerer
创建时间:2020-06-29 16:36:50
学无止境, 学无止尽。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • zuike2000
    栈主
戳我,来吐槽~