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>
21#include <QtCore/qmetaobject.h>
22#include <QtMultimedia/qvideoframeformat.h>
26@interface AVFCaptureFramesDelegate : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
28- (AVFCaptureFramesDelegate *) initWithRenderer:(AVFCameraRenderer*)renderer;
30- (
void) captureOutput:(AVCaptureOutput *)captureOutput
31 didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
32 fromConnection:(AVCaptureConnection *)connection;
36@implementation AVFCaptureFramesDelegate
39 AVFCameraRenderer *m_renderer;
42- (AVFCaptureFramesDelegate *) initWithRenderer:(AVFCameraRenderer*)renderer
44 if (!(self = [super init]))
47 self->m_renderer = renderer;
51- (
void)captureOutput:(AVCaptureOutput *)captureOutput
52 didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
53 fromConnection:(AVCaptureConnection *)connection
56 Q_UNUSED(captureOutput);
62 std::make_unique<AVFVideoBuffer>(m_renderer,
63 QCFType<CVImageBufferRef>::constructFromGet(
64 CMSampleBufferGetImageBuffer(sampleBuffer)));
65 auto format = buffer->videoFormat();
66 if (!format.isValid()) {
70 QVideoFrame frame = QVideoFramePrivate::createFrame(std::move(buffer), format);
71 m_renderer->syncHandleViewfinderFrame(frame);
76AVFCameraRenderer::AVFCameraRenderer(QObject *parent)
79 m_viewfinderFramesDelegate = [[AVFCaptureFramesDelegate alloc] initWithRenderer:
this];
80 connect(&m_orientationHandler, &QVideoOutputOrientationHandler::orientationChanged,
81 this, &AVFCameraRenderer::deviceOrientationChanged);
86 [m_cameraSession->captureSession() removeOutput:m_videoDataOutput];
87 [m_viewfinderFramesDelegate release];
88 [m_videoDataOutput release];
91 dispatch_release(m_delegateQueue);
96 QMutexLocker lock(&m_vfMutex);
100 m_sink->setNativeSize(QSize(m_layer.bounds.size.width, m_layer.bounds.size.height));
102 deviceOrientationChanged();
107 if (!m_videoDataOutput)
110 if (m_cameraSession) {
111 const auto format = m_cameraSession->cameraFormat();
112 if (format.pixelFormat() != QVideoFrameFormat::Format_Invalid)
113 setPixelFormat(format.pixelFormat(), QCameraFormatPrivate::getColorRange(format));
120 if (!m_outputSettings)
123 if (m_outputSettings)
124 m_videoDataOutput.videoSettings = m_outputSettings;
129 m_cameraSession = cameraSession;
130 connect(m_cameraSession, SIGNAL(readyToConfigureConnections()),
131 this, SLOT(updateCaptureConnection()));
133 m_needsHorizontalMirroring =
false;
135 m_videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
138 m_delegateQueue = dispatch_queue_create(
"vf_queue",
nullptr);
140 setSampleBufferDelegate:m_viewfinderFramesDelegate
141 queue:m_delegateQueue];
143 [m_cameraSession->captureSession() addOutput:m_videoDataOutput];
148 AVCaptureConnection *connection = [m_videoDataOutput connectionWithMediaType:AVMediaTypeVideo];
149 if (connection == nil || !m_cameraSession->videoCaptureDevice())
154 if (connection.isVideoMirroringSupported)
155 connection.videoMirrored = m_cameraSession->videoCaptureDevice().position == AVCaptureDevicePositionFront;
158 m_needsHorizontalMirroring = !connection.isVideoMirrored
159 && m_cameraSession->videoCaptureDevice().position == AVCaptureDevicePositionFront;
161 deviceOrientationChanged();
166 AVCaptureConnection *connection = [m_videoDataOutput connectionWithMediaType:AVMediaTypeVideo];
167 if (connection == nil || !m_cameraSession->videoCaptureDevice())
170 if (!connection.supportsVideoOrientation)
174 angle = m_orientationHandler.currentOrientation();
176 AVCaptureVideoOrientation orientation = AVCaptureVideoOrientationPortrait;
181 orientation = AVCaptureVideoOrientationLandscapeRight;
187 orientation = AVCaptureVideoOrientationLandscapeLeft;
191 connection.videoOrientation = orientation;
197 Q_EMIT newViewfinderFrame(frame);
199 QMutexLocker lock(&m_vfMutex);
201 if (!m_lastViewfinderFrame.isValid()) {
202 static QMetaMethod handleViewfinderFrameSlot = metaObject()->method(
203 metaObject()->indexOfMethod(
"handleViewfinderFrame()"));
205 handleViewfinderFrameSlot.invoke(
this, Qt::QueuedConnection);
208 m_lastViewfinderFrame = frame;
213 return m_videoDataOutput;
218 return m_viewfinderFramesDelegate;
223 [m_videoDataOutput setSampleBufferDelegate:m_viewfinderFramesDelegate queue:m_delegateQueue];
230 QMutexLocker lock(&m_vfMutex);
231 frame = m_lastViewfinderFrame;
232 m_lastViewfinderFrame = QVideoFrame();
235 if (
m_sink && frame.isValid()) {
237 m_sink->setVideoFrame(frame);
242 QVideoFrameFormat::ColorRange colorRange)
244 if (rhi() && rhi()->backend() == QRhi::OpenGLES2) {
245 if (pixelFormat != QVideoFrameFormat::Format_BGRA8888)
246 qWarning() <<
"OpenGL rhi backend only supports 32BGRA pixel format.";
253 auto cvPixelFormat = QAVFHelpers::toCVPixelFormat(pixelFormat, colorRange);
254 if (cvPixelFormat == CvPixelFormatInvalid) {
255 cvPixelFormat = kCVPixelFormatType_32BGRA;
256 qWarning() <<
"QCamera::setCameraFormat: couldn't convert requested pixel format, using ARGB32";
259 bool isSupported =
false;
260 NSArray *supportedPixelFormats = m_videoDataOutput.availableVideoCVPixelFormatTypes;
261 for (NSNumber *currentPixelFormat in supportedPixelFormats)
263 if ([currentPixelFormat unsignedIntValue] == cvPixelFormat) {
270 NSDictionary *outputSettings = @{
272 kCVPixelBufferPixelFormatTypeKey : [NSNumber numberWithUnsignedInt:cvPixelFormat]
275 (NSString *)kCVPixelBufferMetalCompatibilityKey : @
true
278 if (m_outputSettings)
279 [m_outputSettings release];
280 m_outputSettings = [[NSDictionary alloc] initWithDictionary:outputSettings];
282 qWarning() <<
"QCamera::setCameraFormat: requested pixel format not supported. Did you use a camera format from another camera?";
286#include "moc_avfcamerarenderer_p.cpp"
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()