多檔案斷點續傳,上傳視訊自動轉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
{
}
}
}
}
相關文章
- Ueditor 上傳圖片自動新增水印(只能上傳圖片,上傳檔案報錯)
- 自動將視訊檔案轉換成音訊檔案,mp4轉mp3格式音訊
- Ueditor上傳圖片自動新增水印(通用圖片檔案)
- VUE-多檔案斷點續傳、秒傳、分片上傳Vue斷點
- element上傳圖片元件使用方法|圖片回顯|格式轉換base64元件
- 圖片格式轉換,JPG圖片轉換成PDF
- 視訊音樂圖片格式轉換Permute 3
- Element-UI框架 —— Upload 上傳(圖片上傳格式和大小判斷)UI框架
- Java大檔案上傳、分片上傳、多檔案上傳、斷點續傳、上傳檔案minio、分片上傳minio等解決方案Java斷點
- 處理檔案上傳時的訊息格式轉換問題
- 大檔案上傳、斷點續傳、秒傳、beego、vue斷點GoVue
- 1. 大檔案上傳如何斷點續傳斷點
- Spring Boot MVC 單張圖片和多張圖片上傳 和通用檔案下載Spring BootMVC
- heic圖片轉換格式怎麼轉?
- word轉html用到的圖片路徑替換上傳HTML
- JAVA實現大檔案分片上傳斷點續傳Java斷點
- 圖片格式怎麼轉換,如何轉換jpg
- 多圖片formpost上傳ORM
- PHP實現圖片(檔案)上傳PHP
- C++圖片格式轉換:BMP轉JPEGC++
- dcat-admin上傳圖片 會自動把圖片壓成2:1的格式?
- JS判斷檔案上傳格式JS
- vue+element 將圖片壓縮並轉換成base64上傳圖片Vue
- 怎麼轉換圖片格式並壓縮圖片
- ie8上傳本地圖片檔案轉base64 並預覽地圖
- Pytorch視覺化(顯示圖片)及格式轉換PyTorch視覺化
- Element-UI框架 —— Upload 上傳(視訊上傳格式和大小判斷)UI框架
- [提問交流]多圖上傳外掛和系統自帶的圖片上傳不能共存嗎?
- Laravel editor.md 支援截圖 / 貼上上傳圖片Laravel
- 前端實現圖片上傳預覽並轉換base64前端
- aspose word轉換pdf檔案後將pdf檔案轉換為圖片png
- android短視訊開發,點選靜態圖片自動跳轉播放視訊Android
- WidsMob ImageConvert for Mac 圖片格式轉換器Mac
- 教程:怎麼轉換heic格式圖片
- 圖片上傳顯示替換
- 想要pdf檔案裡面的圖片,求問pdf格式轉換成jpg?
- [Laravel Admin] 檔案 / 圖片上傳功能之擴充套件 -- 上傳新圖且保留原圖Laravel套件
- 如何給視訊格式的檔案進行格式轉換 可以轉為音訊格式嗎?音訊