基于 Web 实现 m3u8 视频播放的简单应用示例
Posted 飞仔FeiZai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于 Web 实现 m3u8 视频播放的简单应用示例相关的知识,希望对你有一定的参考价值。
基于 Web 实现 m3u8 视频播放的简单应用示例
实现思路
将视频(MP4 等)转换为 M3U8 视频的服务,可以按照以下步骤进行操作:
-
将视频(MP4 等)转换为 M3U8:在服务中,使用适当的工具(如 FFmpeg)将接收到的视频(MP4 等)转换为 M3U8 格式。这将生成一个包含视频流的 M3U8 文件以及相应的分段(TS)文件。
-
提供边下边播服务:将生成的 M3U8 文件和分段文件存储在适当的位置(如服务器上的文件夹或云存储服务中)。然后,可以通过将这些文件的 URL 提供给前端,使前端能够通过边下边播的方式逐段加载和播放视频。
-
前端实现 M3U8 播放器:在前端,可以使用现有的视频播放器库(如 video.js、plyr.js 等)或基于 HLS(HTTP Live Streaming)协议的播放器库(如 hls.js)来实现 M3U8 视频的播放器。这些库可以通过提供 M3U8 文件的 URL 来加载和播放视频。
一、将视频(MP4 等)转换为 M3U8 视频
使用 Python 实现将 MP4 视频转换为 M3U8 视频,按照以下步骤进行操作:
- 安装所需的库:首先,确保已安装所需的库。在 Python 中,可以使用
ffmpeg-python
库来与 FFmpeg 进行交互,以执行视频转换操作。可以使用以下命令安装该库:
pip install ffmpeg-python
- 导入库和设置转换函数:在 Python 代码中,导入
ffmpeg
模块,并创建一个函数,用于将 MP4 转换为 M3U8。以下是一个示例代码:
import ffmpeg
def convert_mp4_to_m3u8(input_file, output_file):
"""
Converts an MP4 file to an M3U8 file using ffmpeg.
Args:
input_file (str): The path to the input MP4 file.
output_file (str): The path to the output M3U8 file.
Returns:
bool: True if the conversion was successful, False otherwise.
"""
try:
ffmpeg.input(input_file).output(output_file, format=\'hls\', hls_time=10, hls_segment_type=\'mpegts\').run()
return True
except ffmpeg.Error as e:
print(f"An error occurred during video conversion: e.stderr")
return False
在这个示例代码中,convert_mp4_to_m3u8
函数接受输入文件路径和输出文件路径作为参数。它使用 FFmpeg 将输入文件转换为 M3U8 格式,并将分段(TS)文件输出到指定的输出文件路径。
二、实现 HTTP 服务器,提供 M3U8 视频的访问
方法一、使用 Python 标准库中的 http.server
模块
这个模块提供了一个简单的 HTTP 服务器,可以处理 GET 和 HEAD 请求,并可以为客户端提供静态文件。
以下是一个简单的示例代码,可以启动一个 HTTP 服务器并为客户端提供视频等资源的访问:
import http.server
import socketserver
PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", PORT), Handler) as httpd:
print("serving at port", PORT)
httpd.serve_forever()
在这个示例中,创建了一个 http.server.SimpleHTTPRequestHandler
处理程序,它可以处理 GET 和 HEAD 请求,并可以为客户端提供静态文件。然后,使用 socketserver.TCPServer
创建一个 TCP 服务器,并将处理程序传递给它。最后,调用 serve_forever()
方法开始监听来自客户端的请求。
将视频等资源放在服务器的根目录下,例如 ./video.m3u8
,客户端可以通过浏览器访问 http://localhost:8000/video.m3u8
来获取该资源。客户端也可以使用其他 HTTP 客户端程序(例如 curl
或者 wget
)来访问资源。
不过需要注意的是,这种方式只适合提供小型的静态文件。如果要提供大型视频等资源,最好使用专门的服务器软件来处理,例如 Apache 或 Nginx。
方法二、使用 Flask 框架
Flask 框架可以提供一种更为灵活的方式来实现视频等静态资源的访问。下面是一个简单的示例代码:
from flask import Flask, send_from_directory
app = Flask(__name__)
@app.route(\'/<path:path>\')
def static_file(path):
return send_from_directory(\'.\', path)
if __name__ == \'__main__\':
app.run(port=8000)
在这个示例中,定义了一个名为 static_file
的路由,它可以处理所有的 HTTP GET 请求,并使用 send_from_directory
函数返回请求的文件。在这里,将请求的文件从当前目录中返回。如果要返回其他目录下的文件,可以将 send_from_directory
函数的第一个参数设置为目录的路径。
要访问视频等静态资源,可以将它们放在与 Flask 应用程序相同的目录中,并使用相对路径作为 URL。例如,如果视频文件名为 video.m3u8
,可以使用 http://localhost:8000/video.m3u8
访问该文件。
需要注意的是,这种方式也适用于小型的静态文件。如果要提供大型视频等资源,最好使用专门的服务器软件来处理,例如 Apache 或 Nginx。另外,这里的示例代码只提供了最简单的静态资源访问功能,如果需要更高级的功能(例如缓存控制、安全性等),可以使用 Flask 扩展或者在代码中自行实现。
三、Web 前端播放 M3U8 视频
M3U8 是一种基于 HTTP Live Streaming (HLS) 协议的视频流播放格式(在播放 M3U8 文件时需要将视频文件和 M3U8 文件都放在 HTTP 服务器上,并通过 HTTP 协议进行访问)。要在 Web 前端中实现 M3U8 播放器,可以使用一些开源的 JavaScript 库,例如 hls.js
和 video.js
。
hls.js
是一个基于 JavaScript 实现的 M3U8 播放器库。它可以自动检测浏览器是否支持 HLS,如果不支持则使用 Flash 播放器来进行播放。以下是一个使用 hls.js
的示例代码:
<!DOCTYPE html>
<html>
<head>
<title>hls.js player example</title>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>
<body>
<video id="video" controls></video>
<script>
var video = document.getElementById("video");
if (Hls.isSupported())
var hls = new Hls();
hls.loadSource("http://127.0.0.1:8000/path/to/video.m3u8");
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, function ()
// video.play();
);
else if (video.canPlayType("application/vnd.apple.mpegurl"))
video.src = "http://127.0.0.1:8000/path/to/video.m3u8";
video.addEventListener("loadedmetadata", function ()
// video.play();
);
</script>
</body>
</html>
在这个示例中,首先��页面中引入了 hls.js
库。然后,创建一个 HTML5 video
元素,并为它设置了 controls
属性,以便用户可以控制视频的播放。
接着,使用 Hls.isSupported()
方法检测浏览器是否支持 HLS。如果支持,则创建一个 Hls
对象,并使用 loadSource
方法加载 M3U8 文件。然后,使用 attachMedia
方法将 video
元素附加到 Hls
对象上,并在 MANIFEST_PARSED
事件触发时开始播放视频。
如果浏览器不支持 HLS,就检测是否支持 application/vnd.apple.mpegurl
格式。如果支持,则为 video
元素的 src
属性设置 M3U8 文件的路径,并在 loadedmetadata
事件触发时开始播放视频。
除了 hls.js
,还有一些其他的 JavaScript 库可以用来实现 M3U8 播放器,例如 video.js
。下面是一个使用 video.js
的示例代码:
<!DOCTYPE html>
<html>
<head>
<title>video.js player example</title>
<link href="https://vjs.zencdn.net/8.3.0/video-js.css" rel="stylesheet" />
<script src="https://vjs.zencdn.net/8.3.0/video.min.js"></script>
</head>
<body>
<video id="video" class="video-js vjs-default-skin" controls></video>
<script>
var video = videojs("video",
techOrder: ["html5", "flash"],
sources: [
src: "http://127.0.0.1:8000/path/to/video.m3u8",
type: "application/x-mpegURL",
,
],
);
// video.play();
</script>
</body>
</html>
在这个示例中,首先引入了 video.js
的 CSS 和 JavaScript 文件。然后,创建了一个 HTML5 video
元素,并为它设置了 class
属性,以便应用 video.js
的默认样式。
接着,使用 videojs
函数创建一个 video.js
对象,并为其指定了 techOrder
和 sources
选项。techOrder
选项指定了播放视频时使用的技术顺序,如果浏览器不支持 HLS,则会使用 Flash 播放器来进行播放。sources
选项指定了待播放的 M3U8 文件的路径和类型。
最后,调用 play
方法开始播放视频。
CefSharp的简单应用,制作自动学习视频软件(基于Chromium)
CefSharp在NuGet的简介是“The CefSharp Chromium-based browser component”,机翻的意思就是“基于Cefsharp Chromium的浏览器组件”
请注意本文不会有太多功能的详细介绍,只有实现相关需求的基本功能
请注意本次使用CefSharp版本为57.0.0,最新版本可能相关用法已经不适用
播放视频需安装相关Flash软件才能播放
本次编写要实现的主要功能是
1:播放视频,
(本次打开指定网址默认会播放视频)
2:自动跳转下一条视频,
(学习进度100%时跳转下一个网址)
3:自动点击验证
(执行JavaScript代码)
成品软件界面如下
一:添加相关引用,NuGet 搜索安装 CefSharp.WinForms,CefSharp.Common(本次使用版本为57.0.0)
二:项目属性中平台要进行设置
三:编写代码
具体实现方式是,有两个窗口,一个浏览学习列表页(获取内页学习页面链接),另一个浏览内页学习页面进行学习
CefSharp.WinForms.ChromiumWebBrowser browser = null;
CefSharp.WinForms.ChromiumWebBrowser browserChild = null;
public Form1() { InitializeComponent(); //必须进行初始化,否则出不来页面啦。 CefSharp.Cef.Initialize(); //实例化控件 即课程列表页查看和获取具体学习页面路径 browser = new CefSharp.WinForms.ChromiumWebBrowser("http://xxx.xxx.cn"); //设置停靠方式 browser.Dock = DockStyle.Fill; //加入到当前窗体中 this.tabControl1.TabPages[0].Controls.Add(browser); //绑定新窗口打开事件 browser.LifeSpanHandler = new NewWindowCreatedEventHandler(); //browser.LoadHandler = new NewLoadHandler(); //browser.FrameLoadEnd += Browser_FrameLoadEnd; //实例化子控件 即学习页面 browserChild = new CefSharp.WinForms.ChromiumWebBrowser("about:blank"); //设置停靠方式 browserChild.Dock = DockStyle.Fill; //加入到当前窗体中 this.tabControl1.TabPages[1].Controls.Add(browserChild); Control.CheckForIllegalCrossThreadCalls = false;//防止出现 线程间操作无效: }
/// <summary> /// 打开新窗口事件处理(在当前浏览器窗口打开) /// </summary> internal class NewWindowCreatedEventHandler : ILifeSpanHandler { public bool DoClose(IWebBrowser browserControl, IBrowser browser) { return false; } public void OnAfterCreated(IWebBrowser browserControl, IBrowser browser) { } public void OnBeforeClose(IWebBrowser browserControl, IBrowser browser) { } public bool OnBeforePopup(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser) { newBrowser = null; var chromiumWebBrowser = (ChromiumWebBrowser)browserControl; chromiumWebBrowser.Load(targetUrl); return true; //Return true to cancel the popup creation copyright by codebye.com. } }
执行JavaScript代码方法
string BrowserEvaluateScriptAsync(string scriptStr) { StringBuilder sb = new StringBuilder(); sb.AppendLine("function tempFunction() {"); sb.AppendLine(scriptStr); sb.AppendLine("}"); sb.AppendLine("tempFunction();"); string resultStr = ""; try { var task = browser.GetBrowser().GetFrame(browser.GetBrowser().GetFrameNames()[0]).EvaluateScriptAsync(sb.ToString()); task.ContinueWith(t => { if (!t.IsFaulted) { var response = t.Result; if (response.Success == true) { if (response.Result != null) { resultStr = response.Result.ToString(); } } } }, TaskScheduler.FromCurrentSynchronizationContext()); return resultStr; } catch (Exception ex) { return resultStr; } }
获取内页学习页面链接代码,实现方式是获取页面的html然后用正则表达式去匹配当前页的链接
//获取课程列表 private void GetDataList_Click(object sender, EventArgs e) { Log("获取课程列表"); if (browser != null) { try { StringBuilder sb = new StringBuilder(); sb.AppendLine("function tempFunction() {"); sb.AppendLine(" return document.body.innerHTML; "); sb.AppendLine("}"); sb.AppendLine("tempFunction();"); var task = browser.GetBrowser().GetFrame(browser.GetBrowser().GetFrameNames()[0]).EvaluateScriptAsync(sb.ToString()); task.ContinueWith(t => { if (!t.IsFaulted) { var response = t.Result; if (response.Success == true) { if (response.Result != null) { string resultStr = response.Result.ToString(); Regex r = new Regex("(/knowledge/document/[\\S]*.html)|(/knowledge/video/[\\S]*.html)|(/package/video/[\\S]*.html)|(/package/document/[\\S]*.html)|(/knowledge/scorm/[\\S]*.html)|(/package/scorm/[\\S]*.html)|(/package/ebook/[\\S]*.html)");//构造表达式package/scorm MatchCollection matches = r.Matches(resultStr); foreach (Match match in matches) { string word = match.Groups["word"].Value; int index = match.Index; richTextBox1.AppendText(match.Value.Replace(""", "")); richTextBox1.AppendText(" "); } SetConfig(LastHistroyDataList, richTextBox1.Text); Log("获取课程列表成功!(添加" + matches.Count.ToString() + "列数据)"); tabControl1.SelectedIndex = 2; } } } }, TaskScheduler.FromCurrentSynchronizationContext()); } catch (Exception ex) { Log("获取课程列表失败!(js执行失败)"); } } else { Log("获取课程列表失败!(浏览器获取失败)"); } }
接下来定时判断具体学习页面是否到达100%的进度,如果达到100%的进度,浏览下一个链接即可
//判断页面是否显示 “已经完成学习” string PanDuanWanCheng() { if (browserChild != null) { try { StringBuilder sb = new StringBuilder(); sb.AppendLine("function tempFunction() {"); sb.AppendLine("return document.getElementById(‘ScheduleText‘).innerText;"); sb.AppendLine("}"); sb.AppendLine("tempFunction();"); string resultStr = ""; var task = browserChild.GetBrowser().GetFrame(browserChild.GetBrowser().GetFrameNames()[0]).EvaluateScriptAsync(sb.ToString()); task.ContinueWith(t => { if (!t.IsFaulted) { var response = t.Result; if (response.Success == true) { if (response.Result != null) { resultStr = response.Result.ToString(); if (resultStr == "100%") { string nowLearnTitle = GetNowLearnTitle(); //Log("课程已完成!" + browserChild.Url.ToString() + "(" + nowLearnTitle + ")"); //完成操作 if (learnWithDataList) { BroserChildStarWithDataList(); } return "1"; } } } } return "0"; }, TaskScheduler.FromCurrentSynchronizationContext()); } catch (Exception ex) { } } return "0"; }