如图,先看看效果
实现方式
1. 通过api获取视频相关m3u8地址,并进行分析(web版可通过调试模式查看)
结果如下
{
"domain_id": "bj29",
"drive_id": "650296441",
"file_id": "63857a5ce3abce4520f84562b13025174c070455",
"video_preview_play_info": {
"category": "live_transcoding",
"meta": {
"duration": 1948.565,
"width": 1920,
"height": 804,
"live_transcoding_meta": {
"ts_segment": 10,
"ts_total_count": 195,
"ts_pre_count": 3
}
},
"live_transcoding_task_list": [{
"template_id": "SD",
"template_name": "pdsSD",
"template_width": 960,
"template_height": 540,
"status": "finished",
"stage": "stage_all",
"url": "https://ccp-bj29-video-preview.oss-enet.aliyuncs.com/lt/8E5DB0912CE1598D006840896CA15A958DAF92B1_272593777__sha1_bj29/SD/media.m3u8?di=bj29&dr=650296441&f=63857a5ce3abce4520f84562b13025174c070455&security-token=CAIS%2BgF1q6Ft5B2yfSjIr5bvMt%2FTg5xZg7SpW0XIszIMaMlHuPTKuDz2IHFPeHJrBeAYt%2FoxmW1X5vwSlq5rR4QAXlDfNQDEHS%2FzqVHPWZHInuDox55m4cTXNAr%2BIhr%2F29CoEIedZdjBe%2FCrRknZnytou9XTfimjWFrXWv%2Fgy%2BQQDLItUxK%2FcCBNCfpPOwJms7V6D3bKMuu3OROY6Qi5TmgQ41Uh1jgjtPzkkpfFtkGF1GeXkLFF%2B97DRbG%2FdNRpMZtFVNO44fd7bKKp0lQLukMWr%2Fwq3PIdp2ma447NWQlLnzyCMvvJ9OVDFyN0aKEnH7J%2Bq%2FzxhTPrMnpkSlacGoABbS5XKPjPcw392n9aHLm5OsD0KUn%2Bu79doqjgQ%2B1kAmRACx4%2BIxJ0fPW4a%2Fso83ckeFioW7U%2Fg%2B9PzOSsbGXjM700r1nvfDenlXX%2B2GPOXjhd8S%2BMYi0GlJq5mZJAYNCh%2BELs8D5H45hN6DkC6aSP%2FLBmyoGipqJ9gwyK%2BxXZki8%3D&u=d636c4f1ca374695af84e6c6ea118436&x-oss-access-key-id=STS.NUZyegnCx4vBYcyW2YdFkW1aZ&x-oss-expires=1669723761&x-oss-process=hls%2Fsign&x-oss-signature=UXkAh73fYqPHxryhD5M9ZWaOnpkxSpNrFjAeWOEcVDw%3D&x-oss-signature-version=OSS2"
}, {
"template_id": "HD",
"template_name": "pdsHD",
"template_width": 1280,
"template_height": 720,
"status": "finished",
"stage": "stage_all",
"url": "https://ccp-bj29-video-preview.oss-enet.aliyuncs.com/lt/8E5DB0912CE1598D006840896CA15A958DAF92B1_272593777__sha1_bj29/HD/media.m3u8?di=bj29&dr=650296441&f=63857a5ce3abce4520f84562b13025174c070455&security-token=CAIS%2BgF1q6Ft5B2yfSjIr5bvMt%2FTg5xZg7SpW0XIszIMaMlHuPTKuDz2IHFPeHJrBeAYt%2FoxmW1X5vwSlq5rR4QAXlDfNQDEHS%2FzqVHPWZHInuDox55m4cTXNAr%2BIhr%2F29CoEIedZdjBe%2FCrRknZnytou9XTfimjWFrXWv%2Fgy%2BQQDLItUxK%2FcCBNCfpPOwJms7V6D3bKMuu3OROY6Qi5TmgQ41Uh1jgjtPzkkpfFtkGF1GeXkLFF%2B97DRbG%2FdNRpMZtFVNO44fd7bKKp0lQLukMWr%2Fwq3PIdp2ma447NWQlLnzyCMvvJ9OVDFyN0aKEnH7J%2Bq%2FzxhTPrMnpkSlacGoABbS5XKPjPcw392n9aHLm5OsD0KUn%2Bu79doqjgQ%2B1kAmRACx4%2BIxJ0fPW4a%2Fso83ckeFioW7U%2Fg%2B9PzOSsbGXjM700r1nvfDenlXX%2B2GPOXjhd8S%2BMYi0GlJq5mZJAYNCh%2BELs8D5H45hN6DkC6aSP%2FLBmyoGipqJ9gwyK%2BxXZki8%3D&u=d636c4f1ca374695af84e6c6ea118436&x-oss-access-key-id=STS.NUZyegnCx4vBYcyW2YdFkW1aZ&x-oss-expires=1669723761&x-oss-process=hls%2Fsign&x-oss-signature=xOZom4mrmiGuALYAIMH%2Bo4ONoG%2FgaXGzFMqgx74EgoE%3D&x-oss-signature-version=OSS2"
}, {
"template_id": "FHD",
"template_name": "pdsFHD",
"template_width": 1920,
"template_height": 1080,
"status": "finished",
"stage": "stage_all",
"url": "https://ccp-bj29-video-preview.oss-enet.aliyuncs.com/lt/8E5DB0912CE1598D006840896CA15A958DAF92B1_272593777__sha1_bj29/FHD/media.m3u8?di=bj29&dr=650296441&f=63857a5ce3abce4520f84562b13025174c070455&security-token=CAIS%2BgF1q6Ft5B2yfSjIr5bvMt%2FTg5xZg7SpW0XIszIMaMlHuPTKuDz2IHFPeHJrBeAYt%2FoxmW1X5vwSlq5rR4QAXlDfNQDEHS%2FzqVHPWZHInuDox55m4cTXNAr%2BIhr%2F29CoEIedZdjBe%2FCrRknZnytou9XTfimjWFrXWv%2Fgy%2BQQDLItUxK%2FcCBNCfpPOwJms7V6D3bKMuu3OROY6Qi5TmgQ41Uh1jgjtPzkkpfFtkGF1GeXkLFF%2B97DRbG%2FdNRpMZtFVNO44fd7bKKp0lQLukMWr%2Fwq3PIdp2ma447NWQlLnzyCMvvJ9OVDFyN0aKEnH7J%2Bq%2FzxhTPrMnpkSlacGoABbS5XKPjPcw392n9aHLm5OsD0KUn%2Bu79doqjgQ%2B1kAmRACx4%2BIxJ0fPW4a%2Fso83ckeFioW7U%2Fg%2B9PzOSsbGXjM700r1nvfDenlXX%2B2GPOXjhd8S%2BMYi0GlJq5mZJAYNCh%2BELs8D5H45hN6DkC6aSP%2FLBmyoGipqJ9gwyK%2BxXZki8%3D&u=d636c4f1ca374695af84e6c6ea118436&x-oss-access-key-id=STS.NUZyegnCx4vBYcyW2YdFkW1aZ&x-oss-expires=1669723761&x-oss-process=hls%2Fsign&x-oss-signature=K5t%2Fe3zHSTVmsJNxUoVi1giCTC4sSTqM6mF5rDyYuM4%3D&x-oss-signature-version=OSS2",
"keep_original_resolution": true
}]
}
}
可以看到,共有三种分辨率可选择,但是阿里云盘并没有提供 分辨率列表的m3u8文件,因此,需要我们自己实现该文件
2.通过Python读取不同分辨率下载连接,并拼接成相应的文件
def quoted(string):
return '"%s"' % string
class StreamInfo(object):
bandwidth = None
program_id = None
resolution = None
codecs = None
name = None
def __init__(self, **kwargs):
self.bandwidth = kwargs.get("bandwidth")
self.program_id = kwargs.get("program_id")
self.resolution = kwargs.get("resolution")
self.codecs = kwargs.get("codecs")
self.name = kwargs.get("name")
def __str__(self):
stream_inf = []
if self.program_id is not None:
stream_inf.append('PROGRAM-ID=%d' % self.program_id)
if self.bandwidth is not None:
stream_inf.append('BANDWIDTH=%d' % self.bandwidth)
if self.resolution is not None:
stream_inf.append('RESOLUTION=' + self.resolution)
if self.codecs is not None:
stream_inf.append('CODECS=' + quoted(self.codecs))
if self.name is not None:
stream_inf.append('NAME=' + self.name)
return ",".join(stream_inf)
def format_m3u8_data(preview_play_info: List[LiveTranscodingTask]):
start_str = '#EXTM3U'
for preview in preview_play_info:
if preview.status == 'finished':
if preview.template_id == 'SD':
stream_inf = StreamInfo(bandwidth=836280, program_id=1, codecs="mp4a.40.2,avc1.64001f",
name=preview.template_name,
resolution=f"{preview.template_width}x{preview.template_height}")
elif preview.template_id == 'HD':
stream_inf = StreamInfo(bandwidth=2149280, program_id=1, codecs="mp4a.40.2,avc1.64001f",
name=preview.template_name,
resolution=f"{preview.template_width}x{preview.template_height}")
elif preview.template_id == 'FHD':
stream_inf = StreamInfo(bandwidth=6221600, program_id=1, codecs="mp4a.40.2,avc1.640028",
name=preview.template_name,
resolution=f"{preview.template_width}x{preview.template_height}")
else:
stream_inf = StreamInfo(bandwidth=460560, program_id=1, codecs="mp4a.40.5,avc1.420016",
name=preview.template_name,
resolution=f"{preview.template_width}x{preview.template_height}")
start_str += '\n#EXT-X-STREAM-INF:' + str(stream_inf) + '\n' + preview.url
return start_str
def get_video_m3u8(file_obj: FileInfo, template_id='FHD|HD|SD|LD'):
drive_obj = AliyunDrive.objects.filter(active=True, enable=True, access_token__isnull=False,
pk=file_obj.aliyun_drive_id.pk).first()
if drive_obj:
ali_obj: Aligo = get_aliyun_drive(drive_obj)
result = ali_obj.get_video_preview_play_info(file_id=file_obj.file_id, drive_id=file_obj.drive_id,
template_id=template_id)
return format_m3u8_data(result.video_preview_play_info.live_transcoding_task_list[::-1])
view实现
from io import BytesIO
from wsgiref.util import FileWrapper
from django.http import FileResponse
from django.views import View
class M3U8View(View):
def get(self, request, file_id):
token = request.GET.get('token')
if token and file_id and verify_token(token, file_id, success_once=False):
instance = FileInfo.objects.filter(file_id=file_id, category='video').first()
if instance:
m3u8_data = get_video_m3u8(instance)
buffer = BytesIO(m3u8_data.encode('utf-8'))
m3u8_file = FileWrapper(buffer)
response = FileResponse(m3u8_file)
response['Content-Type'] = "audio/mpegurl"
return response
return ApiResponse(msg='error')
然后通过http接口,请求内容如下
3.前端通过vue实现,使用的是 vue3-video-play 插件
插件github: GitHub - xdlumia/vue3-video-play: 适用于 Vue3 的 hls.js 播放器组件,配置丰富,界面还算好看
定义视屏页面
代码已经开源,全部代码参考 GitHub - nineaiyu/xshare: 基于阿里云盘的文件分享平台