长视频文件的上传与播放
文章目录
概述
前端:vue3 video.js7.11.8 (https://videojs.com/)
后端:C# webapi
部署平台:前端nginx1.20 后端IIS7
工具:FFMpeg
需求:管理员会上传时长较长的视频文件(1h),用户在客户端查看视频。
m3u8是HLS协议的部分内容,以下copy大牛对mp4和m3u8的区别描述:
1.HTML5 直接支持m3u8协议。
2.m3u8其实是一个协议而不是一种视频格式,m3u8里面包括的多是视频块索引。可以通过网络状态自动切换码率。MP4就没有这方面优势了。
3.m3u8允许客户在进行播放时,从许多不同的备用源中下载视频块。
4.m3u8是HLS协议的部分内容。是一种能够通过http报文就能够请求和访问了。
MP4如果要实现在线播放那么就需要RTP协议来实现。两种手段有比较大的区别。
5.更高性能上能够将部分m3u8的播放块切块之后直接加载到服务器内存中,让客户端可以更快的得到数据。
6.m3u8 由于是采用切块技术,那么下载的播放文件 就可以少很多,只有当前播放的部分。这一点用在在线直播上有很大优势。
最后, 容易卡顿,可能是你访问该服务器的m3u8 延迟较高,网络问题,也可能是服务器没配好而已。
前端分片上传
后端分片接收
后端组装文件
后端FFMpeg将mp4格式转化为m3u8格式
/// <summary>
/// 将mp4源文件转换为流媒体文件
/// </summary>
/// <param name="fileName">mp4源文件名称</param>
/// <param name="filePathName">mp4源文件路径</param>
/// <param name="outputPath">hls输出文件路径</param>
/// <returns></returns>
public static string[] GetHls(string fileName, string filePathName, string outputPath)
{
List<string> vs = new List<string>();
outputPath = CreateFileDic(outputPath);
vs.Add(outputPath);
string command = "-i " + filePathName + " -codec copy -f hls -hls_list_size 200 -hls_time 60 " + outputPath + "\\" + fileName + ".m3u8";
var res = ExecuteCmd2(command);
vs.Add(res);
return vs.ToArray();
}
/// <summary>
/// 检测文件路径是否存在,没有的话创建路径
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private static string CreateFileDic(string path)
{
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
return path;
}
/// <summary>
/// 运行ffmpeg命令,切割视频
/// </summary>
/// <param name="Parameters"></param>
/// <returns></returns>
private static string ExecuteCmd2(string Parameters)
{
try
{
var address = WebConfigurationManager.AppSettings["ffmpegPath"];
if (string.IsNullOrEmpty(address)) address = "C:\\Program Files\\ffmpeg\\ffmpeg.exe";
var process = new System.Diagnostics.Process();
//进程优先级设置
//No process is associated with this object
//process.PriorityClass = ProcessPriorityClass.High;
//process.PriorityClass = ProcessPriorityClass.AboveNormal;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
//应该触发退出事件
process.EnableRaisingEvents = true;
//程序退出事件
process.Exited += (s, e) =>
{
stopwatch.Stop();
//记录退出事件
};
//程序输出消息事件
process.OutputDataReceived += (o, e) =>
{
if (string.IsNullOrWhiteSpace(e?.Data))
{
return;
}
//Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "程序1执行消息:" + e.Data);
};
//程序异常输出消息
process.ErrorDataReceived += (o, e) =>
{
if (string.IsNullOrWhiteSpace(e?.Data))
{
return;
}
//记录输出消息
};
var startInfo = new System.Diagnostics.ProcessStartInfo(address, Parameters);
startInfo.UseShellExecute = false;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardInput = true;
process.StartInfo = startInfo;
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
process.Close();
process.Dispose();
return "1";
//process.Kill();
//Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "转码完成");
}
catch (Exception ex)
{
return ex.Message;
}
}
配置IIS支持m3u8与ts格式
如果没有下列各式支持,请添加
- 扩展名:.ts Mine类型:video/vnd.dlna.mpeg-tts
- 扩展名:.m3u8 Mine类型:application/x-mpegURL
配置nginx/web.config支持m3u8与ts格式
1、修改mime.types:修改m3u8对应对应各式,添加ts对应各式
application/x-mpegURL m3u8;
video/mp2t ts;
2、配置nginx.conf:以下为示例
# 反向代理视频文件:视频流文件 添加型支持与跨域支持
location /video{
proxy_pass http://192.168.1.248:8091;
types{
application/x-mpegURL m3u8;
video/mp2t ts;
}
add_header Access-Control-Allow-Origin *;
}
前端展示长视频
这里我们直接用video.js7.11.8
video.js官网:https://videojs.com/
后端会返回m3u8的地址
以下为代码(jquery写法大同小异)
引用部分:
import Video from 'video.js'
import video_zhCN from 'video.js/dist/lang/zh-CN.json'
import video_en from 'video.js/dist/lang/en.json'
import 'video.js/dist/video-js.css'
Video.addLanguage('zh-CN', video_zhCN)
Video.addLanguage('en', video_en)
html部分:
<video id="hlsVideo" class="video-js vjs-big-play-centered">
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser that
<a href="https://videojs.com/html5-video-support/" target="_blank">
supports HTML5 video
</a>
</p>
</video>
js部分:
let hlsPlayer=null
//初始化页面的时候,从后端获取视频m3u8地址 作为source变量传入
const initHls=(source)=>{
hlsPlayer= Video('hlsVideo', {
controls: true, // 是否显示控制条
// poster: 'xxx', // 视频封面图地址
preload: 'auto',
autoplay: false,
fluid: false, // 自适应宽高
height:360,
width:640,
language: 'zh-CN', // 设置语言
muted: false, // 是否静音
inactivityTimeout: false,
controlBar:{
children:[
{name: 'playToggle'}, // 播放按钮
{name:'currentTimeDisplay'},
{name:'timeDivider'},
{name:'durationDisplay'},
{name: 'progressControl'},
// {name: 'remainingTimeDisplay'},
{
name: 'volumePanel', // 音量控制
inline: false, // 不使用水平方式
},
{name: 'FullscreenToggle'},
]
},
sources:[ // 视频源
{
// src: '//vjs.zencdn.net/v/oceans.mp4',
src:source.VideoPath,
type:'application/x-mpegURL',
}
]
}, function (){
$(".vjs-current-time").show()
$(".vjs-time-divider").show()
$(".vjs-duration").show()
// console.log('视频可以播放了',this);
});
}
//页面跳转(解除挂载) 将播放器dispose,否则会导致多次初始化
onUnmounted(()=>{
hlsPlayer && hlsPlayer.dispose()
})
动态修改video的src
有时候需要在同一个页面,切换视频的src
//修改video的src
function changeSource(src) {
hlsPlayer.pause();
hlsPlayer.currentTime(0);
hlsPlayer.src(src);
hlsPlayer.ready(function () {
this.one('loadeddata', videojs.bind(this, function () {
this.currentTime(0);
}));
hlsPlayer.load();
hlsPlayer.pause();
});
}