5#include "private/qcameradevice_p.h"
6#include "private/qvideoframe_p.h"
10#include <QtMultimedia/private/qavfcameradebug_p.h>
12#include <avfvideosink_p.h>
13#include <avfvideobuffer_p.h>
15#include <QtMultimedia/private/qavfhelpers_p.h>
19#import <AVFoundation/AVFoundation.h>
22#include <QtGui/qopengl.h>
25#include <QtCore/qmetaobject.h>
26#include <QtMultimedia/qvideoframeformat.h>
30@interface AVFCaptureFramesDelegate : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
32- (AVFCaptureFramesDelegate *) initWithRenderer:(AVFCameraRenderer*)renderer;
34- (
void) captureOutput:(AVCaptureOutput *)captureOutput
35 didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
36 fromConnection:(AVCaptureConnection *)connection;
40@implementation AVFCaptureFramesDelegate
43 AVFCameraRenderer *m_renderer;
48 if (!(self = [super init]))
51 self->m_renderer = renderer;
55- (
void)captureOutput:(AVCaptureOutput *)captureOutput
56 didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
57 fromConnection:(AVCaptureConnection *)connection
60 Q_UNUSED(captureOutput);
66 std::make_unique<AVFVideoBuffer>(m_renderer,
67 QCFType<CVImageBufferRef>::constructFromGet(
68 CMSampleBufferGetImageBuffer(sampleBuffer)));
69 auto format = buffer->videoFormat();
70 if (!format.isValid()) {
74 QVideoFrame frame = QVideoFramePrivate::createFrame(std::move(buffer), format);
75 m_renderer->syncHandleViewfinderFrame(frame);
80AVFCameraRenderer::AVFCameraRenderer(QObject *parent)
83 m_viewfinderFramesDelegate = [[AVFCaptureFramesDelegate alloc] initWithRenderer:
this];
84 connect(&m_orientationHandler, &QVideoOutputOrientationHandler::orientationChanged,
85 this, &AVFCameraRenderer::deviceOrientationChanged);
90 [m_cameraSession->captureSession() removeOutput:m_videoDataOutput];
91 [m_viewfinderFramesDelegate release];
92 [m_videoDataOutput release];
95 dispatch_release(m_delegateQueue);
98 CFRelease(m_textureCache);
104 QMutexLocker lock(&m_vfMutex);
108 m_sink->setNativeSize(QSize(m_layer.bounds.size.width, m_layer.bounds.size.height));
110 deviceOrientationChanged();
115 if (!m_videoDataOutput)
118 if (m_cameraSession) {
119 const auto format = m_cameraSession->cameraFormat();
120 if (format.pixelFormat() != QVideoFrameFormat::Format_Invalid)
121 setPixelFormat(format.pixelFormat(), QCameraFormatPrivate::getColorRange(format));
128 if (!m_outputSettings)
131 if (m_outputSettings)
132 m_videoDataOutput.videoSettings = m_outputSettings;
137 m_cameraSession = cameraSession;
138 connect(m_cameraSession, SIGNAL(readyToConfigureConnections()),
139 this, SLOT(updateCaptureConnection()));
141 m_needsHorizontalMirroring =
false;
143 m_videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
146 m_delegateQueue = dispatch_queue_create(
"vf_queue",
nullptr);
148 setSampleBufferDelegate:m_viewfinderFramesDelegate
149 queue:m_delegateQueue];
151 [m_cameraSession->captureSession() addOutput:m_videoDataOutput];
156 AVCaptureConnection *connection = [m_videoDataOutput connectionWithMediaType:AVMediaTypeVideo];
157 if (connection == nil || !m_cameraSession->videoCaptureDevice())
162 if (connection.isVideoMirroringSupported)
163 connection.videoMirrored = m_cameraSession->videoCaptureDevice().position == AVCaptureDevicePositionFront;
166 m_needsHorizontalMirroring = !connection.isVideoMirrored
167 && m_cameraSession->videoCaptureDevice().position == AVCaptureDevicePositionFront;
169 deviceOrientationChanged();
174 AVCaptureConnection *connection = [m_videoDataOutput connectionWithMediaType:AVMediaTypeVideo];
175 if (connection == nil || !m_cameraSession->videoCaptureDevice())
178 if (!connection.supportsVideoOrientation)
182 angle = m_orientationHandler.currentOrientation();
184 AVCaptureVideoOrientation orientation = AVCaptureVideoOrientationPortrait;
189 orientation = AVCaptureVideoOrientationLandscapeRight;
195 orientation = AVCaptureVideoOrientationLandscapeLeft;
199 connection.videoOrientation = orientation;
205 Q_EMIT newViewfinderFrame(frame);
207 QMutexLocker lock(&m_vfMutex);
209 if (!m_lastViewfinderFrame.isValid()) {
210 static QMetaMethod handleViewfinderFrameSlot = metaObject()->method(
211 metaObject()->indexOfMethod(
"handleViewfinderFrame()"));
213 handleViewfinderFrameSlot.invoke(
this, Qt::QueuedConnection);
216 m_lastViewfinderFrame = frame;
221 return m_videoDataOutput;
226 return m_viewfinderFramesDelegate;
231 [m_videoDataOutput setSampleBufferDelegate:m_viewfinderFramesDelegate queue:m_delegateQueue];
238 QMutexLocker lock(&m_vfMutex);
239 frame = m_lastViewfinderFrame;
240 m_lastViewfinderFrame = QVideoFrame();
243 if (
m_sink && frame.isValid()) {
245 m_sink->setVideoFrame(frame);
250 QVideoFrameFormat::ColorRange colorRange)
252 if (rhi() && rhi()->backend() == QRhi::OpenGLES2) {
253 if (pixelFormat != QVideoFrameFormat::Format_BGRA8888)
254 qWarning() <<
"OpenGL rhi backend only supports 32BGRA pixel format.";
261 auto cvPixelFormat = QAVFHelpers::toCVPixelFormat(pixelFormat, colorRange);
262 if (cvPixelFormat == CvPixelFormatInvalid) {
263 cvPixelFormat = kCVPixelFormatType_32BGRA;
264 qWarning() <<
"QCamera::setCameraFormat: couldn't convert requested pixel format, using ARGB32";
267 bool isSupported =
false;
268 NSArray *supportedPixelFormats = m_videoDataOutput.availableVideoCVPixelFormatTypes;
269 for (NSNumber *currentPixelFormat in supportedPixelFormats)
271 if ([currentPixelFormat unsignedIntValue] == cvPixelFormat) {
278 NSDictionary *outputSettings = @{
280 kCVPixelBufferPixelFormatTypeKey : [NSNumber numberWithUnsignedInt:cvPixelFormat]
283 (NSString *)kCVPixelBufferMetalCompatibilityKey : @
true
286 if (m_outputSettings)
287 [m_outputSettings release];
288 m_outputSettings = [[NSDictionary alloc] initWithDictionary:outputSettings];
290 qWarning() <<
"QCamera::setCameraFormat: requested pixel format not supported. Did you use a camera format from another camera?";
294#include "moc_avfcamerarenderer_p.cpp"
Q_FORWARD_DECLARE_OBJC_CLASS(AVFCaptureFramesDelegate)
void reconfigure() override
AVCaptureVideoDataOutput * videoDataOutput() const
void setOutputSettings() override
~AVFCameraRenderer() override
AVFCaptureFramesDelegate * captureDelegate() const
void configureAVCaptureSession(AVFCameraSession *cameraSession)
void setPixelFormat(QVideoFrameFormat::PixelFormat pixelFormat, QVideoFrameFormat::ColorRange colorRange)
void resetCaptureDelegate() const
virtual void setOutputSettings()