带全屏实时预览的相机,
previewLayer!.videoGravity = AVLayerVideoGravityResize
制作图片......
stillImageOutput?.captureStillImageAsynchronously(
from: videoConnection, completionHandler:
全屏实时预览将或应该与静止图像精确匹配。
(为清楚起见:说你不小心使用了AVLayerVideoGravityResizeAspectFill
。在这种情况下,实时预览与静止图像不匹配 - 你会在拉伸时看到“跳跃”。)
如果您尝试使用iOS10 ...
以下(使用AVLayerVideoGravityResize
- 正确选择)
它不能正常工作:在实时预览和静止图像之间获得“小跳”。一个或另一个略微拉伸不正确。
这实际上只是某些设备的错误吗?还是在iOS?
(它完美无缺 - 没有跳转 - 在旧设备上,如果你尝试使用iOS9。)
有没有人见过这个?
// CameraPlane ... the actual live camera plane per se
import UIKit
import AVFoundation
class CameraPlane:UIViewController
{
var captureSession: AVCaptureSession?
var stillImageOutput: AVCaptureStillImageOutput?
var previewLayer: AVCaptureVideoPreviewLayer?
fileprivate func fixConnectionOrientation()
{
if let connection = self.previewLayer?.connection
{
let previewLayerConnection : AVCaptureConnection = connection
guard previewLayerConnection.isVideoOrientationSupported else
{
print("strangely no orientation support")
return
}
previewLayerConnection.videoOrientation = neededVideoOrientation()
previewLayer!.frame = view.bounds
}
}
func neededVideoOrientation()->(AVCaptureVideoOrientation)
{
let currentDevice:UIDevice = UIDevice.current
let orientation: UIDeviceOrientation = currentDevice.orientation
var r:AVCaptureVideoOrientation
switch (orientation)
{
case .portrait: r = .portrait
break
case .landscapeRight: r = .landscapeLeft
break
case .landscapeLeft: r = .landscapeRight
break
case .portraitUpsideDown: r = .portraitUpsideDown
break
default: r = .portrait
break
}
return r
}
override func viewDidLayoutSubviews()
{
super.viewDidLayoutSubviews()
fixConnectionOrientation()
}
func cameraBegin()
{
captureSession = AVCaptureSession()
captureSession!.sessionPreset = AVCaptureSessionPresetPhoto
// remember that of course, none of this will work on a simulator, only on a device
let backCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
var error: NSError?
var input: AVCaptureDeviceInput!
do {
input = try AVCaptureDeviceInput(device: backCamera)
} catch let error1 as NSError
{
error = error1
input = nil
}
if ( error != nil )
{
print("probably on simulator? no camera?")
return;
}
if ( captureSession!.canAddInput(input) == false )
{
print("capture session problem?")
return;
}
captureSession!.addInput(input)
stillImageOutput = AVCaptureStillImageOutput()
stillImageOutput!.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
if ( captureSession!.canAddOutput(stillImageOutput) == false )
{
print("capture session with stillImageOutput problem?")
return;
}
captureSession!.addOutput(stillImageOutput)
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
// previewLayer!.videoGravity = AVLayerVideoGravityResizeAspect
// means, won't reach the top and bottom on devices, gray bars
// previewLayer!.videoGravity = AVLayerVideoGravityResizeAspectFill
// means, you get the "large squeeze" once you make photo
previewLayer!.videoGravity = AVLayerVideoGravityResize
// works perfectly on ios9, older devices etc.
// on 6s+, you get a small jump between the video live preview and the make photo
fixConnectionOrientation()
view.layer.addSublayer(previewLayer!)
captureSession!.startRunning()
previewLayer!.frame = view.bounds
}
/*Video Gravity.
These string constants define how the video is displayed within a layer’s bounds rectangle.
You use these constants when setting the videoGravity property of an AVPlayerLayer or AVCaptureVideoPreviewLayer instance.
AVLayerVideoGravityResize
Specifies that the video should be stretched to fill the layer’s bounds.
AVLayerVideoGravityResizeAspect
Specifies that the player should preserve the video’s aspect ratio and fit the video within the layer’s bounds.
AVLayerVideoGravityResizeAspectFill
Specifies that the player should preserve the video’s aspect ratio and fill the layer’s bounds.
*/
func makePhotoOn(_ here:UIImageView)
{
// recall that this indeed makes a still image, which is used as
// a new background image (indeed on the "stillImage" view)
// and you can then continue to move the door around on that scene.
if ( stillImageOutput == nil )
{
print("simulator, using test image.")
here.image = UIImage(named:"ProductMouldings.jpg")
return
}
guard let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo)
else
{
print("AVMediaTypeVideo didn't work?")
return
}
videoConnection.videoOrientation = (previewLayer!.connection?.videoOrientation)!
stillImageOutput?.captureStillImageAsynchronously(
from: videoConnection, completionHandler:
{
(sampleBuffer, error) in
guard sampleBuffer != nil else
{
print("sample buffer woe?")
return
}
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
let dataProvider = CGDataProvider(data: imageData as! CFData)
let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent)
let ort = self.neededImageOrientation()
let image = UIImage(cgImage:cgImageRef!, scale:1.0, orientation:ort)
here.image = image
})
}
func neededImageOrientation()->(UIImageOrientation)
{
var n : UIImageOrientation
let currentDevice: UIDevice = UIDevice.current
let orientation: UIDeviceOrientation = currentDevice.orientation
switch orientation
{
case UIDeviceOrientation.portraitUpsideDown:
n = .left
case UIDeviceOrientation.landscapeRight:
n = .down
case UIDeviceOrientation.landscapeLeft:
n = .up
case UIDeviceOrientation.portrait:
n = .right
default:
n = .right
}
return n
}
/*
@IBAction func didPressTakeAnother(sender: AnyObject)
{ captureSession!.startRunning() }
*/
}
答案 0 :(得分:2)
完整性检查 - 您确定AVLayerVideoGravityResize
是您想要使用的吗?这会将图像(不保留纵横比)拉伸到预览的框架。如果您打算保持纵横比,您可能需要AVLayerVideoGravityResizeAspect
(如您所见,会有灰色条,但会保持纵横比)或AVLayerVideoGravityResizeAspectFill
(可能是您想要的 - 部分预览将被截止,但将保持纵横比)。
假设您的“此处”视图(传递给makePhotoOn:
的视图)与预览视图的大小/位置相同,您需要设置“此处”视图contentMode
以匹配行为你的预览。
因此,如果您使用AVLayerVideoGravityResizeAspect
进行预览,那么:
here.contentMode = .scaleAspectFit
如果您使用AVLayerVideoGravityResizeAspectFill
进行预览,则:
here.contentMode = .scaleAspectFill
。
视图的默认contentMode
为.scaleToFill
(在此处注明:https://developer.apple.com/reference/uikit/uiview/1622619-contentmode),因此您的“此处”imageView可能会拉伸图像以匹配其大小,而不是保持纵横比。
如果这没有用,你可以考虑提供一个在github上展示问题的准系统项目,这样我们SO中的修补工就可以快速构建并修补它。