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 void LookupEndTime(string filePath)
 {
     if (!ArgList.Get(Arg.END_TIME))
     {
         string value = Ffprober.Probe(filePath).EndTime;
         if (value != null)
         {
             ArgList.Get(Arg.END_TIME).Value = value;
         }
     }
 }
Example #4
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);
        }