애플 공식문서 : https://developer.apple.com/documentation/avfoundation/avcapturevideodataoutputsamplebufferdelegate
지금 만들고 있는 앱은 AVFoundation 을 사용한 카메라 앱이다. 그리고 Google 의 MLKit 을 사용해서 문자인식 기술을 곁들였다.
그리고 카메라에 보이는 실시간 이미지 버퍼에 문자를 인식한 박스를 preview layer 위에 그려서 표현해주고 싶었다.
그래서 AVCapture 에 대한 공식문서를 열심히 파봤는데, 그 중에서도 구현 기능 중에서 제일 핵심이었던 AVCaptureVideoDataOutputSampleBufferDelegate 에 대한 공식문서 내용을 정리해야겠다고 생각했다.
AVCaptureVideoDataOutputSampleBufferDelegate 는 AVCaptureVideoDataOutput 의 델리게이트 프로토콜이기 때문에, AVCaptureVideoDataOutput 를 정리를 하는게 좋을 것 같다.
A capture output that records video and provides access to video frames for processing.
비디오를 기록하는, 그리고 프로세싱을 위한 비디오 프레임 접근을 제공하는 캡처 아웃풋이다. 정리하면, 카메라를 통해 들어오는 비디오 정보들을 이 클래스 안에서 처리한다.
You use this output to process compressed or uncompressed frames from the captured video. You can access the frames with the captureOutput(_:didOutput:from:) delegate method.
setSampleBufferDelegate 을 이용해서 델리게이트를 설정할 수 있다.
그리고 정확히는 captureOutput 라는 델리게이트 메서드를 통해서 비디오 프레임에 접근할 수 있다.
Sets the sample buffer delegate and the queue for invoking callbacks.
샘플 버퍼 델리게이트와 콜백을 유도하는 큐를 세팅합니다.
sampleBufferDelegate
An object conforming to the AVCaptureVideoDataOutputSampleBufferDelegate protocol that will receive sample buffers after they are captured.샘플 버퍼를 넘겨받고 처리할 delegate protocol 을 채택할 (위임받을) 객체. 이걸 self 로 설정하면 그 객체에서 샘플 버퍼 처리를 하게 된다.
sampleBufferCallbackQueue
The queue on which callbacks should be invoked. You must use a serial dispatch queue, to guarantee that video frames will be delivered in order.
The sampleBufferCallbackQueue parameter may not be NULL, except when setting the sampleBufferDelegate to nil.콜백이 유도되어야 하는 큐. 비디오 프레임을 순차적으로 받으려면 serial queue 를 사용해야 한다.
Discussion
- When a new video sample buffer is captured, it is sent to the sample buffer delegate using captureOutput(_:didOutput:from:). All delegate methods are invoked on the specified dispatch queue.
새 비디오의 샘플 버퍼가 캡처되면 captureOutput(_:didOutput:from:)을 사용하여 샘플 버퍼 위임자에게 전송된다. 지정한 디스패치 큐 (위에서 sampleBufferCallbackQueue) 에서 모든 델리게이트 메서드가 호출된다.
- If the queue is blocked when new frames are captured, those frames will be automatically dropped at a time determined by the value of the alwaysDiscardsLateVideoFrames property.
만약에 새로운 프레임들이 캡처되는 동안 그 큐가 블락되면, 프레임들은 자동적으로 정해진 시간에 드랍된다. 근데 그 시간은 alwaysDiscardsLateVideoFrames 프로퍼티로 정한다.
- This allows you to process existing frames on the same queue without having to manage the potential memory usage increases that would otherwise occur when that processing is unable to keep up with the rate of incoming frames.
이건 뭘 뜻하냐면, 같은 큐 안에서 존재하는 프레임들을 A 없이 프로세싱 하도록 돕는다는 거다. A 가 뭐냐면 잠재적 메모리 사용 증가. 근데 그건 언제 발생하냐? 프로세싱이 불가능할때. 들어오는 프레임 비율에 따라가지 못해서.
-> 그래서 나는 alwaysDiscardsLateVideoFrames = true 로 설정 해줬다.
- If your frame processing is consistently unable to keep up with the rate of incoming frames, you should consider using the minFrameDuration property, which will generally yield better performance characteristics and more consistent frame rates than frame dropping alone.
만약에 너의 프레임 처리가 지속적으로 프레임 들어오는 속도를 쫓아가지 못한다면, 넌 minFrameDuration 프로퍼티를 사용하는걸 고려해보는게 좋아 ~ 그건 아마 일반적으로 더 나은 결과랑, 프레임을 드랍하는것보다는 일관된 프레임률을 산출할꺼야.
-> 근데 찾아보니 minFrameDuration 은 deprecated 되었고 videoMinFrameDuration 을 사용해야 됐다.
videoMinFrameDuration 공식문서 링크 : https://developer.apple.com/documentation/avfoundation/avcaptureconnection/1388931-videominframeduration
- If you need to minimize the chances of frames being dropped, you should specify a queue on which a sufficiently small amount of processing is being done outside of receiving sample buffers.
-> 프레임 손실을 줄이려면, 너는 큐를 선언해야 된다. 어떤 큐냐면, 샘플 버퍼들을 받는 작업 이외에 충분히 적은 양의 일을 처리할 수 있는.
- However, if you migrate extra processing to another queue, you are responsible for ensuring that memory usage does not grow without bound from frames that have not been processed.
하지만, 만약에 너가 남은 처리를 다른 큐에 옮겨서 처리하려면, 너는 이러한 책임을 져야한다. 무슨 책임이냐면, 처리되지 않은 프레임들의 메모리 사용량이 경계를 넘지 않도록 하는 책임이다.
sampleBuffer : A CMSampleBuffer object containing the video frame data and additional information about the frame, such as its format and presentation time.
-> 비디오 프레임 데이터를 갖고있는 CMSampleBuffer 객체.
connection : The connection from which the video was received.
-> 비디오를 받은 connection
Discussion
- Delegates receive this message whenever the output captures and outputs a new video frame, decoding or re-encoding it as specified by its videoSettings property. Delegates can use the provided video frame in conjunction with other APIs for further processing.
델리게이트 위임자는 output 이 videoSetting 프로퍼티에 따라서 비디오 프레임들을 받아오거나 캡처할때마다 이 메시지를 받는다. 그리고 델리게이트는 이 제공된 비디오 프레임을 따른 처리 API 랑 함께 결합해서 사용할 수 있다. 필터 씌우는 API 같은거랑 사용가능하다는 뜻인듯.
- This method is called on the dispatch queue specified by the output’s sampleBufferCallbackQueue property. It is called periodically, so it must be efficient to prevent capture performance problems, including dropped frames.
이 메서드는 output 의 sampleBufferCallbackQueue 프로퍼티에 명시된 디스패치 큐에 호출된다. 그니까 위에서 설정했던 그 큐에. 주기적으로 호출된다. 그래서 프레임 드랍과 같은 문제 상황들을 효과적으로 잘 막아야 한다.
- If you need to reference the CMSampleBuffer object outside of the scope of this method, you must CFRetain it and then CFRelease it when you are finished with it.
만약 CMSampleBuffer 객체를 이 메서드 밖에서 사용하려면, 그걸 마칠때 꼭 CFRetain 을 해줘야 한다.
- To maintain optimal performance, some sample buffers directly reference pools of memory that may need to be reused by the device system and other capture inputs
최적의 성능을 유지하려면, 몇몇 샘플 버퍼들은 메모리 풀을 참조한다. 근데 그 메모리 풀은 그 기기의 시스템과 다른 캡처 input 들에게 재사용 될 필요가 있다.
- This is frequently the case for uncompressed device native capture where memory blocks are copied as little as possible.
이건 종종 A 를 위한 케이스인데, A 가 뭐냐면, 메모리 블록들이 가능한 적게 복사되는, 압축되지 않은 캡처 디바이스다.
- If multiple sample buffers reference such pools of memory for too long, inputs will no longer be able to copy new samples into memory and those samples will be dropped.
만약 다수의 샘플 버퍼들이 그러한 메모리풀을 오랫동안 접근한다면, input 들은 더이상 새로운 샘플을 메모리에 복사할 수 없게되고 그 샘플들은 드랍된다.
- If your application is causing samples to be dropped by retaining the provided CMSampleBuffer objects for too long, but it needs access to the sample data for a long period of time, consider copying the data into a new buffer and then releasing the sample buffer (if it was previously retained) so that the memory it references can be reused.
만약 니 앱이 샘플들을 계속 드랍시킨다면 ( CMSampleBuffer 객체들을 너무 오래 retain 함으로써 ), 하지만 오랫동안 샘플 데이터에 접근해야 한다면, 데이터를 새로운 버퍼로 카피하고, 전에 리테인 됐던 그 버퍼를 release 하는 걸 고려해봐라. 메모리 참조가 재 사용될 수 있도록.
- Notifies the delegate that a video frame was discarded.
델리게이트 위임자에게 비디오 프레임이 삭제되었음을 알린다.