先说说什么是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 大家自行百度 这里部在详细介绍
好了 说了这么废话 上才艺
前端 我们需要定义一个容器 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;
}
}
}
}
}
?到这里就该跑跑跑试试了
效果图
?
|