I try to write a simple demo to record video by reading the apple's document It has no error but when I call startRecording() method and pass the delegate, the function in the delegate(didstartrecording,didfinishrecording) won't be executed for some how
class Delegate:NSObject,AVCaptureFileOutputRecordingDelegate{
func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
func cleanup(){
let path = outputFileURL.path
if(FileManager.default.fileExists(atPath: path)){
do{
try FileManager.default.removeItem(atPath: path)
}
catch{
print("error")
}
}
}
if error != nil {
print("error")
}
PHPhotoLibrary.requestAuthorization(for: .readWrite){
status in
if status == .authorized{
PHPhotoLibrary.shared().performChanges{
let option = PHAssetResourceCreationOptions()
option.shouldMoveFile=true
let createrequset = PHAssetCreationRequest.forAsset()
createrequset.addResource(with: .video, fileURL: outputFileURL, options: option)
}
completionHandler:{ a,b in
if !a {
print("error")
}
cleanup()
}
}
else{cleanup()}
}
}
func fileOutput(_ output: AVCaptureFileOutput, didStartRecordingTo fileURL: URL, from connections: [AVCaptureConnection]) {
print("didstart")
}
}
struct ContentView: View {
private var movieFileOutput: AVCaptureMovieFileOutput = AVCaptureMovieFileOutput()
private let sessionQueue = DispatchQueue(label: "session queue")
let a = AVCaptureSession()
var body: some View {
ZStack {
CameraPreview(session: a)
.ignoresSafeArea()
.onAppear{
let status = AVCaptureDevice.authorizationStatus(for: .video)
switch status {
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video){test in
if test {
print("settingup")
setUpCamera()
}
}
case .restricted:
return
case .denied:
fatalError()
case .authorized:
setUpCamera()
print("settingup")
a.startRunning()
@unknown default:
fatalError()
}
}
Button("record"){
record()
}
}
}
func record(){
sessionQueue.async {
if movieFileOutput.isRecording == false{
let movieOutputConnetion = movieFileOutput.connection(with: .video)!
movieOutputConnetion.videoOrientation = .portrait
movieFileOutput.setOutputSettings([AVVideoCodecKey:AVVideoCodecType.h264], for: movieOutputConnetion)
movieOutputConnetion.videoOrientation = .portrait
let outputFileName = UUID().uuidString
let outputFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent((outputFileName as NSString).appendingPathExtension("mov")!)
print("starting")
print(movieFileOutput.connections)
movieFileOutput.startRecording(to: URL(fileURLWithPath: outputFilePath), recordingDelegate: Delegate())
}
else {movieFileOutput.stopRecording()}
}
}
func setUpCamera(){
a.beginConfiguration()
let device = AVCaptureDevice.default(.builtInTelephotoCamera,for:.video,position: .unspecified)
guard let videoDeviceInput = try? AVCaptureDeviceInput(device:device!),
a.canAddInput(videoDeviceInput)
else {return}
print("added")
a.addInput(videoDeviceInput)
let vedio = AVCaptureVideoDataOutput()
guard a.canAddOutput(vedio)else{return}
a.sessionPreset = .hd4K3840x2160
a.addOutput(movieFileOutput)
print(a.connections)
a.commitConfiguration()
}
}
I found that apple official code conbine all of them in a Class, is it necessary for this to work?
CodePudding user response:
You don’t hold a reference for the delegate. Try have it as a property on the view for example. Like the session. You can define a ‘deinit’ on the delegate. And see that the ’ AVCaptureMovieFileOutput’ you are using is holding a weak reference to it. And it is probably being removed from the memory right away. As no object holds a reference to it.
The delegate name should indicate a weak reference (i.e the ARC will not increase the reference count for the object) when passed/assigned. Hence as no other object holds a reference to the Delegate() object you have just initialized. Its reference count will zero once you are out of the function context and the ARC will deinit the object and remove from memory.