好好学习,天天向上

博客园 首页 联系 订阅 管理

这篇文章是使用Python的Web框架Django Rest Framework来提供视频相关的api接口,主要功能包括视频上传、视频转码、视频访问授权、删除视频文件、视频截图功能。

七牛云上的基本概念:

公开空间:可通过文件对象的 URL 直接访问。如果要使用七牛云存储的镜像存储功能,请设置空间的属性为公有。
私有空间:文件对象的访问则必须获得拥有者的授权才能访问。

资源:资源是七牛云存储服务中的逻辑存储单元。

AccessKey: 用于标识用户,用户将 AccessKey 放入访问请求,以便七牛云存储识别访问者的身份。
SecretKey: 是用于加密签名字符串和服务器端验证签名字符串的密钥。

如果将视频放在公开空间里,那么用户可以直接根据url下载视频,是不安全的,如果是付费视频,则必须放在私有空间里,这篇文章也是私有资源的处理。

首先需要有七牛云账号、创建空间,具体操作可参考:七牛云对象存储快速入门

接下来就是写代码。

1、七牛Python SDK安装:

    pip install qiniu
    或
    easy_install qiniu

2、初始化:

在使用SDK 前,您需要一对有效的 AccessKey 和 SecretKey 签名授权。

可以通过如下步骤获得:

  1. 开通七牛开发者帐号
  2. 登录七牛开发者平台,查看 Access Key 和 Secret Key

获取Access Key 和 Secret Key 后,调用如下两行代码进行初始化对接:

    from qiniu import Auth
    q = Auth(access_key, secret_key)

3、api编写,代码是契合本人所做的项目的,您不能够直接使用、api是大致相同的:

  1 from qiniu import Auth, PersistentFop, urlsafe_base64_encode, BucketManager, build_batch_delete
  2 from django.conf import settings
  3 from rest_framework.decorators import list_route, detail_route
  4 from tokenauth.decorators import is_login, admin_login
  5 
  6 from course.models import Chapter
  7 from course.serializers import ChapterSerializer
  8 from course.errors import INVALID_USER, INVALID_PARAMS, VIDEO_NOT_EXIST, OPERATION_NOT_ALLOWED, \
  9     COURSE_ALREADY_ONLINE, COURSE_ALREADY_OFFLINE, CHAPTER_NOT_EXIST
 10 from course.exception_handler import CustomError
 11 
 12 access_key = '你自己账号的access_key'
 13 secret_key = '你自己账号的secret_key'
 14 domain = '七牛云对象存储内容管理生成的外链默认域名'
 15 bucket_name = '要上传的空间名称'
 16 # 视频转码会用到私有队列,在七牛云资源主页多媒体处理点击立即添加
 17 pipeline = '私有队列名称'
 18 
 19 class ChapterViewSet(ModelViewSet):
 20     """
 21         章节 ViewSet
 22     """
 23     queryset = Chapter.objects.all().order_by('created_time')
 24     serializer_class = ChapterSerializer
 25 
 26     @list_route(methods=['get'])
 27     @admin_login
 28     def get_uptoken(self, request):
 29         """
 30             获取上传token,有效期一个小时,前台拿到uptoken就可以上传视频文件
 31         :param request:
 32         :return:
 33         """
 34         q = Auth(access_key, secret_key)
 35         token = q.upload_token(bucket_name)
 36         return Response({'uptoken': token})
 37 
 38     @list_route(methods=['post'])
 39     @admin_login
 40     def transcode(self, request):
 41         """
 42             七牛云视频转码切片m3u8,返回转码后的key。将视频流切割成可由HTTP下载的一个个小的音视频流,并生成一个M3U8播放列表,客户端只需要获取资源的M3U8播放列表即可播放音视频。
 43             并且返回该视频的元信息url,前台可通过此url获取视频的时长等信息
 44         :param request:
 45         :param key:
 46         :return:
 47         """
 48         key = request.data.get('key', None)
 49         if key is None:
 50             raise CustomError(INVALID_PARAMS) 
 51         q = Auth(access_key, secret_key)
 52         fops = 'avthumb/m3u8'
 53         hls_name = 'hls' + UUIDTools.uuid1_hex()
 54 
 55         saveas_key = urlsafe_base64_encode(bucket_name + ':' + hls_name)
 56         fops = fops + '|saveas/' + saveas_key
 57         # 视频转码完成回调函数
 58         notify_url = settings.QINIU_CALLBACK_URL + 'api/v1.0/course/chapters/complete_transcode/'
 59         pfop = PersistentFop(q, bucket_name, pipeline, notify_url)
 60         ops = []
 61         ops.append(fops)
 62         ret, info = pfop.execute(key, ops, 1)
 63         if ret is None:
 64             raise CustomError(VIDEO_NOT_EXIST)
 65 
 66         # 获取视频元信息链接
 67         base_url = 'http://%s/%s?avinfo' % (domain, key)
 68         avinfo_url = q.private_download_url(base_url)
 69 
 70         return Response({'success': True, 'hls_name': hls_name, 'avinfo_url': avinfo_url})
 71 
 72     @list_route(methods=['post'])
 73     def complete_transcode(self, request):
 74         """
 75             七牛云视频转码完成回调
 76         """
 77         origin_key = request.data.get('inputKey', None)
 78         code = request.data.get('code', -1)
 79         if code == 0:
 80             TranscodeRecode.objects.create(created_by=0, updated_by=0, key=origin_key)
 81             chapter = Chapter.objects.filter(origin_key=origin_key).values().first()
 82             if chapter is not None:
 83                 Chapter.objects.filter(pk=chapter.get('id')).update(is_transcoded=True)
 84 
 85         return Response({'success': True})
 86 
 87     @list_route(methods=['get'])
 88     def ts_private_url(self, request):
 89         """
 90             视频播放授权,将m3u8文件中的ts资源的url批量改写成私有url,以临时获取访问权限,有效期一个小时。
 91         :param request:
 92         :param key: m3u8文件的key
 93         :return:
 94         """
 95         key = request.GET.get('key', None)
 96         if not key:
 97             raise CustomError(INVALID_PARAMS)
 98         q = Auth(access_key, secret_key)
 99         base_url = 'https://%s/%s?pm3u8/0/expires/315360000' % (domain, key)
100         private_url = q.private_download_url(base_url, expires=3600)
101         return Response({'private_url': private_url})
102 
103     @list_route(methods=['post'])
104     @admin_login
105     def delete_videos(self, request):
106         """
107             删除七牛云上的视频文件
108         :param request:
109         :param keys: 逗号隔开的key
110         :return:
111         """
112         keys = request.data.get('keys', None)
113         if not keys:
114             raise CustomError(INVALID_PARAMS)
115         keys = keys.split(',')
116         q = Auth(access_key, secret_key)
117         bucket = BucketManager(q)
118         ops = build_batch_delete(bucket_name, keys)
119         ret, info = bucket.batch(ops)
120         qiniu_response = info.text_body.replace('"', '\'')
121 
122         return Response({'success': True, 'qiniu_response': qiniu_response})
123 
124     @list_route(methods=['post'])
125     @admin_login
126     def screenshot(self, request):
127         """
128             七牛云视频截图
129         :param request:
130         :param key:
131         :param offset:
132         :return:
133         """
134         key = request.data.get('key', None)
135         offset = int(request.data.get('offset', -1))
136         if key is None or offset < 0:
137             raise CustomError(INVALID_PARAMS)
138 
139         q = Auth(access_key, secret_key)
140         fops = 'vframe/jpg/offset/%d/w/480/h/360' % offset
141         jpg_name = 'jpg' + UUIDTools.uuid1_hex()
142 
143         saveas_key = urlsafe_base64_encode(bucket_name + ':' + jpg_name)
144         fops = fops + '|saveas/' + saveas_key
145 
156         pfop = PersistentFop(q, bucket_name, pipeline)
147         ops = []
148         ops.append(fops)
149         ret, info = pfop.execute(key, ops, 1)
150         if ret is None:
151             raise CustomError(VIDEO_NOT_EXIST)
152         base_url = 'https://%s/%s' % (domain, jpg_name)
154         # 可以设置token过期时间
154         jpg_url = q.private_download_url(base_url, expires=315360000)
155         print(jpg_url)
156 
157         return Response({'success': True, "jpg_url": jpg_url})    

生成的api如下:

前端调用步骤:

  1. 调用get_uptoken,获取上传授权token,拿到token后使用js根据七牛云上传接口上传视频;
  2. 上传成功后调用transcode切片成m3u8,返回m3u8文件资源名称和视频时长等信息;
  3. 用户点击播放时,调用ts_private_url获取访问权限(参数是步骤2返回的m3u8资源名称);
  4. 若需要视频截图(如封面图),可以调用screenshot接口;若需要删除存储在七牛云上的视频,可以调用delete_videos接口。

 4、上线之后可以使用七牛云的融合 CDN,加速视频的加载。

 

相关参考:

七牛云Python SDK

七牛云音视频切片

私有m3u8

posted on 2018-03-04 16:59  Fighting蔚  阅读(1316)  评论(0编辑  收藏  举报