基于 Web 实现 m3u8 视频播放的简单应用示例

Posted 飞仔FeiZai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于 Web 实现 m3u8 视频播放的简单应用示例相关的知识,希望对你有一定的参考价值。

基于 Web 实现 m3u8 视频播放的简单应用示例

基于 Web 实现 m3u8 视频播放的简单应用示例

实现思路

将视频(MP4 等)转换为 M3U8 视频的服务,可以按照以下步骤进行操作:

  1. 将视频(MP4 等)转换为 M3U8:在服务中,使用适当的工具(如 FFmpeg)将接收到的视频(MP4 等)转换为 M3U8 格式。这将生成一个包含视频流的 M3U8 文件以及相应的分段(TS)文件。

  2. 提供边下边播服务:将生成的 M3U8 文件和分段文件存储在适当的位置(如服务器上的文件夹或云存储服务中)。然后,可以通过将这些文件的 URL 提供给前端,使前端能够通过边下边播的方式逐段加载和播放视频。

  3. 前端实现 M3U8 播放器:在前端,可以使用现有的视频播放器库(如 video.js、plyr.js 等)或基于 HLS(HTTP Live Streaming)协议的播放器库(如 hls.js)来实现 M3U8 视频的播放器。这些库可以通过提供 M3U8 文件的 URL 来加载和播放视频。

一、将视频(MP4 等)转换为 M3U8 视频

使用 Python 实现将 MP4 视频转换为 M3U8 视频,按照以下步骤进行操作:

  1. 安装所需的库:首先,确保已安装所需的库。在 Python 中,可以使用 ffmpeg-python 库来与 FFmpeg 进行交互,以执行视频转换操作。可以使用以下命令安装该库:
pip install ffmpeg-python
  1. 导入库和设置转换函数:在 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.jsvideo.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 对象,并为其指定了 techOrdersources 选项。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";
        }

 

以上是关于基于 Web 实现 m3u8 视频播放的简单应用示例的主要内容,如果未能解决你的问题,请参考以下文章

React 基于antd+video.js实现m3u8格式视频播放及实时切换

FFmpeg基于HLS实现大视频分片下载播放[视频直播二]

FFmpeg基于HLS实现大视频分片下载播放[视频直播二]

原生小程序实现视频监控(m3u8格式)

关于H5播放Http Live Streaming m3u8格式视频

有哪位大神知道m3u8格式的视频用啥播放器能播放