北海和安宁春城网上演练,以贵港思杨木业为模板
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

399 lines
11 KiB

using UnityEngine;
using FFmpeg;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
/// <summary>
/// Entry point for FFmpeg
/// </summary>
public static class FFmpegCommands
{
//Do not call this
static FFmpegWrapper w;
//Call this ------------|
// |
// \|/
static FFmpegWrapper Wrapper
{
get
{
if (w == null)
{
w = MonoBehaviour.FindObjectOfType<FFmpegWrapper>();
if (w == null)
Debug.LogException(new Exception("Place a FFmpeg.prefab in the scene"));
}
return w;
}
}
//Data (instructions)
public const char SEPARATOR = ' ';
public const char QUOTE = '\'';
public const char DOUBLE_QUOTE = '\"';
public const string VERSION_INSTRUCTION = "-version";
public const string REWRITE_INSTRUCTION = "-y";
public const string INPUT_INSTRUCTION = "-i";
public const string INDEX_PREFIX_INSTRUCTION = "%";
public const string INDEX_SUFIX_INSTRUCTION = "d";
public const string RESIZE_INSTRUCTION = "-r";
public const string SS_INSTRUCTION = "-ss";
public const string CODEC_INSTRUCTION = "-codec";
public const string C_CODEC_INSTRUCTION = "-c";
public const string COPY_INSTRUCTION = "copy";
public const string TIME_INSTRUCTION = "-t";
public const string CODEC_VIDEO_INSTRUCTION = "-c:v";
public const string CODEC_AUDIO_INSTRUCTION = "-c:a";
public const string LIB_X264_INSTRUCTION = "libx264";
public const string CONSTANT_RATE_FACTOR_INSTRUCTION = "-crf";
public const string FILE_FORMAT_INPUT_INSTRUCTION = "-f";
public const string CONCAT_INSTRUCTION = "concat";
public const string SAFE_INSTRUCTION = "-safe";
public const string ZERO_INSTRUCTION = "0";
public const string FILTER_COMPLEX_INSTRUCTION = "-filter_complex";
public const string MAP_INSTRUCTION = "-map";
public const string PRESET_INSTRUCTION = "-preset";
public const string VIDEO_INSTRUCTION = "[v]";
public const string AUDIO_INSTRUCTION = "[a]";
public const string ULTRASAFE_INSTRUCTION = "ultrafast";
public const string VIDEO_FORMAT = "[{0}:v:0] ";
public const string AUDIO_FORMAT = "[{0}:a:0] ";
public const string CONCAT_FORMAT = "{0}=n={1}:v=1:a=1";
public const string FIRST_INPUT_VIDEO_CHANNEL = "0:v";
public const string SECOND_INPUT_AUDIO_CHANNEL = "1:a";
public const string SHORTEST_INSTRUCTION = "-shortest";
public const string PIXEL_FORMAT = "-pix_fmt";
public const string YUV_420P = "yuv420p";
//------------------------------
public static void GetVersion()
{
Wrapper.Execute(new string[] { VERSION_INSTRUCTION });
}
//------------------------------
public static void Convert(BaseData config)
{
//-y -i .../input.mp4 .../output.mp3
string[] command =
{
REWRITE_INSTRUCTION,
INPUT_INSTRUCTION,
config.inputPath,
config.outputPath
};
DebugCommand(command);
Wrapper.Execute(command);
}
//------------------------------
public static void Trim(TrimData config)
{
//-y -i .../input.mp4 -ss 00:00:50.0 -codec copy -t 20 .../output.mp4
string[] command =
{
REWRITE_INSTRUCTION,
INPUT_INSTRUCTION,
config.inputPath,
SS_INSTRUCTION,
config.fromTime,
CODEC_INSTRUCTION,
COPY_INSTRUCTION,
TIME_INSTRUCTION,
config.durationSec.ToString(),
config.outputPath
};
DebugCommand(command);
Wrapper.Execute(command);
}
//------------------------------
public static void Decode(DecodeEncodeData config)
{
//-y -i .../video.mp4 -r 30 .../image%1d.jpg .../track.mp3
string[] command =
{
REWRITE_INSTRUCTION,
INPUT_INSTRUCTION,
config.inputPath,
RESIZE_INSTRUCTION,
config.fps.ToString(),
config.outputPath,
config.soundPath
};
DebugCommand(command);
Wrapper.Execute(command);
}
//------------------------------
public static void Encode(DecodeEncodeData config)
{
//-y -i .../image%1d.jpg -r 30 -i .../track.mp3 -pix_fmt yuv420p .../video.mp4
string[] command =
{
REWRITE_INSTRUCTION,
INPUT_INSTRUCTION,
config.inputPath,
RESIZE_INSTRUCTION,
config.fps.ToString(),
INPUT_INSTRUCTION,
config.soundPath,
PIXEL_FORMAT,
YUV_420P,
config.outputPath
};
DebugCommand(command);
Wrapper.Execute(command);
}
//------------------------------
public static void Compress(CompressionData config)
{
//-i .../input.mp4 -c:v libx264 -crf 23 .../output.mp4 -y
string[] command =
{
INPUT_INSTRUCTION,
config.inputPath,
CODEC_VIDEO_INSTRUCTION,
LIB_X264_INSTRUCTION,
CONSTANT_RATE_FACTOR_INSTRUCTION,
config.crf.ToString(),
config.outputPath,
REWRITE_INSTRUCTION
};
DebugCommand(command);
Wrapper.Execute(command);
}
//------------------------------
public static void AppendFast(AppendData config)
{
//-f concat -safe 0 -i .../mylist.txt -c copy .../output.mp4 -y
string[] command =
{
FILE_FORMAT_INPUT_INSTRUCTION,
CONCAT_INSTRUCTION,
SAFE_INSTRUCTION,
ZERO_INSTRUCTION,
INPUT_INSTRUCTION,
GetInputsFile(config.inputPaths),
C_CODEC_INSTRUCTION,
COPY_INSTRUCTION,
config.outputPath,
REWRITE_INSTRUCTION
};
DebugCommand(command);
Wrapper.Execute(command);
}
static string GetInputsFile(List<string> inputPaths)
{
string inputFolder = Path.GetDirectoryName(
//Remove standalone style
inputPaths[0].Replace("\"", string.Empty));
StringBuilder fileBuffer = new StringBuilder();
fileBuffer.Append("# File with input videos\n");
foreach(string ip in inputPaths)
{
//Relative to input folder
string inputPath = ip.Remove(0, inputFolder.Length);
//Remove standalone style
inputPath = ip.Replace("\"", string.Empty);
fileBuffer.Append("file '" + inputPath + "'\n");
}
string filePath = Path.Combine(inputFolder, "AppendInputFiles.txt");
using (FileStream fileStream = File.Create(filePath))
{
byte[] buffer =
new UTF8Encoding(true).GetBytes(fileBuffer.ToString());
fileStream.Write(buffer, 0, buffer.Length);
}
#if UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_EDITOR
filePath = DOUBLE_QUOTE + filePath + DOUBLE_QUOTE;
#endif
Debug.Log("FilePath: " + filePath);
return filePath;
}
//------------------------------
public static void AppendFull(AppendData config)
{
//ffmpeg - i .../input1.mp4 - i .../input2.webm \
//-filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] concat=n=2:v=1:a=1 [v] [a]" \
//-map "[v]" - map "[a]" < encoding options > .../output.mkv -y
List<string> cmd = new List<string>();
StringBuilder filter = new StringBuilder();
#if UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_EDITOR
filter.Append(DOUBLE_QUOTE);
#endif
for (int i = 0; i < config.inputPaths.Count; ++i)
{
cmd.Add(INPUT_INSTRUCTION);
cmd.Add(config.inputPaths[i]);
filter.Append(string.Format(VIDEO_FORMAT, i)).Append(string.Format(AUDIO_FORMAT, i));
}
filter.
Append(string.Format(CONCAT_FORMAT, CONCAT_INSTRUCTION, config.inputPaths.Count)).
Append(SEPARATOR).
Append(VIDEO_INSTRUCTION).
Append(SEPARATOR).
Append(AUDIO_INSTRUCTION);
#if UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_EDITOR
filter.Append(DOUBLE_QUOTE);
#endif
cmd.Add(FILTER_COMPLEX_INSTRUCTION);
cmd.Add(filter.ToString());
cmd.Add(MAP_INSTRUCTION);
cmd.Add(VIDEO_INSTRUCTION);
cmd.Add(MAP_INSTRUCTION);
cmd.Add(AUDIO_INSTRUCTION);
cmd.Add(PRESET_INSTRUCTION);
cmd.Add(ULTRASAFE_INSTRUCTION);
cmd.Add(config.outputPath);
cmd.Add(REWRITE_INSTRUCTION);
string[] command = cmd.ToArray();
DebugCommand(command);
Wrapper.Execute(command);
}
//------------------------------
public static void AddSoundFast(SoundData config)
{
//aac is compatible with mp4 - no need full re-encoding.
//-y -i .../input.mp4 -i .../audio.aac -c copy -map 0:v -map 1:a -shortest .../output.mp4
string[] command =
{
REWRITE_INSTRUCTION,
INPUT_INSTRUCTION,
config.inputPath,
INPUT_INSTRUCTION,
config.soundPath,
C_CODEC_INSTRUCTION,
COPY_INSTRUCTION,
MAP_INSTRUCTION,
FIRST_INPUT_VIDEO_CHANNEL,
MAP_INSTRUCTION,
SECOND_INPUT_AUDIO_CHANNEL,
SHORTEST_INSTRUCTION,
config.outputPath
};
DebugCommand(command);
Wrapper.Execute(command);
}
//------------------------------
public static void AddSoundFull(SoundData config)
{
//mp3 is does not compatible with mp4. Full re-encoding handles this.
//-y -i .../audio.mp3 -i .../input.mp4 .../output.mp4
string[] command =
{
REWRITE_INSTRUCTION,
INPUT_INSTRUCTION,
config.soundPath,
INPUT_INSTRUCTION,
config.inputPath,
config.outputPath
};
DebugCommand(command);
Wrapper.Execute(command);
}
//------------------------------
public static void Watermark(WatermarkData config)
{
//-y -i .../watermark.png -i .../input.mp4 -filter_complex \
//"[0:v]scale=iw*0.25:ih*0.25 [ovrl], [1:v][ovrl]overlay=x=(main_w-overlay_w)*0.95:y=(main_h-overlay_h)*0.05" \
//FFmpegUnityBindDemo.mp4
StringBuilder filter = new StringBuilder();
#if UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_EDITOR
filter.Append(DOUBLE_QUOTE);
#endif
filter.
Append("[0:v]scale=iw*").
Append(config.imageScale).
Append(":ih*").
Append(config.imageScale).
Append(" [ovrl], [1:v][ovrl]overlay=x=(main_w-overlay_w)*").
Append(config.xPosNormal).
Append(":y=(main_h-overlay_h)*").
Append(config.yPosNormal);
#if UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_EDITOR
filter.Append(DOUBLE_QUOTE);
#endif
string[] command =
{
REWRITE_INSTRUCTION,
INPUT_INSTRUCTION,
config.imagePath,
INPUT_INSTRUCTION,
config.inputPath,
FILTER_COMPLEX_INSTRUCTION,
filter.ToString(),
config.outputPath
};
DebugCommand(command);
Wrapper.Execute(command);
}
//------------------------------
public static void DirectInput(string input)
{
string[] command = input.Split(' ');
DebugCommand(command);
Wrapper.Execute(command);
}
//------------------------------
static void DebugCommand(string[] command)
{
StringBuilder debugCommand = new StringBuilder();
foreach (string instruction in command)
debugCommand.Append(instruction + " ");
Debug.Log(debugCommand.ToString());
}
}