未安装FFmpeg的,请查看安装教程 >>
MP4转M3U8结果演示,推荐使用VLC Media Player进行M3U8播放测试
示例源码
1、前台调用
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>MP4视频转换为M3U8格式</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<p>视频ID:<asp:TextBox ID="txtCourseName" runat="server"></asp:TextBox></p>
<p>本地视频:<asp:FileUpload ID="upVideoFile" runat="server" /></p>
<p>片段时长:<asp:TextBox ID="txtVideoLength" runat="server" Text="5" TextMode="Number"></asp:TextBox></p>
<p><asp:Button ID="btnSave" runat="server" Text="开始转换" OnClick="btnSave_Click" /></p>
<p><asp:Literal ID="ltrTimer" runat="server"></asp:Literal></p>
</div>
</form>
</body>
</html>
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace AspNet_FFmpeg
{
public partial class UpCourse : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnSave_Click(object sender, EventArgs e)
{
try
{
this.ltrTimer.Text = DateTime.Now.ToString("hh:mm:ss:ms");
if (this.txtCourseName.Text.Trim().Equals(""))
{
Response.Write("<script>alert('请填写ID!')</script>");
return;
}
if (!this.upVideoFile.HasFile)
{
Response.Write("<script>alert('请选择视频!')</script>");
return;
}
//上传文件的名称的命名规则是标题
string fileName = this.txtCourseName.Text;
string filePathTemp = "upload_files/" + this.txtCourseName.Text.Trim();
string fpath = Path.Combine(Request.PhysicalApplicationPath, filePathTemp);
// 目录不存在,则创建目录
if (!Directory.Exists(fpath))
{
Directory.CreateDirectory(fpath);
}
//取出上传的视频的文件名,进而取出该文件的扩展名
string sourceFileName = Path.GetFileName(upVideoFile.FileName);
string extendName = sourceFileName.Substring(sourceFileName.LastIndexOf(".") + 1);
//检测上传文件是否为MP4文件
if (!extendName.ToLower().Equals("mp4"))
{
Response.Write("<script>alert('请选择MP4格式视频!')</script>");
return;
}
//上传到服务器
//上传后的文件名的命名规则是:标题+后缀
string fileNameTemp = fileName + "." + extendName;
string videoUrl = Path.Combine(fpath, fileNameTemp);
this.upVideoFile.SaveAs(videoUrl);
//截取缩略图
string imgUrl1 = Path.Combine(fpath, fileName + "01.jpg");
FFmpegHelper.CatchImg(videoUrl, imgUrl1, 0);
//截取缩略图
string imgUrl2 = Path.Combine(fpath, fileName + "02.jpg");
FFmpegHelper.CatchImg(videoUrl, imgUrl2, 1);
//截取缩略图
string imgUrl3 = Path.Combine(fpath, fileName + "03.jpg");
FFmpegHelper.CatchImg(videoUrl, imgUrl3, 2);
//检测是否已生成缩略图
if ((!System.IO.File.Exists(imgUrl1)) || !System.IO.File.Exists(imgUrl2) || !System.IO.File.Exists(imgUrl3))
{
//删除缩略图
System.IO.File.Delete(imgUrl1);
System.IO.File.Delete(imgUrl2);
System.IO.File.Delete(imgUrl3);
//删除MP4源文件
System.IO.File.Delete(videoUrl);
Response.Write("<script>alert('视频转换失败!')</script>");
return;
}
//进行视频转换
string tsUrl = Path.Combine(fpath, fileName + ".ts");
FFmpegHelper.VideoToTs(videoUrl, tsUrl);
//检测是否已生成ts文件
if (!System.IO.File.Exists(tsUrl))
{
//删除缩略图
System.IO.File.Delete(imgUrl1);
System.IO.File.Delete(imgUrl2);
System.IO.File.Delete(imgUrl3);
//删除MP4源文件
System.IO.File.Delete(videoUrl);
Response.Write("<script>alert('视频转换失败!')</script>");
return;
}
//生成M3U8文件
string m3u8Path = Path.Combine(fpath, fileName);
int VideoLength = Convert.ToInt32(this.txtVideoLength.Text);
FFmpegHelper.TsToM3u8(tsUrl, m3u8Path, VideoLength);
//检测是否已生成M3U8文件
if (!System.IO.File.Exists(m3u8Path + ".m3u8"))
{
//删除缩略图
System.IO.File.Delete(imgUrl1);
System.IO.File.Delete(imgUrl2);
System.IO.File.Delete(imgUrl3);
//删除MP4源文件
System.IO.File.Delete(videoUrl);
//删除TS源文件
System.IO.File.Delete(tsUrl);
Response.Write("<script>alert('视频转换失败!')</script>");
return;
}
//删除MP4源文件
System.IO.File.Delete(videoUrl);
//删除TS源文件
System.IO.File.Delete(tsUrl);
this.ltrTimer.Text += (" - " + DateTime.Now.ToString("hh:mm:ss:ms"));
Response.Write("<script>alert('视频转换完成!')</script>");
}
catch (Exception ex)
{
Response.Write("<script>alert('" + ex.Message + "')</script>");
return;
}
}
}
}
2、FFmpegHelper公共类
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;
namespace AspNet_FFmpeg
{
public static class FFmpegHelper
{
//安装的ffmpeg的路径 写在配置文件的 你也可以直接写你的路径 D:\ffmpeg\bin\ffmpeg.exe
//static string FFmpegPath = System.Configuration.ConfigurationManager.AppSettings["ffmepg"];
/// <summary>
/// 视频转码为ts文件
/// </summary>
/// <param name="videoUrl"></param>
/// <param name="targetUrl"></param>
public static void VideoToTs(string videoUrl, string targetUrl)
{
//视频转码指令
string cmd = string.Format("ffmpeg -y -i \"{0}\" -vcodec copy -acodec copy -vbsf h264_mp4toannexb \"{1}\"", videoUrl, targetUrl);
RunMyProcess(cmd);
}
/// <summary>
/// 将ts文件转换为mu3u8文件
/// </summary>
/// <param name="tsUrl"></param>
/// <param name="m3u8Url">这个路径不要带扩展名</param>
/// <param name="videoLength">视频切片时长,默认5秒</param>
public static void TsToM3u8(string tsUrl, string m3u8Url, int videoLength = 5)
{
//这里是关键点,一般平时切视频都是用FFmpeg -i 地址 -c这样,但是在服务器时,这样调用可能找不到ffmpeg的路径 所以这里直接用ffmpeg.exe来执行命令
//string cmd = $@"{FFmpegPath} -i {tsUrl} -c copy -map 0 -f segment -segment_list {m3u8Url}.m3u8 -segment_time 5 {m3u8Url}%03d.ts";
string cmd = string.Format("ffmpeg -i \"{0}\" -c copy -map 0 -f segment -segment_list \"{1}.m3u8\" -segment_time {2} \"{1}%03d.ts\"", tsUrl, m3u8Url, videoLength);
RunMyProcess(cmd);
}
/// <summary>
/// 生成MP4频的缩略图
/// </summary>
/// <param name="videoUrl">视频文件地址</param>
/// <param name="imgUrl">视频缩略图地址</param>
/// <param name="imgSize">宽和高参数,如:240*180</param>
/// <param name="Second">ss后跟的时间单位为秒</param>
/// <returns></returns>
public static string CatchImg(string videoUrl,string imgUrl, int Second=8, string imgSize= "1280x720")
{
try
{
//转换文件格式的同时抓缩微图:
//ffmpeg - i "test.avi" - y - f image2 - ss 8 - t 0.001 - s 350x240 'test.jpg'
//- ss后跟的时间单位为秒
string cmd = string.Format("ffmpeg -i \"{0}\" -y -f image2 -ss {1} -t 0.001 -s {2} \"{3}\"", videoUrl, Second, imgSize, imgUrl);
RunMyProcess(cmd);
//注意:图片截取成功后,数据由内存缓存写到磁盘需要时间较长,大概在3,4秒甚至更长;
//System.Threading.Thread.Sleep(500);
if (System.IO.File.Exists(imgUrl))
{
return imgUrl;
}
return "";
}
catch
{
return "";
}
}
/// <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();//启动线程
p.StandardInput.WriteLine(Parameters + "&&exit"); //向cmd窗口发送输入信息
p.StandardInput.AutoFlush = true;
p.StandardInput.Close();
//获取cmd窗口的输出信息
string output = p.StandardError.ReadToEnd(); //可以输出output查看具体报错原因
p.WaitForExit();//等待完成
p.Close();//关闭进程
p.Dispose();//释放资源
}
catch (Exception ex)
{
throw ex;
}
}
}
}
}