多文件断点续传,上传视频自动转MP4和截图,图片格式转换
功能:自己写的一个组件,根据调用传过来的的fileType判断是上传视频还是图片还是音频。可以选择多文件上传,同时也可以暂停,继续,取消,断网重连续传。如果上传的是视频,会自动转为mp4,自动截取一帧图片。如果上传的是.tif格式图片则转换为png格式(用的ffmpeg插件)。
界面:
前端代码:
@{
ViewBag.Title = "Index";
<link rel="stylesheet" href="/Content/gdsm/vendor/bootstrap-3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="/Content/gdsm/vendor/bootstrap-datepicker-1.6.4-dist/css/bootstrap-datepicker3.min.css">
<link rel="stylesheet" href="/Content/gdsm/css/common.css">
<link rel="stylesheet" href="/Content/gdsm/css/admin.css">
<script src="/Content/gdsm/vendor/jquery-3.3.1/jquery-3.3.1.min.js"></script>
<script src="/Content/gdsm/vendor/bootstrap-3.3.7/js/bootstrap.min.js"></script>
<script src="/Content/gdsm/vendor/layer-v3.1.1/layer/layer.js"></script>
<script src="/Content/gdsm/vendor/jquery.nicescroll-3.7.6/jquery.nicescroll.min.js"></script>
<script type="text/javascript" src="~/Content/gdsm/vendor/bootstrap-datepicker-1.6.4-dist/js/bootstrap-datepicker.min.js"></script>
<script type="text/javascript" src="~/Content/gdsm/vendor/bootstrap-datepicker-1.6.4-dist/locales/bootstrap-datepicker.zh-CN.min.js"></script>
<script src="/Content/gdsm/js/common.js"></script>
ViewData["datacategory"] = ViewContext.RouteData.Values["categoryData"];
string fileType = ViewContext.RouteData.Values["categroy"].ToString();
}
<div id="addShapeContent">
<div class="panel">
<div class="panel-heading">
<h3 class="panel-title">文件上传</h3>
</div>
<div class="panel-body shape-upload p30">
<div class="upload-box item">
@switch (fileType)
{
case "image":
<div class="upload-btn">
<input type="file" name="uploadFile" multiple="multiple" accept=".jpg,.jpeg,.png,.gif,.bmp,.tif">
选择文件
</div>
<p class="file-desc">(图片支持jpg, jpeg, png, gif, bmp, tif;大小不超过5M,推荐尺寸:4:3,16:9)</p>
break;
case "media":
<div class="upload-btn">
<input type="file" name="uploadFile" multiple="multiple" accept=".mp4,.flv,.avi,.wmv">
选择文件
</div>
<p class="file-desc">(视频支持mp4, flv, wmv, avi;大小不超过20M)</p>
break;
case "music":
<div class="upload-btn">
<input type="file" name="uploadFile" multiple="multiple" accept=".mp3">
选择文件
</div>
<p class="file-desc">(音频支持mp3大小不超过20M)</p>
break;
case "shape":
<div class="upload-btn">
<input type="file" name="uploadFile" multiple="multiple" accept=".jpg,.jpeg,.png,.gif,.bmp,.tif">
选择文件
</div>
<p class="file-desc">(图片支持jpg, jpeg, png, gif, bmp, tif;大小不超过5M,推荐尺寸:4:3,16:9)</p>
break;
}
</div>
<div class="item">
<div class="control-label">添加至</div>
<div class="control">
<select id="sltcategory" class="form-control">
@if (ViewData["datacategory"] != null)
{
foreach (var item in ViewData["datacategory"] as List<GDSMModel.JHResCategory>)
{
<option value="@item.res_category_id">@item.res_category_name</option>
}
}
</select>
</div>
</div>
<div class="item">
<div id="prolabel" class="control-label" style="display:none">正在上传中</div>
<div class="control">
<ul id="proul" class="progress-lists mt34" style="height:135px; overflow-y:auto;"></ul>
</div>
</div>
</div>
<div class="panel-footer">
<button type="button" class="btn btn-lucency js-cancle pull-right ml20">关闭</button>
</div>
</div>
</div>
<div id="progressbar" style="display:none">
<li class="progress-detail" id="****">
<span class="name" title="####" style="height:30px;">####</span>
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-success" role="progressbar"
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"
style="width:0%;">
</div>
</div>
<span class="num" style="width:30px;">0%</span>
<label class="currIndex" style="display:none">0</label>
<button class="btn btn-blue btn-sm" onclick="PauseAndContinue(this);" style="margin-right:10px">暂停</button>
<button class="btn btn-blue btn-sm" onclick="Cancle(this);">取消</button>
</li>
</div>
<script type="text/javascript">
//用于存储file信息
var filearr = new Array();
//离线状态下的fileID
var offlinefileids = new Array();
$(function () {
//数组加个删除功能
Array.prototype.remove = function (val) {
var index = this.indexOf(val);
if (index > -1) {
this.splice(index, 1);
}
};
//监听网络已连接事件
window.addEventListener('online', Online);
//上传功能
$("input[type='file']").change(function () {
var filelists = this.files;
//切换下标签类型,防止上传同一文件OnChange触发不了
$(this).attr("type", "text");
$(this).attr("type", "file");
for (var i = 0; i < filelists.length; i++) {
if (filelists == undefined) {
layer.open({
title: '错误提示'
, content: '您的浏览器暂不支持上传文件,建议使用IE9以上、FireFox、Chrome、360极速模式等浏览器。'
});
return;
}
if (filelists.length < 1) {
layer.open({
title: '错误提示'
, content: '请选择文件。'
});
return;
}
//验证格式类型
var fileSplit = filelists[i].name.toLowerCase().split(".");
var fileFormat = fileSplit[fileSplit.length - 1]; //获得文件结尾的类型如 zip rar 这种写法确保是最后的
if (validate(fileFormat, filelists[i].name)) {
$("#prolabel").show();
var fileid = uuid();//生成一个文件ID
var file = filelists[i];
var totalSize = filelists[i].size;//文件大小
var blockSize = 1024 * 1024;//块大小
var blockCount = Math.ceil(totalSize / blockSize);//总块数
//存储file信息
var data = new fileData(file, totalSize, blockCount, blockSize);
filearr[fileid] = data;
//存储执行上传中的文件id
offlinefileids.push(fileid);
//获取服务器上最近上传的文件块序号
//currIndex = 0;
//生成进度条
var progressbar = $("#progressbar").html();
//替换名称
progressbar = progressbar.replace(new RegExp("####", 'g'), file.name);
//替换ID
progressbar = progressbar.replace("****", fileid);
$("ul.progress-lists").append(progressbar);
//开始分块上传文件
UploadPost(fileid, file, totalSize, blockCount, blockSize);
}
}
});
});
//上传文件
function UploadPost(fileid, file, totalSize, blockCount, blockSize) {
var queryid = "#" + fileid;
var state = $(queryid).find("button[style]").html();//获取暂停继续的状态
var currIndex = parseInt($(queryid).find("label.currIndex").html());//获取文件块数
var category = $("#sltcategory").val();
if (!(state == "暂停")) {
if ($(queryid).find("label.currIndex").html() == "-1") {
//取消上传,删除文件块
CancleAjax(queryid, fileid);
}
return; //暂停
}
try {
var start = currIndex * blockSize; //文件流开始位置
var end = Math.min(totalSize, start + blockSize); //文件流结束位置
var block = file.slice(start, end); //截取下来的文件流块信息
//组装提交表单信息
var formDataBlock = new FormData();
formDataBlock.append('fileName', file.name);//文件名
formDataBlock.append('blockCount', blockCount);//总块数
formDataBlock.append('currIndex', currIndex);//当前上传的块下标
formDataBlock.append('uploadId', fileid);//上传编号
formDataBlock.append('fileType', "@fileType");//文件类别
formDataBlock.append('categoryType', category)//分类
formDataBlock.append('totalSize', totalSize)//文件大小,用于验证
formDataBlock.append('data', block);
//提交服务器
$.ajax({
url: '/Admin/FileUpload/Upload',
type: 'post',
data: formDataBlock,
processData: false,
contentType: false,
success: function (res) {
block = null;
if ($(queryid).find("label.currIndex").html() == "-1") {
//取消上传,删除文件块
CancleAjax(queryid, fileid);
}
else if (res.Code === 1) {
//设置进度条
currIndex++;
var num = Math.round((currIndex) / blockCount * 100) + "%";
$(queryid).find("span.num").html(num);
$(queryid).find("div.progress-bar").css("width", num);
//如果当前文件块不是最后一个,递归上传其他文件块信息
if (currIndex < blockCount) {
$(queryid).find("label.currIndex").html(currIndex);
UploadPost(fileid, file, totalSize, blockCount, blockSize);
}
else {
//上传成功
$(queryid).fadeOut(2000, function () {
$(this).remove();
if ($("#proul").children().length <= 1)
$("#prolabel").fadeOut("fast");
});
offlinefileids.remove(fileid);
filearr[fileid] = "";
}
}
else {
layer.open({
title: '错误提示'
, content: res.Msg
});
}
}, error: function (e) {
if (!navigator.onLine) {
layer.open({
title: '错误提示'
, content: '网络连接已断开。'
});
}
else if (e.status == 0) {
UploadPost(fileid, file, totalSize, blockCount, blockSize);
}
else {
layer.open({
title: '错误提示'
, content: e.responseText
});
}
}
});
} catch (e) {
alert(e);
}
}
//暂停
function PauseAndContinue(obj) {
var fileid = $(obj).parent().attr("id");
if ($(obj).html() == "暂停") {
$(obj).html("继续");
offlinefileids.remove(fileid);
}
else {
$(obj).html("暂停");
var fdata = filearr[fileid];
offlinefileids.push(fileid);
UploadPost(fileid, fdata.file, fdata.totalSize, fdata.blockCount, fdata.blockSize);
}
}
//取消
function Cancle(obj) {
$(obj).parent().find("label.currIndex").html("-1");
}
//取消上传,删除文件块
function CancleAjax(queryid, fileid) {
$.ajax({
url: '/Admin/FileUpload/Cancle?id=' + fileid,
datatype: "json",
type: "GET",
async: false,
success: function () {
$(queryid).find("span.num").html("0%");
$(queryid).find("div.progress-bar").css("width", 0);
$(queryid).fadeOut(2000, function () {
$(this).remove();
if ($("#proul").children().length <= 1)
$("#prolabel").fadeOut("fast");
});
}
});
}
//网络连接上继续执行上传
function Online() {
for (var i = 0; i < offlinefileids.length; i++) {
var fileid = offlinefileids[i];
var fdata = filearr[fileid];
UploadPost(fileid, fdata.file, fdata.totalSize, fdata.blockCount, fdata.blockSize);
}
}
//验证
function validate(fileType,filename)
{
var type = "@fileType";
var result = true;
switch (type) {
case "image":
if (fileType != "jpg" && fileType != "jpeg" && fileType != "png" && fileType != "gif" && fileType != "bmp" && fileType != "tif" && fileType != "") {
layer.open({
title: '格式错误'
, content: filename + '的格式错误'
});
result = false;
}
break;
case "shape":
if (fileType != "jpg" && fileType != "jpeg" && fileType != "png" && fileType != "gif" && fileType != "bmp" && fileType != "tif" && fileType != "") {
layer.open({
title: '格式错误'
, content: filename + '的格式错误'
});
result = false;
}
break;
case "music":
if (fileType != "mp3") {
layer.open({
title: '格式错误'
, content: filename + '的格式错误'
});
result = false;
}
break;
case "media":
if (fileType != "mp4" && fileType != "flv" && fileType != "avi" && fileType != "wmv") {
layer.open({
title: '格式错误'
, content: filename + '的格式错误'
});
result = false;
}
break;
}
return result;
}
//生成GUID
function uuid() {
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
//return uuid;
return uuid.replace(new RegExp("-", 'g'), "");
}
//用于存储file信息
function fileData(file, totalSize, blockCount, blockSize) {
this.file = file;
this.totalSize = totalSize;
this.blockCount = blockCount;
this.blockSize = blockSize;
}
</script>
后端代码:
using GDSMBLL;
using GDSMCommon;
using GDSMModel;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Mvc;
namespace GDSMPlateForm.Areas.Admin.Controllers
{
public class FileUploadController : Controller
{
public string oriVideoPathc = "";
public string outVideoPathc = "";
public string ffmpegPathc = System.Web.Hosting.HostingEnvironment.MapPath("~/Content/ffmpeg/ffmpeg.exe");
// GET: Admin/FileUpload
public ActionResult Index()
{
return View();
}
[Route]
[HttpPost]
public ActionResult Upload(string uploadId, int blockCount, int currIndex, string fileName,string fileType,string categoryType,int totalSize)
{
try
{
var file = Request.Files[0];
//文件格式
string format = Path.GetExtension(fileName);
//路径
MD5 md5 = new MD5CryptoServiceProvider();
string cryptStr = "";
#region 校验
ValidateHelper vh = new ValidateHelper();
if (file == null)
return Json(new UploadResult { Msg = "请选择文件" }, JsonRequestBehavior.AllowGet);
if (blockCount < 1)
return Json(new UploadResult { Msg = "块数量不能小于1" }, JsonRequestBehavior.AllowGet);
if (currIndex < 0)
return Json(new UploadResult { Msg = "块数量小于0" }, JsonRequestBehavior.AllowGet);
if (string.IsNullOrWhiteSpace(uploadId))
return Json(new UploadResult { Msg = "上传编号为空" }, JsonRequestBehavior.AllowGet);
if (!vh.IsValidateFileExtension(fileName))
{
return Json(new UploadResult { Msg = "文件格式不支持" }, JsonRequestBehavior.AllowGet);
}
if (totalSize > vh.GetResTypeSize(fileType))
{
return Json(new UploadResult { Msg = "文件超过指定大小" }, JsonRequestBehavior.AllowGet);
}
var result = new UploadResult { Code = 1, Msg = "上传成功~" };
result.UploadID = uploadId;
#endregion
#region ==块处理==
string relativePath = "/upload";
if (!string.IsNullOrEmpty(fileType) && !string.IsNullOrEmpty(categoryType))
{
relativePath = "/Content/resource/" + fileType + "/" + categoryType + "/" + uploadId;
}
string dir = System.Web.HttpContext.Current.Server.MapPath("~" + relativePath);
if (Directory.Exists(dir) == false)
{
Directory.CreateDirectory(dir);
}
//块文件名称
var blockName = $"{uploadId}_{currIndex}.block";
//块文件目录路径
var blockPath = Path.Combine(dir, "block");
//块文件目录对象
DirectoryInfo blockDirectoryInfo = Directory.Exists(blockPath) ? new DirectoryInfo(blockPath) : Directory.CreateDirectory(blockPath);
//块文件完整路径
var blockFullPath = Path.Combine(blockPath, blockName);
if (System.IO.File.Exists(blockFullPath))
{
//块已上传,不做失败处理
return Json(new UploadResult { Code = 1, Msg = "该文件块已上传~" }, JsonRequestBehavior.AllowGet);
}
file.SaveAs(blockFullPath);
#endregion
#region ==块合并处理==
//判断块文件是否已将上传完,上传完合并文件
if (blockDirectoryInfo.GetFiles().Count().Equals(blockCount))
{
//var timestamp = DateTime.Now.ToString("yyyMMdd");
string fileOldNmae = fileName;
fileName = uploadId + format;
//var filePath = Path.Combine(dir, timestamp);
var filePath = dir;
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
//完整文件存储路径
var fileFullPath = Path.Combine(filePath, fileName);
//读取每个文件块写入文件流
using (var fs = new FileStream(fileFullPath, FileMode.Create))
{
for (var i = 0; i < blockCount; i++)
{
var path = Path.Combine(blockPath, $"{uploadId}_{i}.block");
var bytes = System.IO.File.ReadAllBytes(path);
fs.Write(bytes, 0, bytes.Length);
}
//删除所有文件块路径
Directory.Delete(blockPath, true);
}
#region md5加密
FileStream fileStream = new FileStream(fileFullPath, FileMode.Open);
//对面文件流进行md5加密
byte[] cryptBytes = md5.ComputeHash(fileStream);
//加密的二进制转为string类型
cryptStr = Convert.ToBase64String(cryptBytes);
fileStream.Close();
#endregion
result.FileInfo = new UploadFileInfo
{
FileName = fileName,
FilePath = fileFullPath
};
if (fileType == "media")
{
outVideoPathc = filePath + "\\" + uploadId + ".mp4";//转mp4格式路径
oriVideoPathc = fileFullPath;//原视频路径
string thubHeight = "150";
string frameIndex = "1";
string thubWidth = "200";
string thubImagePath = filePath + "\\" + uploadId + ".png";
FileConvertUtil.MediaExstractImage(ffmpegPathc, oriVideoPathc, thubHeight, frameIndex, thubWidth, thubImagePath);
format = ".mp4";
fileName = uploadId + format;
System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(ConvertMp4WithoutTxt));
thread.Start();
}
else if (fileType == "image" || fileType == "shape")
{
if (format == ".tif" || format == ".TIF")
{
format = ".png";
fileName = uploadId + format;
outVideoPathc = filePath + "\\" + uploadId + ".png";//转mp4格式路径
oriVideoPathc = fileFullPath;//原视频路径
System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(ConvertImageFormat));
thread.Start();
}
}
#region 信息存入数据库
JHResouce jhResouce = new JHResouce();
jhResouce.file_id = Guid.NewGuid().ToString();
jhResouce.file_name = fileName;
jhResouce.file_oldname = fileOldNmae;
jhResouce.file_path = Path.Combine(relativePath, fileName).Replace("\\", "/");
jhResouce.res_category_id = categoryType;
jhResouce.create_user_id = "";
jhResouce.create_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
jhResouce.md5 = cryptStr;
if (fileType == "media")
{
jhResouce.file_type = Path.Combine(relativePath, uploadId + ".png").Replace("\\", "/");
}
else
{
jhResouce.file_type = format;
}
HttpCookie cookieid = Request.Cookies["user_id"];
if (cookieid != null)
{
if (cookieid.Value != "")
{
jhResouce.create_user_id = cookieid.Value;
}
}
JHResouceBL hResouceBL = new JHResouceBL();
hResouceBL.Insert(jhResouce, GetTableName(fileType));
new JHLogBL().Insert(LogType.add, fileType + "添加操作,文件上传");
#endregion
}
#endregion
return Json(result);
}
catch (Exception ex)
{
throw;
}
}
/// <summary>
/// 上传过程中取消上传,删除相应文件块
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet]
public int Cancle(string id)
{
try
{
//获取文件块路径,删除文件块
string dir = System.Web.HttpContext.Current.Server.MapPath("~/upload");
var blockPath = Path.Combine(dir, id);
Directory.Delete(blockPath, true);
return 1;
}
catch
{
return 0;
}
}
/// <summary>
/// 视频转换为mp4
/// </summary>
public void ConvertMp4WithoutTxt()
{
Process p = new Process();//建立外部调用线程
p.StartInfo.FileName = ffmpegPathc; //System.Windows.Forms.Application.StartupPath + "\\ffmpeg.exe";//要调用外部程序的绝对路径
// string StrArg = "-i concat:\"" + StrMP4A + "|" + StrMP4B + "\" -vcodec copy -acodec copy " + StrOutMp4Path + " -y";
//string StrArg = "- i concat: \"" + StrMP4A + "|" + StrMP4B + "\" - vcodec copy - acodec copy "+ StrOutMp4Path + " -y";
// string StrArg = "-i D:\\123.flv -i D:\\water.png -filter_complex \"overlay=10:10\" -b 1024k -acodec copy";
// string StrArg = "-i "+StrMP4A+" -acodec copy -vcodec copy -f flv C:\\dis\\test1.mp4";
// string StrArg = "-i \"" + StrMP4A + "\" -qscale 6 \"" + StrOutMp4Path + "\"";// "-i " + StrMP4A + " -y -vcodec h264 -b 1500 "+StrOutMp4Path ;
string StrArg = "-i " + oriVideoPathc + " -c:v libx264 -strict -2 " + outVideoPathc;
p.StartInfo.Arguments = StrArg;
p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN)
p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...这是我耗费了2个多月得出来的经验...mencoder就是用standardOutput来捕获的)
p.StartInfo.CreateNoWindow = true;//不创建进程窗口
p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
p.Start();//启动线程
p.BeginErrorReadLine();//开始异步读取
p.WaitForExit();//阻塞等待进程结束
p.Close();//关闭进程
p.Dispose();//释放资源
LogHelper.WriteLog("视频转换成功:" + outVideoPathc);
LogHelper.WriteLog("开始删除原文件:" + oriVideoPathc);
System.IO.File.Delete(oriVideoPathc);
LogHelper.WriteLog("原文件删除成功");
}
/// <summary>
/// 图片格式转换
/// </summary>
public void ConvertImageFormat()
{
Process p = new Process();//建立外部调用线程
p.StartInfo.FileName = ffmpegPathc; //System.Windows.Forms.Application.StartupPath + "\\ffmpeg.exe";//要调用外部程序的绝对路径
// string StrArg = "-i concat:\"" + StrMP4A + "|" + StrMP4B + "\" -vcodec copy -acodec copy " + StrOutMp4Path + " -y";
//string StrArg = "- i concat: \"" + StrMP4A + "|" + StrMP4B + "\" - vcodec copy - acodec copy "+ StrOutMp4Path + " -y";
// string StrArg = "-i D:\\123.flv -i D:\\water.png -filter_complex \"overlay=10:10\" -b 1024k -acodec copy";
// string StrArg = "-i "+StrMP4A+" -acodec copy -vcodec copy -f flv C:\\dis\\test1.mp4";
// string StrArg = "-i \"" + StrMP4A + "\" -qscale 6 \"" + StrOutMp4Path + "\"";// "-i " + StrMP4A + " -y -vcodec h264 -b 1500 "+StrOutMp4Path ;
string StrArg = "-i " + oriVideoPathc + " " + outVideoPathc;
p.StartInfo.Arguments = StrArg;
p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN)
p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...这是我耗费了2个多月得出来的经验...mencoder就是用standardOutput来捕获的)
p.StartInfo.CreateNoWindow = true;//不创建进程窗口
p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
p.Start();//启动线程
p.BeginErrorReadLine();//开始异步读取
p.WaitForExit();//阻塞等待进程结束
p.Close();//关闭进程
p.Dispose();//释放资源
LogHelper.WriteLog("图片转换成功:" + outVideoPathc);
LogHelper.WriteLog("开始删除原文件:" + oriVideoPathc);
System.IO.File.Delete(oriVideoPathc);
LogHelper.WriteLog("原文件删除成功");
}
private void Output(object sendProcess, DataReceivedEventArgs output)
{
if (!String.IsNullOrEmpty(output.Data))
{
}
else
{
//MessageBox.Show("视频合成失败");
}
}
/// <summary>
/// 根据类型获取表名
/// </summary>
/// <param name="stype"></param>
/// <returns></returns>
private string GetTableName(string stype)
{
string tableName = "";
if (stype == "image")
{
tableName = "h_res_image";
}
else if (stype == "shape")
{
tableName = "h_res_shape";
}
else if (stype == "music")
{
tableName = "h_res_music";
}
else if (stype == "media")
{
tableName = "h_res_media";
}
return tableName;
}
/// <summary>
/// 获取文件扩展名
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public string GetExtension(string fileName)
{
if (string.IsNullOrWhiteSpace(fileName) || fileName.IndexOf(".") < 0)
{
return string.Empty;
}
var arr = fileName.Split('.');
return arr[arr.Length - 1];
}
/// <summary>
/// 根据类型验证上传文件类型
/// </summary>
/// <param name="stype"></param>
/// <returns></returns>
private bool IsValidateFileExtension(string fileExtension)
{
string format = System.Configuration.ConfigurationManager.AppSettings["format"].ToString();
bool result = false;
fileExtension = fileExtension.Replace(".", "");
fileExtension = fileExtension.ToLower();
if (format.Contains(fileExtension))
{
result = true;
}
return result;
}
}
/// <summary>
/// 文件上传结果
/// </summary>
public class UploadResult
{
/// <summary>
/// 状态码 0失败 1成功
/// </summary>
public int Code { get; set; }
/// <summary>
/// 消息
/// </summary>
public string Msg { get; set; }
/// <summary>
/// 上传编号,唯一
/// </summary>
public string UploadID { get; set; }
/// <summary>
/// 文件保存信息
/// </summary>
public UploadFileInfo FileInfo { get; set; }
}
public class UploadFileInfo
{
/// <summary>
/// 文件保存名称
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 文件保存路径
/// </summary>
public string FilePath { get; set; }
/// <summary>
/// 文件MD5值
/// </summary>
public string MD5 { get; set; }
}
}
FileConvertUtil.cs(上传视频截图转格式功能)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace GDSMCommon
{
public class FileConvertUtil
{
/// <summary>
/// 获取视频的第一帧转换成图片
/// </summary>
/// <param name="ffmpegPath">ffmpeg路径</param>
/// <param name="oriVideoPath">视频路径</param>
/// <param name="thubHeight">转换后图片高度</param>
/// <param name="frameIndex">第几帧</param>
/// <param name="thubWidth">转换后图片的宽度</param>
/// <param name="thubImagePath">转换后图片存储路径</param>
public static void MediaExstractImage(string ffmpegPath,string oriVideoPath,string thubHeight,string frameIndex,string thubWidth,string thubImagePath)
{
Process p = new Process();//建立外部调用线程
p.StartInfo.FileName =ffmpegPath;//要调用外部程序的绝对路径
string command = string.Format("-i \"{1}\" -vframes 1 -r 1 -ac 1 -ab 2 -s {3}*{4} -f image2 \"{5}\"", ffmpegPath, oriVideoPath, frameIndex, thubWidth, thubHeight, thubImagePath);
command = string.Format(" -i \"{0}\" -y -f image2 -ss 00:00:01 -t 0.000001 -s {1}*{2} \"{3}\"",oriVideoPath,thubWidth,thubHeight,thubImagePath);
p.StartInfo.Arguments = command;
p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN)
p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...这是我耗费了2个多月得出来的经验...mencoder就是用standardOutput来捕获的)
p.StartInfo.CreateNoWindow = true;//不创建进程窗口
p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
p.Start();//启动线程
p.BeginErrorReadLine();//开始异步读取
p.WaitForExit();//阻塞等待进程结束
p.Close();//关闭进程
p.Dispose();//释放资源
LogHelper.WriteLog("图片转换成功:"+ thubImagePath);
}
/// <summary>
/// 视频转成相应格式
/// </summary>
/// <param name="ffmpegPath"></param>
/// <param name="oriVideoPath"></param>
/// <param name="outVideoPath"></param>
public static void ConvertMp4WithoutTxt(string ffmpegPath,string oriVideoPath, string outVideoPath)
{
Process p = new Process();//建立外部调用线程
p.StartInfo.FileName = ffmpegPath;// System.Windows.Forms.Application.StartupPath + "\\ffmpeg.exe";//要调用外部程序的绝对路径
// string StrArg = "-i concat:\"" + StrMP4A + "|" + StrMP4B + "\" -vcodec copy -acodec copy " + StrOutMp4Path + " -y";
//string StrArg = "- i concat: \"" + StrMP4A + "|" + StrMP4B + "\" - vcodec copy - acodec copy "+ StrOutMp4Path + " -y";
// string StrArg = "-i D:\\123.flv -i D:\\water.png -filter_complex \"overlay=10:10\" -b 1024k -acodec copy";
// string StrArg = "-i "+StrMP4A+" -acodec copy -vcodec copy -f flv C:\\dis\\test1.mp4";
string StrArg = "-i " + oriVideoPath + " -c:v libx264 -strict -2 " + oriVideoPath; //"-i \"" + oriVideoPath + "\" -qscale 6 \"" + outVideoPath + "\"";// "-i " + StrMP4A + " -y -vcodec h264 -b 500000 "+StrOutMp4Path ;
p.StartInfo.Arguments = StrArg;
p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN)
p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...这是我耗费了2个多月得出来的经验...mencoder就是用standardOutput来捕获的)
p.StartInfo.CreateNoWindow = true;//不创建进程窗口
p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
p.Start();//启动线程
p.BeginErrorReadLine();//开始异步读取
p.WaitForExit();//阻塞等待进程结束
p.Close();//关闭进程
p.Dispose();//释放资源
}
/// <summary>
/// 转换后调用方法
/// </summary>
/// <param name="sendProcess"></param>
/// <param name="output"></param>
private static void Output(object sendProcess, DataReceivedEventArgs output)
{
if (!String.IsNullOrEmpty(output.Data))
{
//处理方法...
}
else
{
}
}
}
}