Skip to content
This repository has been archived by the owner on Feb 2, 2019. It is now read-only.

Commit

Permalink
Ffprober with caching, new preview method
Browse files Browse the repository at this point in the history
  • Loading branch information
CherryPerry committed Aug 8, 2015
1 parent 421ab7d commit c9fb446
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 70 deletions.
7 changes: 6 additions & 1 deletion VpxEncode/Cache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ public struct ACKey

private ConcurrentDictionary<int, ConcurrentDictionary<object, object>> Map = new ConcurrentDictionary<int, ConcurrentDictionary<object, object>>();

private Cache() { }
private Cache()
{
Map[CACHE_AUDIO] = new ConcurrentDictionary<object, object>();
Map[CACHE_FIRSTPASS] = new ConcurrentDictionary<object, object>();
Map[CACHE_STRINGS] = new ConcurrentDictionary<object, object>();
}

public void Put(int mode, object key, object value) { Map[mode][key] = value; }

Expand Down
41 changes: 41 additions & 0 deletions VpxEncode/Ffprober.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Newtonsoft.Json.Linq;
using System.Linq;

namespace VpxEncode
{
internal static class Ffprober
{
public struct Result
{
public string Scale;
public int HeightPix, WidthPix;
public string EndTime;
public string Framerate;
}

public static Result Probe(string filePath)
{
string args = $"-v quiet -print_format json -show_streams -show_format -hide_banner \"{filePath}\"";
string json = Cache.Instance.Get<string>(Cache.CACHE_STRINGS, args);
if (json == null)
{
json = new Executer(Executer.FFPROBE).Execute(args);
Cache.Instance.Put(Cache.CACHE_STRINGS, args, json);
}
try
{
JObject root = JObject.Parse(json);
var videoStream = root["streams"].Where(x => x["codec_type"].ToString() == "video").First();
return new Result()
{
EndTime = root["format"]["duration"].ToString(),
WidthPix = int.Parse(videoStream["width"].ToString()),
HeightPix = int.Parse(videoStream["height"].ToString()),
Scale = $"{videoStream["width"]}:{videoStream["height"]}",
Framerate = videoStream["r_frame_rate"].ToString()
};
}
catch { return default(Result); }
}
}
}
117 changes: 48 additions & 69 deletions VpxEncode/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ public static void Main(string[] args)
Encode(index, filePath, subPath, start, end, ArgList.Get(Arg.LIMIT).AsInt());
}
};
Parallel.ForEach(indexes, new ParallelOptions { MaxDegreeOfParallelism = ArgList.Get(Arg.SINGLE_THREAD) ? (Environment.ProcessorCount - 1) : Math.Max(1, Environment.ProcessorCount / 2) },
Parallel.ForEach(indexes, new ParallelOptions
{ MaxDegreeOfParallelism = ArgList.Get(Arg.SINGLE_THREAD) ? Math.Max(1, Environment.ProcessorCount - 1) : Math.Max(1, Environment.ProcessorCount / 2) },
(singleIndex) =>
{
if (lines.Length > singleIndex && singleIndex >= 0)
Expand Down Expand Up @@ -335,7 +336,7 @@ static string Encode(long i, string file, string subs, TimeSpan start, TimeSpan
string scale = ArgList.Get(Arg.SCALE).AsString();
if (scale != "no" && !ArgList.Get(Arg.UPSCALE))
{
string oScale = GetScale(file);
string oScale = Ffprober.Probe(file).Scale;
string[] scaleSplit = oScale.Split('x');
if (scaleSplit.Length == 2)
{
Expand Down Expand Up @@ -426,7 +427,7 @@ static string Encode(long i, string file, string subs, TimeSpan start, TimeSpan
}

// Concat
args = $"-hide_banner -y -i \"{webmPath}\" -i \"{oggPath}\" -c copy -metadata title=\"{Path.GetFileNameWithoutExtension(file)} encoded by github.com/CherryPerry/ffmpeg-vp9-wrap\" \"{finalPath}\"";
args = $"-hide_banner -y -i \"{webmPath}\" -i \"{oggPath}\" -c copy -metadata title=\"{Path.GetFileNameWithoutExtension(file)} [github.com/CherryPerry/ffmpeg-vp9-wrap]\" \"{finalPath}\"";
ExecuteFFMPEG(args, pu);

// Delete
Expand All @@ -443,7 +444,7 @@ static string Encode(long i, string file, string subs, TimeSpan start, TimeSpan

static string GetCrop(string file, string start, string t)
{
string args = $"-ss {start} -i \"{file}\" -t {t} -vf cropdetect=24:2:0 -f null NUL";
string args = $"-hide_banner -ss {start} -i \"{file}\" -t {t} -vf cropdetect=24:2:0 -f null NUL";
string cached = Cache.Instance.Get<string>(Cache.CACHE_STRINGS, args);
if (cached == null)
{
Expand Down Expand Up @@ -476,64 +477,63 @@ static string DownloadVideo()
return vd.SavePath;
}

static string GetEndTime(string filePath)
{
string args = $"-v quiet -print_format json -show_format -hide_banner \"{filePath}\"";
string key = args + "DURATION";
string duration = Cache.Instance.Get<string>(Cache.CACHE_STRINGS, key);
if (duration == null)
{
string json = new Executer(Executer.FFPROBE).Execute(args);
JObject root = JObject.Parse(json);
try
{
duration = root["format"]["duration"].ToString();
Cache.Instance.Put(Cache.CACHE_STRINGS, key, duration);
}
catch { }
}
return duration;
}

static void LookupEndTime(string filePath)
{
if (!ArgList.Get(Arg.END_TIME))
{
string value = GetEndTime(filePath);
string value = Ffprober.Probe(filePath).EndTime;
if (value != null)
ArgList.Get(Arg.END_TIME).Value = value;
}
}

// method 1: add preview as separate track with slightly bigger resolution (via Pituz)
static void GeneratePreview(string filePath)
{
OutputProcessor sp = new SimpleProcessor();
ProcessingUnit pu = sp.CreateOne();

string fileName = Path.GetFileName(filePath),
output = filePath.Substring(0, filePath.LastIndexOf('.') + 1) + "preview.webm",
previewSource;
if (!ArgList.Get(Arg.PREVIEW_SOURCE))
previewSource = filePath;
else
previewSource = GetFullPath(ArgList.Get(Arg.PREVIEW_SOURCE).AsString());
string previewTiming = ArgList.Get(Arg.PREVIEW).AsString();
bool previewSourceIsWebm = previewSource.EndsWith("webm");
previewSource = ArgList.Get(Arg.PREVIEW_SOURCE) ? GetFullPath(ArgList.Get(Arg.PREVIEW_SOURCE).AsString()) : filePath,
previewTiming = ArgList.Get(Arg.PREVIEW).AsString();

// preview.webm
// Preview
long time = DateTime.Now.ToFileTimeUtc();
string previewWebm = GetFolder(filePath) + "\\preview_" + time.ToString() + ".webm";
string args;
// TODO: webm copy does not work, increases time of video by 5 second!
if (previewSourceIsWebm && false)
args = $"-hide_banner -ss {previewTiming} -i \"{previewSource}\" -c:v copy -vframes 1 -an -sn \"{previewWebm}\"";
else
{
// Same scale
string scale = GetScale(filePath);
scale = scale == null ? string.Empty : ("-vf scale=" + scale);
args = $"-hide_banner -ss {previewTiming} -i \"{previewSource}\" -c:v vp9 -b:v 0 -crf 4 -vframes 1 -speed 1 -an -sn {scale} \"{previewWebm}\"";
}

// Same scale
Ffprober.Result result = Ffprober.Probe(filePath);
string scale = result.Scale;
scale = scale == null ? string.Empty : $",scale={result.WidthPix + 1}:-1";
scale = $"-filter:v:1 \"trim=end_frame=2{scale}\"";
string args = $"-hide_banner -i \"{filePath}\" -ss {previewTiming} -i \"{previewSource}\" -c copy -map 0:v -map 0:a -map 1:v -c:v:1 vp9 -b:v:1 0 -crf 8 -speed 1 {scale} \"{output}\"";
ExecuteFFMPEG(args, pu);

sp.Destroy(pu);
}

[Obsolete]
static void GeneratePreviewOld(string filePath)
{
OutputProcessor sp = new SimpleProcessor();
ProcessingUnit pu = sp.CreateOne();

string fileName = Path.GetFileName(filePath),
output = filePath.Substring(0, filePath.LastIndexOf('.') + 1) + "preview.webm",
previewSource = ArgList.Get(Arg.PREVIEW_SOURCE) ? GetFullPath(ArgList.Get(Arg.PREVIEW_SOURCE).AsString()) : filePath,
previewTiming = ArgList.Get(Arg.PREVIEW).AsString();

// Preview
long time = DateTime.Now.ToFileTimeUtc();
string previewWebm = GetFolder(filePath) + "\\preview_" + time.ToString() + ".webm";

// Same scale
Ffprober.Result result = Ffprober.Probe(filePath);
string scale = result.Scale;
scale = scale == null ? string.Empty : (",scale=" + scale);
scale = $"-vf \"trim=end_frame=2{scale}\"";
string args = $"-hide_banner -ss {previewTiming} -i \"{previewSource}\" -c:v vp9 -b:v 0 -crf 8 -speed 1 -an -sn {scale} \"{previewWebm}\"";
ExecuteFFMPEG(args, pu);

// Bad muxing fix
Expand All @@ -545,14 +545,13 @@ static void GeneratePreview(string filePath)
string concatedWebm = $"concat_{time}.webm";
string concatFile = $"concat_{time}.txt";
File.WriteAllText(concatFile, $"file '{previewWebm}'\r\nfile '{videoOnly}'", Encoding.Default);
string fps = result.Framerate;
string dur = Ffprober.Probe(previewWebm).EndTime;
if (dur == null)
dur = "0.042";
args = $"-hide_banner -f concat -i \"{concatFile}\" -c copy \"{concatedWebm}\"";
ExecuteFFMPEG(args, pu);

// Audio
string dur = GetEndTime(previewWebm);
if (dur == null)
dur = "00:00.042";
args = $"-hide_banner -y -i \"{concatedWebm}\" -itsoffset {dur} -i \"{filePath}\" -map 0:v -map 1:a -c copy \"{output}\"";
args = $"-hide_banner -y -itsoffset 0.5 -i \"{filePath}\" -i \"{concatedWebm}\" -map 1:v -map 0:a -c copy \"{output}\"";
ExecuteFFMPEG(args, pu);

// Delete
Expand All @@ -564,26 +563,6 @@ static void GeneratePreview(string filePath)
sp.Destroy(pu);
}

static string GetScale(string filePath)
{
string args = $"-v quiet -print_format json -show_streams -hide_banner \"{filePath}\"";
string key = args + "SCALE";
string scale = Cache.Instance.Get<string>(Cache.CACHE_STRINGS, key);
if (scale == null)
{
string json = new Executer(Executer.FFPROBE).Execute(args);
JObject root = JObject.Parse(json);
try
{
var videoStream = root["streams"].Where(x => x["codec_type"].ToString() == "video").First();
scale = $"{videoStream["width"]}:{videoStream["height"]}";
Cache.Instance.Put(Cache.CACHE_STRINGS, key, scale);
}
catch { }
}
return scale;
}

static void ExecuteFFMPEG(string args, ProcessingUnit pu)
{
Process proc = new Process();
Expand Down
1 change: 1 addition & 0 deletions VpxEncode/VpxEncode.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
<Compile Include="Cache.cs" />
<Compile Include="Executer.cs" />
<Compile Include="FfmpegLoader.cs" />
<Compile Include="Ffprober.cs" />
<Compile Include="LinearBitrateLookup.cs" />
<Compile Include="Output\OutputProcessor.cs" />
<Compile Include="Output\PercentedProcessor.cs" />
Expand Down

0 comments on commit c9fb446

Please sign in to comment.