/// <summary> /// Finds the bounds and crops accordingly immediately /// </summary> private void SingleCrop() { bool updateCrop = false; if (LastSwitchedAspectRatio < 0.1f) { LastDetectionResult = false; return; } if (GUIGraphicsContext.RenderBlackImage) { LastDetectionResult = false; return; } Bitmap frame = grabber.GetCurrentImage(); if (frame == null || frame.Height == 0 || frame.Width == 0) { LastDetectionResult = false; return; } Rectangle bounds = new Rectangle(); if (!analyzer.FindBounds(frame, ref bounds)) { LastDetectionResult = false; frame.Dispose(); frame = null; return; } double Hsym = 1.0; double Vsym = 1.0; if (bounds.Left > 20 || ((frame.Width - bounds.Right) > 20 && bounds.Left > 0)) { Hsym = (double)(frame.Width - bounds.Right) / (double)bounds.Left; } if (bounds.Top > 20 || ((frame.Height - bounds.Bottom) > 20 && bounds.Top > 0)) { Vsym = (double)(frame.Height - bounds.Bottom) / (double)bounds.Top; } if (currentSettings.verboseLog) { Log.Debug("ViewModeSwitcher: SingleCrop(), Detected BB -> left: {0}, right: {1}, top: {2}, bottom: {3}, Hsym: {4}, Vsym: {5}", bounds.Left, (frame.Width - bounds.Right), bounds.Top, (frame.Height - bounds.Bottom), Hsym, Vsym); } //Check for symmetry of black bars - asymmetric bars are probably a false detection if ((Hsym > SymLimHigh) || (Hsym < SymLimLow) || (Vsym > SymLimHigh) || (Vsym < SymLimLow)) { if (currentSettings.verboseLog) { Log.Debug("ViewModeSwitcher: SingleCrop(), Symmetry check failed"); } if (NoMatchCropCount < 3) { NoMatchCropCount++; LastDetectionResult = false; } frame.Dispose(); frame = null; return; } //Use the smallest black bar size double cropH = (double)(Math.Min(frame.Width - bounds.Right, bounds.Left)); double cropV = (double)(Math.Min(frame.Height - bounds.Bottom, bounds.Top)); //Check for a close match (within 1% of width/height) to the previous crop values if ((((Math.Abs(cropV - LastRawCropV)) / (double)frame.Height) > 0.01) || (((Math.Abs(cropH - LastRawCropH)) / (double)frame.Width) > 0.01)) { LastRawCropH = cropH; LastRawCropV = cropV; if (NoMatchCropCount < 3) { NoMatchCropCount++; LastDetectionResult = false; } if (currentSettings.verboseLog) { Log.Debug("ViewModeSwitcher: SingleCrop(), No match with last crop : " + NoMatchCropCount); } frame.Dispose(); frame = null; return; } LastRawCropH = cropH; LastRawCropV = cropV; //Work out actual picture aspect ratio double newasp = ((double)frame.Width - cropH * 2) / ((double)frame.Height - cropV * 2); bool checkPBv = false; if (LastAnamorphFactor > 0.0) { //Correction for anamorphic video i.e. when pixel aspect ratio != video aspect ratio. newasp *= LastAnamorphFactor; //Check for letterbox/pillarbox video if (LastSwitchedAspectRatio > 1.68 && LastSwitchedAspectRatio < 1.87) { if ((cropV / (double)frame.Height < 0.02) && newasp > 1.2 && newasp < 1.46) { checkPBv = true; } else if ((cropH / (double)frame.Width < 0.02) && newasp > 2.1 && newasp < 2.57) { checkPBv = true; } } else if (LastSwitchedAspectRatio > 1.25 && LastSwitchedAspectRatio < 1.41) { if ((cropH / (double)frame.Width < 0.02) && newasp > 1.47 && newasp < 1.95) { checkPBv = true; } else if ((cropH / (double)frame.Width < 0.02) && newasp > 2.1 && newasp < 2.57) { checkPBv = true; } } //After this correction, cropH value is in 'real' video pixels, not source pixels cropH *= LastAnamorphFactor; } if (newasp < 1.1 || newasp > 2.7) // faulty crop { if (NoMatchCropCount < 3) { NoMatchCropCount++; LastDetectionResult = false; } frame.Dispose(); frame = null; return; } NoMatchCropCount = 0; if (currentSettings.verboseLog) { Log.Debug("ViewModeSwitcher: SingleCrop(), Video AR: {0}, Cropped AR: {1}", LastSwitchedAspectRatio, newasp); } //Check for 'Pillar Boxed' 4:3 inside 16:9 video, and 'Letter Boxed' 16:9 inside 4:3 video if (CheckRulesPBLB(-newasp, frame.Width, frame.Height, checkPBv)) { if (LastSwitchedGeometry != Geometry.Type.NonLinearStretch) { //NonLinearStretch needs full side bar cropping, other modes don't cropH = overScan; cropV = overScan / LastSwitchedAspectRatio; } else { //Add overscan to NonLinearStretch cropH += overScan; cropV += overScan / LastSwitchedAspectRatio; } if (!isPBorLB) //Only update on first detection { updateCrop = true; } isPBorLB = true; } else //Normal video cropping { //Use overscan cropping if larger than detected black bars cropH = Math.Max(cropH, overScan); cropV = Math.Max(cropV, overScan / LastSwitchedAspectRatio); if (isPBorLB) { if (currentSettings.verboseLog) { Log.Debug("ViewModeSwitcher: SingleCrop(), PillarBox -> Normal"); } //Force CheckAspectRatios() update updatePending = false; isPBorLB = false; LastSwitchedAspectRatio = 0.0; frame.Dispose(); frame = null; return; } isPBorLB = false; } if (currentSettings.verboseLog) { Log.Debug("ViewModeSwitcher: SingleCrop(), Real cropH: {0}, cropV: {1}", cropH, cropV); } if ((Math.Abs(cropH - fCropH) > 5) || (Math.Abs(cropV - fCropV) > 3)) { fCropH = cropH; fCropV = cropV; updateCrop = true; } if (updateCrop) { updatePending = true; } frame.Dispose(); frame = null; }
/// <summary> /// Finds the bounds and crops accordingly immediately /// </summary> private void SingleCrop() { if (GUIGraphicsContext.RenderBlackImage) { LastDetectionResult = false; return; } Bitmap frame = grabber.GetCurrentImage(); if (frame == null || frame.Height == 0 || frame.Width == 0) { LastDetectionResult = false; return; } Rectangle bounds = new Rectangle(); if (!analyzer.FindBounds(frame, ref bounds)) { LastDetectionResult = false; return; } int cropH = Math.Min(GUIGraphicsContext.VideoSize.Width - bounds.Right, bounds.Left); if (cropH < overScan) { cropH = overScan; } int cropV = Math.Min(GUIGraphicsContext.VideoSize.Height - bounds.Bottom, bounds.Top); if (cropV < overScan / LastSwitchedAspectRatio) { cropV = (int)(overScan / LastSwitchedAspectRatio); } if (cropV > cropH / LastSwitchedAspectRatio) { cropV = (int)(cropH / LastSwitchedAspectRatio); } float newasp = (float)(frame.Width - cropH * 2) / (float)(frame.Height - cropV * 2); if (newasp < 1) // faulty crop { cropH = overScan; cropV = (int)(overScan / LastSwitchedAspectRatio); } if (cropH != cropSettings.Left || cropV != cropSettings.Top) { cropSettings.Top = cropV; //bounds.Top; cropSettings.Bottom = cropV; // GUIGraphicsContext.VideoSize.Height - (bounds.Bottom + 1); cropSettings.Left = cropH; // bounds.Left; cropSettings.Right = cropH; // GUIGraphicsContext.VideoSize.Width - (bounds.Right + 1); SetCropMode(); } if (newasp >= 1) { float asp = (float)(frame.Width) / (float)(frame.Height); //Log.Debug("asp: {0}, newasp: {1}", asp, newasp); if (Math.Abs(asp - newasp) > 0.2 && LastSwitchedAspectRatio > 1.5) { SetAspectRatio("4:3 inside 16:9", Geometry.Type.NonLinearStretch); } } frame.Dispose(); frame = null; }