Esempio n. 1
0
        private void GenerateShotChanges(string videoFileName)
        {
            var shotChangesGenerator = new ShotChangesGenerator();
            var threshold            = 0.4m;

            if (decimal.TryParse(Configuration.Settings.General.FFmpegSceneThreshold, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var d))
            {
                threshold = d;
            }
            using (var process = shotChangesGenerator.GetProcess(videoFileName, threshold))
            {
                while (!process.HasExited)
                {
                    Application.DoEvents();
                    System.Threading.Thread.Sleep(100);
                    if (_abort)
                    {
                        DialogResult = DialogResult.Cancel;
                        process.Kill();
                        return;
                    }
                }
            }
            var seconds = ShotChangesGenerator.GetSeconds(shotChangesGenerator.GetTimeCodesString().SplitToLines().ToArray());

            if (seconds.Count > 0)
            {
                ShotChangeHelper.SaveShotChanges(videoFileName, seconds);
            }
        }
Esempio n. 2
0
        private void RefreshCheckBoxes(string language)
        {
            _netflixQualityController = new NetflixQualityController {
                Language = language, VideoFileName = _videoFileName, FrameRate = _frameRate
            };

            checkBoxNoItalics.Checked = !_netflixQualityController.AllowItalics;
            checkBoxNoItalics.Enabled = !_netflixQualityController.AllowItalics;

            int halfSecGapInFrames = (int)Math.Round(_frameRate / 2, MidpointRounding.AwayFromZero);

            checkBoxGapBridge.Text = $"Frame gap: 3 to {halfSecGapInFrames - 1} frames => 2 frames";

            var shotChangesExist = false;

            if (_netflixQualityController.VideoExists)
            {
                if (ShotChangeHelper.FromDisk(_videoFileName).Count > 0)
                {
                    shotChangesExist = true;
                }
            }
            checkBoxShotChange.Checked = shotChangesExist;
            checkBoxShotChange.Enabled = shotChangesExist;

            var checkFrameRate = _subtitleFormat.GetType() == new NetflixTimedText().GetType();

            checkBoxTtmlFrameRate.Checked = checkFrameRate;
            checkBoxTtmlFrameRate.Enabled = checkFrameRate;

            var speakerStyle             = _netflixQualityController.SpeakerStyle;
            var checkBoxSpeakerStyleText = "Dual Speakers: Use a hyphen without a space";

            if (speakerStyle == DialogType.DashBothLinesWithSpace)
            {
                checkBoxSpeakerStyleText = "Dual Speakers: Use a hyphen with a space";
            }
            else if (speakerStyle == DialogType.DashSecondLineWithSpace)
            {
                checkBoxSpeakerStyleText = "Dual Speakers: Use a hyphen with a space to denote the second speaker only";
            }
            else if (speakerStyle == DialogType.DashSecondLineWithoutSpace)
            {
                checkBoxSpeakerStyleText = "Dual Speakers: Use a hyphen without a space to denote the second speaker only";
            }

            checkBoxSpeakerStyle.Text = checkBoxSpeakerStyleText;

            checkBox17CharsPerSecond.Text = string.Format(LanguageSettings.Current.NetflixQualityCheck.MaximumXCharsPerSecond, _netflixQualityController.CharactersPerSecond);
            checkBoxMaxLineLength.Text    = string.Format(LanguageSettings.Current.NetflixQualityCheck.MaximumLineLength, _netflixQualityController.SingleLineMaxLength);
        }
        public void Check(Subtitle subtitle, NetflixQualityController controller)
        {
            if (!controller.VideoExists)
            {
                return;
            }

            var shotChanges = ShotChangeHelper.FromDisk(controller.VideoFileName);

            if (shotChanges == null || shotChanges.Count == 0)
            {
                return;
            }

            if (Configuration.Settings.General.CurrentVideoIsSmpte)
            {
                shotChanges = shotChanges.Select(sc => sc /= 1.001).ToList();
            }

            int    halfSecGapInFrames = (int)Math.Round(controller.FrameRate / 2, MidpointRounding.AwayFromZero);
            double twoFramesGap       = 1000.0 / controller.FrameRate * 2.0;

            foreach (Paragraph p in subtitle.Paragraphs)
            {
                var    fixedParagraph = new Paragraph(p, false);
                string comment        = string.Empty;

                List <double> previousStartShotChanges = shotChanges.Where(x => SubtitleFormat.MillisecondsToFrames(x * 1000) < SubtitleFormat.MillisecondsToFrames(p.StartTime.TotalMilliseconds)).ToList();
                List <double> nextStartShotChanges     = shotChanges.Where(x => SubtitleFormat.MillisecondsToFrames(x * 1000) > SubtitleFormat.MillisecondsToFrames(p.StartTime.TotalMilliseconds)).ToList();
                List <double> previousEndShotChanges   = shotChanges.Where(x => SubtitleFormat.MillisecondsToFrames(x * 1000) < SubtitleFormat.MillisecondsToFrames(p.EndTime.TotalMilliseconds)).ToList();
                List <double> nextEndShotChanges       = shotChanges.Where(x => SubtitleFormat.MillisecondsToFrames(x * 1000) > SubtitleFormat.MillisecondsToFrames(p.EndTime.TotalMilliseconds)).ToList();
                var           onShotChange             = shotChanges.FirstOrDefault(x => SubtitleFormat.MillisecondsToFrames(x * 1000) == SubtitleFormat.MillisecondsToFrames(p.EndTime.TotalMilliseconds));

                if (previousStartShotChanges.Count > 0)
                {
                    double nearestStartPrevShotChange = previousStartShotChanges.Aggregate((x, y) => Math.Abs(x - p.StartTime.TotalSeconds) < Math.Abs(y - p.StartTime.TotalSeconds) ? x : y);
                    if (SubtitleFormat.MillisecondsToFrames(p.StartTime.TotalMilliseconds - nearestStartPrevShotChange * 1000) < halfSecGapInFrames)
                    {
                        fixedParagraph.StartTime.TotalMilliseconds = nearestStartPrevShotChange * 1000;
                        comment = $"The in-cue is within {halfSecGapInFrames} frames after the shot change, snap the in-cue to the shot-change";
                        controller.AddRecord(p, fixedParagraph, comment);
                    }
                }

                if (nextStartShotChanges.Count > 0)
                {
                    double nearestStartNextShotChange = nextStartShotChanges.Aggregate((x, y) => Math.Abs(x - p.StartTime.TotalSeconds) < Math.Abs(y - p.StartTime.TotalSeconds) ? x : y);
                    var    gapToShotChange            = SubtitleFormat.MillisecondsToFrames(nearestStartNextShotChange * 1000 - p.StartTime.TotalMilliseconds);
                    var    threshold = (int)Math.Round(halfSecGapInFrames * 0.75, MidpointRounding.AwayFromZero);
                    if (gapToShotChange != 0 && gapToShotChange < halfSecGapInFrames)
                    {
                        if (gapToShotChange < threshold)
                        {
                            fixedParagraph.StartTime.TotalMilliseconds = nearestStartNextShotChange * 1000;
                            comment = $"The in-cue is 1-{threshold - 1} frames before the shot change, snap the in-cue to the shot change";
                        }
                        else
                        {
                            fixedParagraph.StartTime.TotalMilliseconds = nearestStartNextShotChange * 1000 - (1000.0 / controller.FrameRate * halfSecGapInFrames);
                            comment = $"The in-cue is {threshold}-{halfSecGapInFrames - 1} frames before the shot change, pull the in-cue to half a second ({halfSecGapInFrames} frames) before the shot-change";
                        }

                        controller.AddRecord(p, fixedParagraph, comment);
                    }
                }

                if (previousEndShotChanges.Count > 0)
                {
                    double nearestEndPrevShotChange = previousEndShotChanges.Aggregate((x, y) => Math.Abs(x - p.EndTime.TotalSeconds) < Math.Abs(y - p.EndTime.TotalSeconds) ? x : y);
                    if (SubtitleFormat.MillisecondsToFrames(p.EndTime.TotalMilliseconds - nearestEndPrevShotChange * 1000) < halfSecGapInFrames)
                    {
                        fixedParagraph.EndTime.TotalMilliseconds = nearestEndPrevShotChange * 1000 - twoFramesGap;
                        comment = $"The out-cue is within {halfSecGapInFrames} frames after the shot change";
                        controller.AddRecord(p, fixedParagraph, comment);
                    }
                }

                if (nextEndShotChanges.Count > 0)
                {
                    double nearestEndNextShotChange = nextEndShotChanges.Aggregate((x, y) => Math.Abs(x - p.EndTime.TotalSeconds) < Math.Abs(y - p.EndTime.TotalSeconds) ? x : y);
                    if (SubtitleFormat.MillisecondsToFrames(nearestEndNextShotChange * 1000 - p.EndTime.TotalMilliseconds) < halfSecGapInFrames &&
                        SubtitleFormat.MillisecondsToFrames(nearestEndNextShotChange * 1000 - p.EndTime.TotalMilliseconds) < 2)
                    {
                        fixedParagraph.EndTime.TotalMilliseconds = nearestEndNextShotChange * 1000 - twoFramesGap;
                        comment = $"The out-cue is within {halfSecGapInFrames} frames of the shot change";
                        controller.AddRecord(p, fixedParagraph, comment);
                    }
                }

                if (onShotChange > 0)
                {
                    fixedParagraph.EndTime.TotalMilliseconds = onShotChange * 1000 - twoFramesGap;
                    comment = "The out-cue is on the shot change, respect the two-frame gap";
                    controller.AddRecord(p, fixedParagraph, comment);
                }
            }
        }