关于M3U8视频播放的处理(Asp.Net MVC+video.js)

先说说什么是M3U8

M3U8 是 Unicode 版本的 M3U,用 UTF-8 编码。"M3U" 和 "M3U8" 文件都是苹果公司使用的 HTTP Live Streaming(HLS) 协议格式的基础,这种协议格式可以在 iPhone 和 Macbook 等设备播放。

HLS 的工作原理是把整个流分成一个个小的基于 HTTP 的文件来下载,每次只下载一些。当媒体流正在播放时,客户端可以选择从许多不同的备用源中以不同的速率下载同样的资源,允许流媒体会话适应不同的数据速率。在开始一个流媒体会话时,客户端会下载一个包含元数据的 extended M3U (m3u8) playlist文件,用于寻找可用的媒体流。
HLS 只请求基本的 HTTP 报文,与实时传输协议(RTP)不同,HLS 可以穿过任何允许 HTTP 数据通过的防火墙或者代理服务器。它也很容易使用内容分发网络来传输媒体流。

详细的就不多说了 上原文链接
作者:Whyn
链接:传送门
来源:简书
 

本次 前端用到的就是 大家都熟知的 Video.js  

后端 采用Asp.Net MVC 框架

视频转码工具 FFmpeg

关于FFmpeg 大家自行百度 这里部在详细介绍

好了 说了这么废话 上才艺

前端 我们需要定义一个容器 div  通过video.js 动态生成播放器

在生成前,我们需要定义video的配置项,sources 代表播放文件 src为文件路径 type为文件类型

 上传文件就掠过了

    <div>
        <input type="text" id="filename" />
        <input type="file" name="File" id="FileS" />
        <button type="submit" id="updatefile">上传</button>

    </div>

    <div>video.js播放器</div>
    <video id="video" class="video-js" style="float:left">
    </video>

<script type="text/javascript">
  ///video.js 播放器配置项
    var options = {
        width: 800,
        height: 800,
        autoplay: true,
        controls: true,
        loop: false,
        preload: 'auto',
        sourceOrder: true,
        sources: [{
            src: "../../File/index.m3u8",
            type: 'application/x-mpegURL'
        }],
        bigPlayButton: true,
        textTrackDisplay: false,
        posterImage: false,
        errorDisplay: false,
        playbackRates: [0.5, 1, 1.5, 2, 3]
    }
    ///video.js 播放器初始化
    var videojsplayer = videojs('video', options);

$("#updatefile").click(function () {
        var files = $("#FileS").prop("files")[0];
        //声明FormData对象
        var formData = new FormData();
        //向FormData对象添加文件
        formData.append("file", files);
        formData.append("Name", $("#filename").val());
        $.ajax({
            type: "POST",
            url: "/Home/UploadingVideo/",
            async: true,///开启异步
            contentType: false,
            processData: false,          
            data: formData,
           
            success: function (data) {
                debugger

                if (data.src == "上传失败!") { alert(data.src); }
                else if (data.src == "没有找到该文件!") { alert(data.src); }
                else {
                    alert(data.Type);
                    window.location.reload();///用于刷新页面
                }
            },
            error: function (e) {
                console.log(e)
            }
        });
    })
</script>

后台我们接受传递过来的文件 进行保存和转码 HomeController代码

 public ActionResult UploadingVideo(HttpPostedFileBase file, string Name)
        {
            string src = "";
            string filePath = string.Empty;
            string guid = "";
            int type = -1;
            try
            {
                FFmpegHelper FF = new FFmpegHelper();
                //判断文件是否为空
                if (file != null)
                {
                    //获取文件类型
                    string fileExtension = System.IO.Path.GetExtension(file.FileName);
                    //自定义文件名(时间+唯一标识符+后缀)
                    guid = Guid.NewGuid().ToString();
                    string fileName = guid + fileExtension;
                    //判断是否存在需要的目录,不存在则创建 
                    if (!Directory.Exists(Server.MapPath("~/File/")))
                    { Directory.CreateDirectory(Server.MapPath("~/File/")); }

                    //若扩展名不为空则判断文件是否是指定视频类型
                    if (fileExtension != null)
                    {
                        VidoInfo mode = new VidoInfo();
                        mode.GUID = guid;
                        mode.Name = Name;
                        mode.Time = DateTime.Now;

                        if ("(.mp4)|(.avi)|(.flv)|(.rmvb)|(.wmv)|(.mov)".Contains(fileExtension))
                        {
                            mode.FileName = guid + ".m3u8";
                            //文件信息保存数据库
                            DB.VidoInfo.Add(mode);
                            DB.SaveChanges();

                            //判断是否存在需要的目录,不存在则创建 
                            if (!Directory.Exists(Server.MapPath("~/File/Video/")))
                            { Directory.CreateDirectory(Server.MapPath("~/File/Video/")); }

                            //拼接保存文件的详细路径
                            filePath = Server.MapPath("~/File/Video/") + fileName;

                            //保存文件
                            file.SaveAs(filePath);
                            //FF.VideoToTs(filePath, Server.MapPath("~/File/M3U8/") + guid+".ts");
                            //FF.TsToM3u8(filePath, Server.MapPath("~/File/M3U8/") + guid + ".m3u8", 25);
                            Thread thread2 = new Thread(new ThreadStart(delegate () { FF.TsToM3u8(filePath, Server.MapPath("~/File/M3U8/") + guid + ".m3u8", 25); }));
                            thread2.Start();

                            //拼接返回的Img标签
                            src = "/File/Video/" + fileName;
                            type = 1;
                        }
                        else if ("(.doc)|(.docx)".Contains(fileExtension))
                        {
                            mode.FileName = fileName;
                            //文件信息保存数据库
                            DB.VidoInfo.Add(mode);
                            DB.SaveChanges();

                            //判断是否存在需要的目录,不存在则创建 
                            if (!Directory.Exists(Server.MapPath("~/File/Office/")))
                            { Directory.CreateDirectory(Server.MapPath("~/File/Office/")); }

                            //拼接保存文件的详细路径
                            filePath = Server.MapPath("~/File/Office/") + fileName;
                            //保存文件
                            file.SaveAs(filePath);
                            //拼接返回的Img标签
                            src = "/File/Office/" + fileName;
                            type = 2;
                        }
                        else if ("(.xls)|(.xlsx)".Contains(fileExtension))
                        {
                            mode.FileName = fileName;
                            //文件信息保存数据库
                            DB.VidoInfo.Add(mode);
                            DB.SaveChanges();

                            //判断是否存在需要的目录,不存在则创建 
                            if (!Directory.Exists(Server.MapPath("~/File/Office/")))
                            { Directory.CreateDirectory(Server.MapPath("~/File/Office/")); }

                            //拼接保存文件的详细路径
                            filePath = Server.MapPath("~/File/Office/") + fileName;
                            //保存文件
                            file.SaveAs(filePath);
                            //拼接返回的Img标签
                            src = "/File/Office/" + fileName;
                            type = 3;
                        }
                        else if ("(.ppt)".Contains(fileExtension))
                        {
                            mode.FileName = fileName;
                            //文件信息保存数据库
                            DB.VidoInfo.Add(mode);
                            DB.SaveChanges();

                            //判断是否存在需要的目录,不存在则创建 
                            if (!Directory.Exists(Server.MapPath("~/File/Office/")))
                            { Directory.CreateDirectory(Server.MapPath("~/File/Office/")); }

                            //拼接保存文件的详细路径
                            filePath = Server.MapPath("~/File/Office/") + fileName;
                            //保存文件
                            file.SaveAs(filePath);
                            //拼接返回的Img标签
                            src = "/File/Office/" + fileName;
                            type = 4;
                        }
                        else if ("(.pdf)".Contains(fileExtension))
                        {
                            mode.FileName = fileName;
                            //文件信息保存数据库
                            DB.VidoInfo.Add(mode);
                            DB.SaveChanges();

                            //判断是否存在需要的目录,不存在则创建 
                            if (!Directory.Exists(Server.MapPath("~/File/Office/")))
                            { Directory.CreateDirectory(Server.MapPath("~/File/Office/")); }

                            //拼接保存文件的详细路径
                            filePath = Server.MapPath("~/File/Office/") + fileName;
                            //保存文件
                            file.SaveAs(filePath);
                            //拼接返回的Img标签
                            src = "/File/Office/" + fileName;
                            type = 5;
                        }
                    }
                    else
                    { src = "上传失败!"; }
                }
                else
                { src = "没有找到该文件!"; }
            }
            catch (Exception ex)
            {

                src = ex.Message;
            }
           
            return Json(new { src = src,Type = type }, JsonRequestBehavior.AllowGet);
        }

FFmpegHelper 压轴出场!

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;

namespace WebVideo
{
    public  class FFmpegHelper
    {
        //安装的ffmpeg的路径 写在配置文件的 你也可以直接写你的路径 D:\ffmpeg\bin\ffmpeg.exe
        //static string FFmpegPath = System.Configuration.ConfigurationManager.AppSettings["ffmepg"];



        /// <summary>
        /// 将ts文件转换为mu3u8文件
        /// </summary>
        /// <param name="tsUrl"></param>
        /// <param name="m3u8Url">这个路径不要带扩展名</param>
        /// <param name="videoLength">视频切片时长,默认5秒</param>
        public  void TsToM3u8(string tsUrl, string m3u8Url, int videoLength = 5)
        {
            //视频转码指令
            //string para = $@"ffmpeg -i {tsUrl} -c copy -map 0 -f segment -segment_list {m3u8Url}.m3u8 -segment_time 5 {m3u8Url}-%03d.ts";
            //这里是关键点,一般平时切视频都是用FFmpeg -i  地址 -c这样,但是在服务器时,这样调用可能找不到ffmpeg的路径 所以这里直接用ffmpeg.exe来执行命令
            //string para = $@"{FFmpegPath} -i {tsUrl} -c copy -map 0 -f segment -segment_list {m3u8Url}.m3u8 -segment_time 5 {m3u8Url}-%03d.ts";
            string para = string.Format("ffmpeg -i {0} -profile:v baseline -level 3.0 -start_number 0 -hls_time {1} -hls_list_size 0 -f hls {2}", tsUrl, videoLength, m3u8Url);
            RunMyProcess(para);
        }

        /// <summary>
        /// 执行cmd指令
        /// </summary>
        /// <param name="Parameters"></param>
        public static void RunMyProcess(string Parameters)
        {
            using (Process p = new Process())
            {
                try
                {
                    p.StartInfo.FileName = "cmd.exe";
                    p.StartInfo.UseShellExecute = false;//是否使用操作系统shell启动
                    p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
                    p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
                    p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
                    p.StartInfo.CreateNoWindow = false;//不显示程序窗口                                                
                    p.Start();//启动程序
                    //向cmd窗口发送输入信息
                    p.StandardInput.WriteLine(Parameters + "&&exit");
                    p.StandardInput.AutoFlush = true;
                    p.StandardInput.Close();
                    //获取cmd窗口的输出信息
                    string output = p.StandardError.ReadToEnd(); //可以输出output查看具体报错原因

                    //等待程序执行完退出进程
                    p.WaitForExit();
                    p.Close();

                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }
    }
}

 到这里就该跑跑跑试试了

效果图

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值