这篇文章是使用Python的Web框架Django Rest Framework来提供视频相关的api接口,主要功能包括视频上传、视频转码、视频访问授权、删除视频文件、视频截图功能。
七牛云上的基本概念:
公开空间:可通过文件对象的 URL 直接访问。如果要使用七牛云存储的镜像存储功能,请设置空间的属性为公有。
私有空间:文件对象的访问则必须获得拥有者的授权才能访问。
资源:资源是七牛云存储服务中的逻辑存储单元。
AccessKey: 用于标识用户,用户将 AccessKey 放入访问请求,以便七牛云存储识别访问者的身份。
SecretKey: 是用于加密签名字符串和服务器端验证签名字符串的密钥。
如果将视频放在公开空间里,那么用户可以直接根据url下载视频,是不安全的,如果是付费视频,则必须放在私有空间里,这篇文章也是私有资源的处理。
首先需要有七牛云账号、创建空间,具体操作可参考:七牛云对象存储快速入门
接下来就是写代码。
1、七牛Python SDK安装:
pip install qiniu
或
easy_install qiniu
2、初始化:
在使用SDK 前,您需要一对有效的 AccessKey 和 SecretKey 签名授权。
可以通过如下步骤获得:
- 开通七牛开发者帐号
- 登录七牛开发者平台,查看 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如下:
前端调用步骤:
- 调用get_uptoken,获取上传授权token,拿到token后使用js根据七牛云上传接口上传视频;
- 上传成功后调用transcode切片成m3u8,返回m3u8文件资源名称和视频时长等信息;
- 用户点击播放时,调用ts_private_url获取访问权限(参数是步骤2返回的m3u8资源名称);
- 若需要视频截图(如封面图),可以调用screenshot接口;若需要删除存储在七牛云上的视频,可以调用delete_videos接口。
4、上线之后可以使用七牛云的融合 CDN,加速视频的加载。
相关参考:
七牛云Python SDK
七牛云音视频切片
私有m3u8