Example #1
0
        // 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 = 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={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);
        }
Example #2
0
        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 -pix_fmt +yuv420p -b:v 0 -crf 8 -speed 1 -an -sn {scale} \"{previewWebm}\"";
              ExecuteFFMPEG(args, pu);

              // Bad muxing fix
              string videoOnly = $"video_{time}.webm";
              args = $"-hide_banner -i \"{filePath}\" -c copy -map 0:v \"{videoOnly}\"";
              ExecuteFFMPEG(args, pu);

              // Concat
              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);
              args = $"-hide_banner -y -itsoffset 0.5 -i \"{filePath}\" -i \"{concatedWebm}\" -map 1:v -map 0:a -c copy \"{output}\"";
              ExecuteFFMPEG(args, pu);

              // Delete
              File.Delete(concatFile);
              File.Delete(previewWebm);
              File.Delete(concatedWebm);
              File.Delete(videoOnly);

              sp.Destroy(pu);
        }
Example #3
0
        static string Encode(long i, string file, string subs, TimeSpan start, TimeSpan end, int sizeLimit, int crf)
        {
            // subs = *.ass
              if (subs != null && subs.StartsWith("*"))
            subs = file.Substring(0, file.LastIndexOf('.')) + subs.Substring(1);

              // subs = same
              if (subs == "same")
            subs = file;

              bool subsWereCopied = false;
              string subsFilename = Path.GetFileName(subs);
              if (ArgList.Get(Arg.FIX_SUBS) && SubStationAlpha.IsAcceptable(subs))
              {
            string subsNew = Path.Combine(Environment.CurrentDirectory, subsFilename);
            subsFilename += i.ToString() + "_ARIAL.ass";
            SubStationAlpha ssa = new SubStationAlpha(subs);
            ssa.ChangeFontAndSave(subsNew);
            subs = subsNew;
            subsWereCopied = true;
              }

              string code = null;
              if (i < 10000)
            code = $"{i}_{DateTime.Now.ToFileTimeUtc()}";
              else
            code = i.ToString();

              string filePath = GetFolder(file),
             webmPath = Path.Combine(filePath, $"temp_{code}.webm"),
             oggPath = Path.Combine(filePath, $"temp_{code}.ogg"),
             finalPath = Path.Combine(filePath, $"{ArgList.Get(Arg.NAME_PREFIX).AsString()}{code}.webm");

              TimeSpan timeLength = end - start;
              string startString = start.ToString("hh\\:mm\\:ss\\.fff"),
             timeLengthString = timeLength.ToString("hh\\:mm\\:ss\\.fff");

              OutputProcessor sp = new SimpleProcessor();
              ProcessingUnit pu = sp.CreateOne();

              // Audio settings
              string mapAudio = ArgList.Get(Arg.MAP_AUDIO) ? $"-map 0:a:{ArgList.Get(Arg.MAP_AUDIO).AsInt()}" : string.Empty;
              int opusRate = ArgList.Get(Arg.OPUS_RATE).AsInt();
              string audioFile = ArgList.Get(Arg.AUDIO_FILE) ? GetFullPath(ArgList.Get(Arg.AUDIO_FILE).AsString()) : file;
              string otherAudio = ArgList.Get(Arg.OTHER_AUDIO).AsString();
              int vorbis = ArgList.Get(Arg.VORBIS) ? ArgList.Get(Arg.VORBIS).AsInt() : -1;
              string codecParams = vorbis == -1 ? $"-c:a opus -b:a {opusRate}K -vbr on" : $"-c:a libvorbis -q:a {vorbis}";

              // Encode audio
              string args = $"-hide_banner -y -ss {startString} -i \"{audioFile}\" {mapAudio} -ac 2 {codecParams} -vn -sn -t {timeLengthString} {otherAudio} \"{oggPath}\"";

              // Audio cache
              Cache.ACKey aKey = new Cache.ACKey(args);
              bool aCached = Cache.Instance.CreateIfPossible(aKey, oggPath);
              if (!aCached)
              {
            ExecuteFFMPEG(args, pu);
            Cache.Instance.Save(aKey, oggPath);
              }

              // No upscale check
              string scale = ArgList.Get(Arg.SCALE).AsString();
              if (scale != "no" && !ArgList.Get(Arg.UPSCALE))
              {
            string oScale = Ffprober.Probe(file).Scale;
            string[] scaleSplit = oScale.Split('x');
            if (scaleSplit.Length == 2)
            {
              int oWidth = int.Parse(scaleSplit[0]);
              int oHeight = int.Parse(scaleSplit[1]);
              scaleSplit = scale.Split(':');
              int width = int.Parse(scaleSplit[0]);
              int height = int.Parse(scaleSplit[1]);
              if (width > oWidth || height > oHeight)
            scale = "no";
            }
              }

              // VideoFilter
              const string vfDefault = "-vf \"";
              StringBuilder vf = new StringBuilder(vfDefault);
              Action addSubs = () =>
              {
            if (subs != null)
            {
              string format = subs.EndsWith("ass") || subs.EndsWith("ssa") ? "ass='{0}'{1}" : "subtitles='{0}'{1}";
              format = string.Format(format, subs.Replace(@"\", @"\\").Replace(":", @"\:"), ArgList.Get(Arg.SUBS_INDEX).Command);
              format = string.Format(new CultureInfo("en"), "setpts=PTS+{0:0.######}/TB,{1},setpts=PTS-STARTPTS", start.TotalSeconds, format);
              vf.AppendIfPrev(",").AppendForPrev(format);
            }
              };
              Action addScale = () =>
              {
            if (scale != "no")
              vf.AppendIfPrev(",").AppendForPrev($"scale={scale}:sws_flags=lanczos");
              };

              if (ArgList.Get(Arg.CROP))
              {
            string crop = GetCrop(file, startString, timeLengthString);
            if (crop != null)
              vf.AppendIfPrev(",").AppendForPrev(crop);
            pu.Write("CROP: " + crop);
              }
              if (ArgList.Get(Arg.CROP_V))
            vf.AppendIfPrev(",").AppendForPrev("crop=" + ArgList.Get(Arg.CROP_V).AsString());
              if (ArgList.Get(Arg.SUBS_FIRST))
              {
            addSubs();
            addScale();
              }
              else
              {
            addScale();
            addSubs();
              }

              if (vf.Length == vfDefault.Length)
            vf.Clear();
              else
            vf.Append("\" ");

              // Encode 2-pass video
              StringBuilder otherVideo = new StringBuilder();
              otherVideo.AppendForPrev(ArgList.Get(Arg.OTHER_VIDEO).AsString()).AppendIfPrev(" ");

              if (crf < 4 || crf > 63)
              {
            crf = ushort.MaxValue;
            if (ArgList.Get(Arg.CRF_MODE))
              try { crf = ushort.Parse(ArgList.Get(Arg.CRF_MODE).Value); if (crf < 4 || crf > 63) crf = ushort.MaxValue; }
              catch { }
              }

              string threadSettings;
              if (ArgList.Get(Arg.SINGLE_THREAD))
            threadSettings = "-tile-columns 0 -frame-parallel 0 -threads 1 -speed 1";
              else
            threadSettings = $"-tile-columns {Environment.ProcessorCount} -frame-parallel 1 -threads {Environment.ProcessorCount} -speed 1";

              // Pass 1 cache
              string logPath = Path.Combine(Environment.CurrentDirectory, $"temp_{code}-0.log");
              Cache.FPCKey key = new Cache.FPCKey(file, vf.ToString(), startString, timeLengthString);
              bool cached = Cache.Instance.CreateIfPossible(key, logPath);

              // If CRF_MODE
              if (crf != ushort.MaxValue)
              {
            if (!cached)
            {
              args = $"-hide_banner -y -ss {startString} -i \"{file}\" -c:v vp9 -pix_fmt +yuv420p {vf} -crf {crf} -b:v 0 {threadSettings} -an -t {timeLengthString} -sn -lag-in-frames 25 -pass 1 -auto-alt-ref 1 -passlogfile temp_{code} -f null -y NUL";
              ExecuteFFMPEG(args, pu);
              Cache.Instance.Save(key, logPath);
            }

            args = $"-hide_banner -y -ss {startString} -i \"{file}\" -c:v vp9 -pix_fmt +yuv420p {vf} -crf {crf} -b:v 0 {threadSettings} -an -t {timeLengthString} -sn -lag-in-frames 25 -pass 2 -auto-alt-ref 1 -passlogfile temp_{code} \"{webmPath}\"";
            ExecuteFFMPEG(args, pu);
              }
              else
              {
            double audioSize = GetSizeKB(oggPath);
            int bitrate = (int)((sizeLimit - audioSize) * 8 / timeLength.TotalSeconds);
            string bitrateString = $"-b:v {bitrate}K";

            if (!cached)
            {
              args = $"-hide_banner -y -ss {startString} -i \"{file}\" -c:v vp9 -pix_fmt +yuv420p {bitrateString} {threadSettings} -an {vf} -t {timeLengthString} -sn {otherVideo} -lag-in-frames 25 -pass 1 -auto-alt-ref 1 -passlogfile temp_{code} -f null -y NUL";
              ExecuteFFMPEG(args, pu);
              Cache.Instance.Save(key, logPath);
            }

            args = $"-hide_banner -y -ss {startString} -i \"{file}\" -c:v vp9 -pix_fmt +yuv420p {bitrateString} {threadSettings} -an {vf} -t {timeLengthString} -sn {otherVideo} -lag-in-frames 25 -pass 2 -auto-alt-ref 1 -passlogfile temp_{code} \"{webmPath}\"";
            ExecuteFFMPEG(args, pu);
              }

              // Concat
              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
              if (subsWereCopied)
            File.Delete(subs);
              File.Delete(webmPath);
              File.Delete(oggPath);
              File.Delete(logPath);

              sp.Destroy(pu);

              return finalPath;
        }