Esempio n. 1
0
        private async void CalculateAudioGain_Click(object sender, RoutedEventArgs e)
        {
            CalculateAudioGain.IsEnabled = false;
            CalculateAudioGain.Content   = "Wait";
            float?Gain = await Task.Run(() => AvisynthTools.GetAudioGain(encodeSettings.FilePath, null));

            if (Gain.HasValue)
            {
                encodeSettings.AudioGain = Gain;
            }
            CalculateAudioGain.IsEnabled = true;
            CalculateAudioGain.Content   = "Auto";
        }
        public CompletionStatus GenerateDeshakerLog(MediaEncoderSettings settings, string inputFile) {
            // Prepare Deshaker settings.
            settings.DeshakerSettings.Pass = 1;
            settings.DeshakerSettings.LogFile = settings.DeshakerTempLog;
            settings.DeshakerSettings.SourcePixelAspectRatio = settings.SourceAspectRatio.Value;
            // settings.DeshakerSettings.AppendToFile = true;
            File.Delete(settings.DeshakerLog);

            // Start UI.
            CompletionStatus Result = CompletionStatus.Success;
            object JobId = "Deshaker";
            FFmpegConfig.UserInterfaceManager.Start(JobId, "Running Deshaker Prescan");
            ProcessStartOptions JobOptions = new ProcessStartOptions(JobId, "Getting Frame Count", false);

            // Get frame count.
            settings.CalculateSize();
            int FrameStart = (int)((settings.DeshakerSettings.PrescanStart ?? 0) * settings.SourceFrameRate.Value);
            int FrameEnd = (int)((settings.DeshakerSettings.PrescanEnd ?? 0) * settings.SourceFrameRate.Value);
            string Script = MediaEncoderScript.GenerateDeshakerScript(settings, inputFile, 0, FrameStart, FrameEnd);
            File.WriteAllText(settings.DeshakerScript, Script);
            JobOptions.FrameCount = AvisynthTools.GetFrameCount(settings.DeshakerScript, JobOptions);

            // Pad file start.
            using (StreamWriter sw = new StreamWriter(File.Open(settings.DeshakerLog, FileMode.Create), Encoding.ASCII)) {
                for (int i = 0; i < FrameStart; i++) {
                    sw.WriteLine((i + 1).ToString().PadLeft(7) + "									skipped		#	   0.00	   0.00	");
                }
            }

            // Run segments.
            var Segments = settings.DeshakerSettings.Segments;
            if (JobOptions.FrameCount > 0) {
                for (int i = 0; i < Segments.Count; i++) {
                    // Get start position of next segment.
                    long NextSegmentStart = i < Segments.Count - 1 ? Segments[i + 1].FrameStart : 0;
                    if (NextSegmentStart == 0 || NextSegmentStart > FrameStart) { // Enforce PrescanStart for preview
                        long SegmentStart = Segments[i].FrameStart;
                        long SegmentEnd = NextSegmentStart > 0 ? NextSegmentStart - 1 : 0;
                        // Enforce PrescanEnd for preview
                        if ((FrameEnd > 0 && SegmentStart > FrameEnd) || (SegmentEnd > 0 && SegmentStart > SegmentEnd))
                            break;
                        if ((FrameStart > 0 && FrameStart > SegmentStart) || SegmentStart == 0)
                            SegmentStart = FrameStart;
                        if ((FrameEnd > 0 && FrameEnd < SegmentEnd) || SegmentEnd == 0)
                            SegmentEnd = FrameEnd;
                        Result = GenerateDeshakerLogSegment(settings, inputFile, i, FrameStart, SegmentStart, SegmentEnd, JobOptions);
                        if (Result != CompletionStatus.Success)
                            break;

                        // Merge log segment into log file and set right frame numbers.
                        using (StreamWriter sw = new StreamWriter(File.Open(settings.DeshakerLog, FileMode.Append), Encoding.ASCII)) {
                            using (StreamReader sr = new StreamReader(File.OpenRead(settings.DeshakerTempLog), Encoding.ASCII)) {
                                string LogLine, LogNum, LogNumField, LineOut;
                                long NewLineNum = SegmentStart;
                                LogLine = sr.ReadLine();
                                while (LogLine != null) {
                                    if (LogLine.Length > 7) {
                                        LogNum = LogLine.Substring(0, 7).Trim();
                                        if (LogNum.Length > 0) {
                                            LogNumField = LogNum[LogNum.Length - 1].ToString();
                                            if (LogNumField != "A" && LogNumField != "B") // For interlaced videos
                                                LogNumField = "";
                                            NewLineNum++; // Log file starts at 1, not 0.
                                            LineOut = (NewLineNum.ToString() + LogNumField).PadLeft(7) + LogLine.Substring(7, LogLine.Length - 8);
                                            sw.WriteLine(LineOut);
                                        }
                                    }
                                    LogLine = sr.ReadLine();
                                }
                            }
                        }
                        File.Delete(settings.DeshakerTempLog);
                    }
                }
            } else
                Result = CompletionStatus.Error;

            // End UI.
            FFmpegConfig.UserInterfaceManager.Stop(JobId);
            return Result;
        }
        /// <summary>
        /// Analyzes output files to determine what work is done and what needs to be done.
        /// </summary>
        /// <param name="settings">The media encoder settings of the job to scan.</param>
        /// <returns>Whether job needs to execute.</returns>
        public void Analyze(MediaEncoderSettings settings)
        {
            int Threads = settings.ParallelProcessing;

            if (Threads == 0)
            {
                Threads = 1;
            }
            this.settings = settings;
            SegDone       = new List <SegmentInfo>();
            SegLeft       = new List <SegmentInfo>();

            // Get script total frame count, and run in background until all other files are scanned.
            EncoderBusiness.EditStartPosition(settings.ScriptFile, 0, 0);
            ProcessStartOptions Options   = new ProcessStartOptions(settings.JobIndex, "Analyzing Segments...", false).TrackProcess(settings);
            Task <long>         TaskCount = Task.Run(() => AvisynthTools.GetFrameCount(settings.ScriptFile, Options));

            // Get list of output files in folder. The number after "_Output_" is the frame position of that segment.
            string FileName    = string.Format("Job{0}_Output_", settings.JobIndex);
            string FileNameExt = string.Format(".{0}", settings.Container);

            string[] SegFiles = Directory.GetFiles(PathManager.TempFilesPath, FileName + "*" + FileNameExt);

            // Scan each segment file and discard files smaller than 10kb or of less than 10 frames.
            // Create a list of tasks to run them all in parallel.
            List <Task <KeyValuePair <string, long> > > TaskList = new List <Task <KeyValuePair <string, long> > >();

            foreach (string seg in SegFiles)
            {
                if (settings.CompletionStatus == CompletionStatus.Cancelled)
                {
                    break;
                }
                // Discard empty files.
                if (new FileInfo(seg).Length > 0)
                {
                    // string SegmentLocal = seg;
                    TaskList.Add(Task.Run(() => {
                        return(new KeyValuePair <string, long>(seg, MediaInfo.GetFrameCount(seg, null)));
                    }));
                }
                else
                {
                    File.Delete(seg);
                }
            }

            // Run all segment length queries simultaneously and analyze results to fill SegDone.
            Task.WaitAll(TaskList.ToArray());
            string SegFile;
            long   SegStart;
            bool   SegAdded;
            int    Pos;
            string SegText;

            if (settings.CompletionStatus != CompletionStatus.Cancelled)
            {
                foreach (var item in TaskList)
                {
                    SegFile  = item.Result.Key;
                    SegStart = 0;
                    SegAdded = false;
                    if (item.Result.Value >= 1)   // Segment must contain at least one valid frame.
                    {
                        Pos = SegFile.IndexOf(FileName);
                        if (Pos > -1)
                        {
                            Pos    += FileName.Length;
                            SegText = SegFile.Substring(Pos, SegFile.Length - Pos - FileNameExt.Length);
                            if (long.TryParse(SegText, out SegStart))
                            {
                                SegDone.Add(new SegmentInfo(SegStart, SegStart + item.Result.Value));
                                SegAdded = true;
                            }
                        }
                    }
                    if (!SegAdded)
                    {
                        File.Delete(SegFile);
                    }
                }
                // Order can be random, must sort.
                SegDone = SegDone.OrderBy(s => s.Start).ToList();
            }

            // Get script total frames and calculate the work left.
            TaskCount.Wait();
            if (settings.CompletionStatus == CompletionStatus.Cancelled)
            {
                SegDone.Clear();
            }
            else
            {
                // Create list of segments left.
                TotalFrames = TaskCount.Result;
                long SegPos = 0;
                foreach (SegmentInfo segd in SegDone)
                {
                    if (segd.Start > SegPos)
                    {
                        SegLeft.Add(new SegmentInfo(SegPos, segd.Start - 1));
                    }
                    SegPos = segd.End + 1;
                }
                if (SegPos < TotalFrames)
                {
                    SegLeft.Add(new SegmentInfo(SegPos, TotalFrames - 1));
                }

                if (settings.ParallelProcessing > 1)
                {
                    // Divide in segments
                    int         Instances    = settings.ParallelProcessing;
                    int         SmallSegSize = SegSize / Instances;
                    int         StartSegSize = ((Instances - 1) * Instances / 2) * SmallSegSize;
                    SegmentInfo Seg;
                    int         SegCount = 0;
                    long        IdealSeg, AvailSeg;

                    // Work on copy because original list will be modified.
                    List <SegmentInfo> SegLeftCopy = SegLeft.ToList();
                    SegLeft.Clear();

                    for (int i = 0; i < SegLeftCopy.Count(); i++)
                    {
                        Seg      = SegLeftCopy[i];
                        AvailSeg = Seg.Length;
                        while (AvailSeg > 0)
                        {
                            // Start with smaller segments.
                            IdealSeg = SegCount < Instances ? ++SegCount * SmallSegSize : SegSize;
                            // Split segment only if it is larger than threshold
                            if (AvailSeg > IdealSeg + SmallSegSize)
                            {
                                SegLeft.Add(new SegmentInfo(Seg.Start, Seg.Start + IdealSeg - 1));
                                Seg.Start += IdealSeg;
                                AvailSeg  -= IdealSeg;
                            }
                            else
                            {
                                SegLeft.Add(new SegmentInfo(Seg.Start, Seg.End));
                                AvailSeg = 0;
                            }
                        }
                    }

                    // If we're still missing segments (for short clips), split using other method.
                    // Create segments to reach the desired amount of threads.
                    int SegMissing = SegLeft.Count > 0 ? Threads - SegLeft.Count() : 0;
                    for (int i = 0; i < SegMissing; i++)
                    {
                        // Find largest segment.
                        int  SegMaxIndex = 0;
                        long SegMax      = SegLeft[0].Length;
                        for (int j = 1; j < SegLeft.Count(); j++)
                        {
                            if (SegLeft[j].Length > SegMax)
                            {
                                SegMaxIndex = j;
                                SegMax      = SegLeft[j].Length;
                            }
                        }
                        // Split largest segment in half.
                        Seg = SegLeft[SegMaxIndex];
                        if (Seg.Length > 80)   // Only split if segment has at least 80 frames (creating segments of 40).
                        {
                            long SegSep = Seg.Start + (Seg.Length - 1) / 2;
                            SegLeft[SegMaxIndex] = new SegmentInfo(Seg.Start, SegSep);
                            SegLeft.Insert(SegMaxIndex + 1, new SegmentInfo(SegSep + 1, Seg.End));
                        }
                    }
                }
            }
        }