I am very new to Metal, but diligently working to follow Apple's AVCamFilter sample project. The project demonstrates using a MTKView as a preview for an AVCaptureSession.
I have been unsuccessful in figuring out how to have my MTKView render "full screen" (specifically on iPhone X, XS, and 3rd generation iPad Pro). While my constraints are set properly in the Storyboard, my camera preview is scaled to a different aspect ratio, and not full screen.
As a test, I set;
self.clearColor = MTLClearColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
in my MTKView's init, confirming that the MTKView is the proper size (I can see the red background in the problematic areas, but my camera preview does not stretch to fill the screen).
I am of the belief that my issue exists in this calculation;
// Calculate scale.
if textureWidth > 0 && textureHeight > 0 {
switch textureRotation {
case .rotate0Degrees, .rotate180Degrees:
scaleX = Float(internalBounds.width / CGFloat(textureWidth))
scaleY = Float(internalBounds.height / CGFloat(textureHeight))
case .rotate90Degrees, .rotate270Degrees:
scaleX = Float(internalBounds.width / CGFloat(textureHeight))
scaleY = Float(internalBounds.height / CGFloat(textureWidth))
}
}
// Resize aspect ratio.
resizeAspect = min(scaleX, scaleY)
if scaleX < scaleY {
scaleY = scaleX / scaleY
scaleX = 1.0
} else {
scaleX = scaleY / scaleX
scaleY = 1.0
}
In my test environment, my texture size is 2400x1800 and my internal bounds are 834x1194. While I recognize the difference in aspect ratio, I am trying to figure out the correct math to have the texture fill the entire display (even if that means it is scaled slightly less and I lose some of the texture on the sides).
Could anyone advise? Thanks!
// Resize aspect ratio.
resizeAspect = min(scaleX, scaleY)
if scaleX < scaleY {
scaleY = scaleX / scaleY
scaleX = 1.0
} else {
scaleX = scaleY / scaleX
scaleY = 1.0
}
Replace with
// Resize aspect ratio.
// For AspectFill Screen scaleX > scaleY
// For AspectFit Screen scaleX < scaleY
resizeAspect = min(scaleX, scaleY)
if scaleX > scaleY {
scaleY = scaleX / scaleY
scaleX = 1.0
} else {
scaleX = scaleY / scaleX
scaleY = 1.0
}
Open PreviewMetalView.swift
Replace following lines:
let width = CVPixelBufferGetWidth(previewPixelBuffer)
let height = CVPixelBufferGetHeight(previewPixelBuffer)
with following lines:
let previewViewWidth = Int(self.frame.size.width)
let previewViewheight = Int(self.frame.size.height)
let isPortrait = previewViewheight > previewViewWidth
let width = isPortrait ? previewViewheight : previewViewWidth
let height = isPortrait ? previewViewWidth : previewViewheight