支持下载完成后自动封装音视频
This commit is contained in:
parent
01de8a53ad
commit
8d2b1d6faa
|
@ -44,6 +44,7 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
public static string cmd_uiLanguage { get => GetText("cmd_uiLanguage"); }
|
public static string cmd_uiLanguage { get => GetText("cmd_uiLanguage"); }
|
||||||
public static string cmd_urlProcessorArgs { get => GetText("cmd_urlProcessorArgs"); }
|
public static string cmd_urlProcessorArgs { get => GetText("cmd_urlProcessorArgs"); }
|
||||||
public static string cmd_useShakaPackager { get => GetText("cmd_useShakaPackager"); }
|
public static string cmd_useShakaPackager { get => GetText("cmd_useShakaPackager"); }
|
||||||
|
public static string cmd_muxAfterDone { get => GetText("cmd_muxAfterDone"); }
|
||||||
public static string cmd_writeMetaJson { get => GetText("cmd_writeMetaJson"); }
|
public static string cmd_writeMetaJson { get => GetText("cmd_writeMetaJson"); }
|
||||||
public static string fetch { get => GetText("fetch"); }
|
public static string fetch { get => GetText("fetch"); }
|
||||||
public static string ffmpegMerge { get => GetText("ffmpegMerge"); }
|
public static string ffmpegMerge { get => GetText("ffmpegMerge"); }
|
||||||
|
|
|
@ -220,6 +220,12 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
zhTW: "使用shaka-packager替代mp4decrypt",
|
zhTW: "使用shaka-packager替代mp4decrypt",
|
||||||
enUS: "Use shaka-packager instead of mp4decrypt"
|
enUS: "Use shaka-packager instead of mp4decrypt"
|
||||||
),
|
),
|
||||||
|
["cmd_muxAfterDone"] = new TextContainer
|
||||||
|
(
|
||||||
|
zhCN: "所有工作完成时尝试使用ffmpeg混流分离的音视频(mkv)",
|
||||||
|
zhTW: "所有工作完成時嘗試使用ffmpeg混流分離的影音(mkv)",
|
||||||
|
enUS: "When all works is done, try to use ffmpeg to mux the separated audio(s) and video.(mkv)"
|
||||||
|
),
|
||||||
["cmd_writeMetaJson"] = new TextContainer
|
["cmd_writeMetaJson"] = new TextContainer
|
||||||
(
|
(
|
||||||
zhCN: "解析后的信息是否输出json文件",
|
zhCN: "解析后的信息是否输出json文件",
|
||||||
|
|
|
@ -36,6 +36,7 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
private readonly static Option<bool> AppendUrlParams = new(new string[] { "--append-url-params" }, description: ResString.cmd_appendUrlParams, getDefaultValue: () => false);
|
private readonly static Option<bool> AppendUrlParams = new(new string[] { "--append-url-params" }, description: ResString.cmd_appendUrlParams, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> MP4RealTimeDecryption = new (new string[] { "--mp4-real-time-decryption" }, description: ResString.cmd_MP4RealTimeDecryption, getDefaultValue: () => false);
|
private readonly static Option<bool> MP4RealTimeDecryption = new (new string[] { "--mp4-real-time-decryption" }, description: ResString.cmd_MP4RealTimeDecryption, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> UseShakaPackager = new (new string[] { "--use-shaka-packager" }, description: ResString.cmd_useShakaPackager, getDefaultValue: () => false);
|
private readonly static Option<bool> UseShakaPackager = new (new string[] { "--use-shaka-packager" }, description: ResString.cmd_useShakaPackager, getDefaultValue: () => false);
|
||||||
|
private readonly static Option<bool> MuxAfterDone = new (new string[] { "--mux-after-done" }, description: ResString.cmd_muxAfterDone, getDefaultValue: () => false);
|
||||||
private readonly static Option<string?> DecryptionBinaryPath = new(new string[] { "--decryption-binary-path" }, description: ResString.cmd_decryptionBinaryPath);
|
private readonly static Option<string?> DecryptionBinaryPath = new(new string[] { "--decryption-binary-path" }, description: ResString.cmd_decryptionBinaryPath);
|
||||||
private readonly static Option<string?> FFmpegBinaryPath = new(new string[] { "--ffmpeg-binary-path" }, description: ResString.cmd_ffmpegBinaryPath);
|
private readonly static Option<string?> FFmpegBinaryPath = new(new string[] { "--ffmpeg-binary-path" }, description: ResString.cmd_ffmpegBinaryPath);
|
||||||
|
|
||||||
|
@ -73,6 +74,7 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
FFmpegBinaryPath = bindingContext.ParseResult.GetValueForOption(FFmpegBinaryPath),
|
FFmpegBinaryPath = bindingContext.ParseResult.GetValueForOption(FFmpegBinaryPath),
|
||||||
KeyTextFile = bindingContext.ParseResult.GetValueForOption(KeyTextFile),
|
KeyTextFile = bindingContext.ParseResult.GetValueForOption(KeyTextFile),
|
||||||
DownloadRetryCount = bindingContext.ParseResult.GetValueForOption(DownloadRetryCount),
|
DownloadRetryCount = bindingContext.ParseResult.GetValueForOption(DownloadRetryCount),
|
||||||
|
MuxAfterDone = bindingContext.ParseResult.GetValueForOption(MuxAfterDone),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,10 +93,10 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
|
|
||||||
public static async Task<int> InvokeArgs(string[] args, Func<MyOption, Task> action)
|
public static async Task<int> InvokeArgs(string[] args, Func<MyOption, Task> action)
|
||||||
{
|
{
|
||||||
var rootCommand = new RootCommand("N_m3u8DL-RE (Beta version) 20220819")
|
var rootCommand = new RootCommand("N_m3u8DL-RE (Beta version) 20220821")
|
||||||
{
|
{
|
||||||
Input, TmpDir, SaveDir, SaveName, ThreadCount, DownloadRetryCount, AutoSelect, SkipMerge, SkipDownload, CheckSegmentsCount,
|
Input, TmpDir, SaveDir, SaveName, ThreadCount, DownloadRetryCount, AutoSelect, SkipMerge, SkipDownload, CheckSegmentsCount,
|
||||||
BinaryMerge, DelAfterDone, WriteMetaJson, AppendUrlParams, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix,
|
BinaryMerge, DelAfterDone, WriteMetaJson, MuxAfterDone, AppendUrlParams, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix,
|
||||||
FFmpegBinaryPath,
|
FFmpegBinaryPath,
|
||||||
LogLevel, UILanguage, UrlProcessorArgs, Keys, KeyTextFile, DecryptionBinaryPath, UseShakaPackager, MP4RealTimeDecryption
|
LogLevel, UILanguage, UrlProcessorArgs, Keys, KeyTextFile, DecryptionBinaryPath, UseShakaPackager, MP4RealTimeDecryption
|
||||||
};
|
};
|
||||||
|
|
|
@ -86,6 +86,10 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseShakaPackager { get; set; }
|
public bool UseShakaPackager { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// See: <see cref="CommandInvoker.MuxAfterDone"/>.
|
||||||
|
/// </summary>
|
||||||
|
public bool MuxAfterDone { get; set; }
|
||||||
|
/// <summary>
|
||||||
/// See: <see cref="CommandInvoker.SubtitleFormat"/>.
|
/// See: <see cref="CommandInvoker.SubtitleFormat"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SubtitleFormat SubtitleFormat { get; set; }
|
public SubtitleFormat SubtitleFormat { get; set; }
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace N_m3u8DL_RE.Config
|
||||||
FFmpegBinaryPath = option.FFmpegBinaryPath;
|
FFmpegBinaryPath = option.FFmpegBinaryPath;
|
||||||
KeyTextFile = option.KeyTextFile;
|
KeyTextFile = option.KeyTextFile;
|
||||||
DownloadRetryCount = option.DownloadRetryCount;
|
DownloadRetryCount = option.DownloadRetryCount;
|
||||||
|
MuxAfterDone = option.MuxAfterDone;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -92,6 +93,10 @@ namespace N_m3u8DL_RE.Config
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseShakaPackager { get; set; }
|
public bool UseShakaPackager { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// 自动混流音视频
|
||||||
|
/// </summary>
|
||||||
|
public bool MuxAfterDone { get; set; }
|
||||||
|
/// <summary>
|
||||||
/// MP4解密所用工具的全路径
|
/// MP4解密所用工具的全路径
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? DecryptionBinaryPath { get; set; }
|
public string? DecryptionBinaryPath { get; set; }
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
IDownloader Downloader;
|
IDownloader Downloader;
|
||||||
DownloaderConfig DownloaderConfig;
|
DownloaderConfig DownloaderConfig;
|
||||||
DateTime NowDateTime;
|
DateTime NowDateTime;
|
||||||
|
List<OutputFile> OutputFiles = new();
|
||||||
|
|
||||||
public SimpleDownloadManager(DownloaderConfig downloaderConfig)
|
public SimpleDownloadManager(DownloaderConfig downloaderConfig)
|
||||||
{
|
{
|
||||||
|
@ -94,7 +95,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
if (segments == null) return false;
|
if (segments == null) return false;
|
||||||
|
|
||||||
var type = streamSpec.MediaType ?? Common.Enum.MediaType.VIDEO;
|
var type = streamSpec.MediaType ?? Common.Enum.MediaType.VIDEO;
|
||||||
var dirName = $"{DownloaderConfig.SaveName ?? NowDateTime.ToString("yyyy-MM-dd_HH-mm-ss")}_{streamSpec.GroupId}_{streamSpec.Codecs}_{streamSpec.Language}";
|
var dirName = $"{DownloaderConfig.SaveName ?? NowDateTime.ToString("yyyy-MM-dd_HH-mm-ss")}_{streamSpec.GroupId}_{streamSpec.Codecs}_{streamSpec.Bandwidth}_{streamSpec.Language}";
|
||||||
//去除非法字符
|
//去除非法字符
|
||||||
dirName = ConvertUtil.GetValidFileName(dirName, filterSlash: true);
|
dirName = ConvertUtil.GetValidFileName(dirName, filterSlash: true);
|
||||||
var tmpDir = Path.Combine(DownloaderConfig.TmpDir ?? Environment.CurrentDirectory, dirName);
|
var tmpDir = Path.Combine(DownloaderConfig.TmpDir ?? Environment.CurrentDirectory, dirName);
|
||||||
|
@ -250,19 +251,20 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var output = Path.Combine(saveDir, saveName + $".{streamSpec.Extension ?? "ts"}");
|
//修改输出后缀
|
||||||
|
var outputExt = "." + streamSpec.Extension;
|
||||||
|
if (streamSpec.Extension == null) outputExt = ".ts";
|
||||||
|
else if (streamSpec.MediaType == MediaType.AUDIO) outputExt = ".m4a";
|
||||||
|
else if (streamSpec.MediaType != MediaType.SUBTITLES) outputExt = ".mp4";
|
||||||
|
|
||||||
|
var output = Path.Combine(saveDir, saveName + outputExt);
|
||||||
|
|
||||||
//检测目标文件是否存在
|
//检测目标文件是否存在
|
||||||
while (File.Exists(output))
|
while (File.Exists(output))
|
||||||
{
|
{
|
||||||
Logger.WarnMarkUp($"{output} => {output = Path.ChangeExtension(output, $"copy" + Path.GetExtension(output))}");
|
Logger.WarnMarkUp($"{output} => {output = Path.ChangeExtension(output, $"copy" + Path.GetExtension(output))}");
|
||||||
}
|
}
|
||||||
|
|
||||||
//修改输出后缀
|
|
||||||
if (streamSpec.MediaType == Common.Enum.MediaType.AUDIO)
|
|
||||||
output = Path.ChangeExtension(output, ".m4a");
|
|
||||||
else if (streamSpec.MediaType != Common.Enum.MediaType.SUBTITLES)
|
|
||||||
output = Path.ChangeExtension(output, ".mp4");
|
|
||||||
|
|
||||||
if (DownloaderConfig.MP4RealTimeDecryption && mp4InitFile != "")
|
if (DownloaderConfig.MP4RealTimeDecryption && mp4InitFile != "")
|
||||||
{
|
{
|
||||||
File.Delete(mp4InitFile);
|
File.Delete(mp4InitFile);
|
||||||
|
@ -464,10 +466,18 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
//ffmpeg合并
|
||||||
var files = FileDic.Values.Select(v => v!.ActualFilePath).OrderBy(s => s).ToArray();
|
var files = FileDic.Values.Select(v => v!.ActualFilePath).OrderBy(s => s).ToArray();
|
||||||
Logger.InfoMarkUp(ResString.ffmpegMerge);
|
Logger.InfoMarkUp(ResString.ffmpegMerge);
|
||||||
var ext = streamSpec.MediaType == MediaType.AUDIO ? "m4a" : "mp4";
|
var ext = streamSpec.MediaType == MediaType.AUDIO ? "m4a" : "mp4";
|
||||||
mergeSuccess = MergeUtil.MergeByFFmpeg(DownloaderConfig.FFmpegBinaryPath!, files, Path.ChangeExtension(output, null), ext, useAACFilter);
|
var ffOut = Path.Combine(Path.GetDirectoryName(output)!, Path.GetFileNameWithoutExtension(output) + $".{ext}");
|
||||||
|
//检测目标文件是否存在
|
||||||
|
while (File.Exists(ffOut))
|
||||||
|
{
|
||||||
|
Logger.WarnMarkUp($"{ffOut} => {ffOut = Path.ChangeExtension(ffOut, $"copy" + Path.GetExtension(ffOut))}");
|
||||||
|
}
|
||||||
|
mergeSuccess = MergeUtil.MergeByFFmpeg(DownloaderConfig.FFmpegBinaryPath!, files, Path.ChangeExtension(ffOut, null), ext, useAACFilter);
|
||||||
|
if (mergeSuccess) output = ffOut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,10 +514,13 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
{
|
{
|
||||||
File.Delete(enc);
|
File.Delete(enc);
|
||||||
File.Move(dec, enc);
|
File.Move(dec, enc);
|
||||||
output = dec;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//记录所有文件信息
|
||||||
|
if (File.Exists(output))
|
||||||
|
OutputFiles.Add(new OutputFile() { FilePath = output, LangCode = streamSpec.Language, Description = streamSpec.Name });
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,7 +559,20 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Results.Values.All(v => v == true);
|
var success = Results.Values.All(v => v == true);
|
||||||
|
|
||||||
|
//混流
|
||||||
|
if (success && OutputFiles.Count > 0)
|
||||||
|
{
|
||||||
|
var outName = $"{DownloaderConfig.SaveName ?? NowDateTime.ToString("yyyy-MM-dd_HH-mm-ss")}";
|
||||||
|
Logger.WarnMarkUp($"Muxing to [grey]{outName.EscapeMarkup()}.mkv[/]");
|
||||||
|
var result = MergeUtil.MuxInputsByFFmpeg(DownloaderConfig.FFmpegBinaryPath!, OutputFiles.ToArray(), outName);
|
||||||
|
//完成后删除各轨道文件
|
||||||
|
if (result) OutputFiles.ForEach(f => File.Delete(f.FilePath));
|
||||||
|
else Logger.ErrorMarkUp($"Mux failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace N_m3u8DL_RE.Entity
|
||||||
|
{
|
||||||
|
internal class OutputFile
|
||||||
|
{
|
||||||
|
public required string FilePath { get; set; }
|
||||||
|
public string? LangCode { get; set; }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -103,6 +103,7 @@ namespace N_m3u8DL_RE
|
||||||
parserConfig.UrlProcessors.Insert(0, new NowehoryzontyUrlProcessor());
|
parserConfig.UrlProcessors.Insert(0, new NowehoryzontyUrlProcessor());
|
||||||
|
|
||||||
var url = string.Empty;
|
var url = string.Empty;
|
||||||
|
//url = "https://media.axprod.net/TestVectors/v7-Clear/Manifest_1080p.mpd"; //多音轨多字幕
|
||||||
//url = "https://cmafref.akamaized.net/cmaf/live-ull/2006350/akambr/out.mpd"; //直播
|
//url = "https://cmafref.akamaized.net/cmaf/live-ull/2006350/akambr/out.mpd"; //直播
|
||||||
//url = "http://playertest.longtailvideo.com/adaptive/oceans_aes/oceans_aes.m3u8";
|
//url = "http://playertest.longtailvideo.com/adaptive/oceans_aes/oceans_aes.m3u8";
|
||||||
//url = "https://vod.sdn.wavve.com/hls/S01/S01_E461382925.1/1/5000/chunklist.m3u8";
|
//url = "https://vod.sdn.wavve.com/hls/S01/S01_E461382925.1/1/5000/chunklist.m3u8";
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
using N_m3u8DL_RE.Common.Log;
|
using N_m3u8DL_RE.Common.Log;
|
||||||
|
using N_m3u8DL_RE.Entity;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.CommandLine;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -46,6 +48,30 @@ namespace N_m3u8DL_RE.Util
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void InvokeFFmpeg(string binary, string command, string workingDirectory)
|
||||||
|
{
|
||||||
|
using var p = new Process();
|
||||||
|
p.StartInfo = new ProcessStartInfo()
|
||||||
|
{
|
||||||
|
WorkingDirectory = workingDirectory,
|
||||||
|
FileName = binary,
|
||||||
|
Arguments = command,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
UseShellExecute = false
|
||||||
|
};
|
||||||
|
p.ErrorDataReceived += (sendProcess, output) =>
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(output.Data))
|
||||||
|
{
|
||||||
|
Logger.WarnMarkUp($"[grey]{output.Data.EscapeMarkup()}[/]");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
p.Start();
|
||||||
|
p.BeginErrorReadLine();
|
||||||
|
p.WaitForExit();
|
||||||
|
}
|
||||||
|
|
||||||
public static bool MergeByFFmpeg(string binary, string[] files, string outputPath, string muxFormat, bool useAACFilter,
|
public static bool MergeByFFmpeg(string binary, string[] files, string outputPath, string muxFormat, bool useAACFilter,
|
||||||
bool fastStart = false,
|
bool fastStart = false,
|
||||||
bool writeDate = true, string poster = "", string audioName = "", string title = "",
|
bool writeDate = true, string poster = "", string audioName = "", string title = "",
|
||||||
|
@ -53,13 +79,6 @@ namespace N_m3u8DL_RE.Util
|
||||||
{
|
{
|
||||||
string dateString = string.IsNullOrEmpty(recTime) ? DateTime.Now.ToString("o") : recTime;
|
string dateString = string.IsNullOrEmpty(recTime) ? DateTime.Now.ToString("o") : recTime;
|
||||||
|
|
||||||
//同名文件已存在的共存策略
|
|
||||||
if (File.Exists($"{outputPath}.{muxFormat.ToLower()}"))
|
|
||||||
{
|
|
||||||
outputPath = Path.Combine(Path.GetDirectoryName(outputPath)!,
|
|
||||||
Path.GetFileName(outputPath) + "_" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder command = new StringBuilder("-loglevel warning -i concat:\"");
|
StringBuilder command = new StringBuilder("-loglevel warning -i concat:\"");
|
||||||
string ddpAudio = string.Empty;
|
string ddpAudio = string.Empty;
|
||||||
string addPoster = "-map 1 -c:v:1 copy -disposition:v:1 attached_pic";
|
string addPoster = "-map 1 -c:v:1 copy -disposition:v:1 attached_pic";
|
||||||
|
@ -112,31 +131,51 @@ namespace N_m3u8DL_RE.Util
|
||||||
|
|
||||||
Logger.DebugMarkUp($"{binary}: {command}");
|
Logger.DebugMarkUp($"{binary}: {command}");
|
||||||
|
|
||||||
using var p = new Process();
|
InvokeFFmpeg(binary, command.ToString(), Path.GetDirectoryName(files[0])!);
|
||||||
p.StartInfo = new ProcessStartInfo()
|
|
||||||
{
|
|
||||||
WorkingDirectory = Path.GetDirectoryName(files[0]),
|
|
||||||
FileName = binary,
|
|
||||||
Arguments = command.ToString(),
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
UseShellExecute = false
|
|
||||||
};
|
|
||||||
p.ErrorDataReceived += (sendProcess, output) =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(output.Data))
|
|
||||||
{
|
|
||||||
Logger.WarnMarkUp($"[grey]{output.Data.EscapeMarkup()}[/]");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
p.Start();
|
|
||||||
p.BeginErrorReadLine();
|
|
||||||
p.WaitForExit();
|
|
||||||
|
|
||||||
if (File.Exists($"{outputPath}.{muxFormat}") && new FileInfo($"{outputPath}.{muxFormat}").Length > 0)
|
if (File.Exists($"{outputPath}.{muxFormat}") && new FileInfo($"{outputPath}.{muxFormat}").Length > 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool MuxInputsByFFmpeg(string binary, OutputFile[] files, string outputPath)
|
||||||
|
{
|
||||||
|
string dateString = DateTime.Now.ToString("o");
|
||||||
|
StringBuilder command = new StringBuilder("-loglevel warning -y ");
|
||||||
|
|
||||||
|
//INPUT
|
||||||
|
foreach (var item in files)
|
||||||
|
{
|
||||||
|
command.Append($" -i \"{item.FilePath}\" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
//MAP
|
||||||
|
for (int i = 0; i < files.Length; i++)
|
||||||
|
{
|
||||||
|
command.Append($" -map {i} ");
|
||||||
|
}
|
||||||
|
|
||||||
|
//CLEAN
|
||||||
|
command.Append(" -map_metadata -1 ");
|
||||||
|
|
||||||
|
//LANG and NAME
|
||||||
|
for (int i = 0; i < files.Length; i++)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(files[i].LangCode))
|
||||||
|
command.Append($" -metadata:s:{i} language={files[i].LangCode} ");
|
||||||
|
if (!string.IsNullOrEmpty(files[i].Description))
|
||||||
|
command.Append($" -metadata:s:{i} title={files[i].Description} ");
|
||||||
|
}
|
||||||
|
|
||||||
|
command.Append($" -metadata date=\"{dateString}\" -ignore_unknown -copy_unknown -c copy \"{outputPath}.mkv\"");
|
||||||
|
|
||||||
|
InvokeFFmpeg(binary, command.ToString(), Path.GetDirectoryName(files[0].FilePath)!);
|
||||||
|
|
||||||
|
if (File.Exists($"{outputPath}.mkv") && new FileInfo($"{outputPath}.mkv").Length > 1024)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue