Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qavfcapturephotooutputdelegate.mm
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtFFmpegMediaPluginImpl/private/qavfcapturephotooutputdelegate_p.h>
5
6#include <QtCore/private/qexpected_p.h>
7#include <QtCore/qmutex.h>
8
9#include <QtFFmpegMediaPluginImpl/private/qavfcamerarotationtracker_p.h>
10#include <QtFFmpegMediaPluginImpl/private/qcvimagevideobuffer_p.h>
11
12#include <QtMultimedia/private/qavfcameradebug_p.h>
13#include <QtMultimedia/private/qavfcamerautility_p.h>
14#include <QtMultimedia/private/qavfhelpers_p.h>
15#include <QtMultimedia/private/qmultimediautils_p.h>
16#include <QtMultimedia/private/qvideoframe_p.h>
17
18QT_USE_NAMESPACE
19
20namespace {
21
26
27} // Anonymous namespace
28
30 AVCapturePhoto *,
31 QT_MANGLE_NAMESPACE(QAVFCapturePhotoOutputDelegate) *,
32 NSError *);
33
34@implementation QT_MANGLE_NAMESPACE(QAVFCapturePhotoOutputDelegate) {
35@private
36 QFFmpeg::QAVFStillPhotoNotifier m_notifier;
37
38@public
39 QFFmpeg::AvfCameraRotationTracker m_qAvfCameraRotationTracker;
40}
41
42- (instancetype) init:(AVCaptureDevice *)captureDevice
43{
44 if (!(self = [super init]))
45 return nil;
46
47 Q_ASSERT(captureDevice);
48
49 m_qAvfCameraRotationTracker = QFFmpeg::AvfCameraRotationTracker(captureDevice);
50
51 return self;
52}
53
54- (QFFmpeg::QAVFStillPhotoNotifier &)notifier
55{
56 return self->m_notifier;
57}
58
59// The AVCapturePhotoOutput gives no guarantee on which thread may call this function,
60// so this function needs to be completely thread safe.
61- (void) captureOutput:(AVCapturePhotoOutput *)output
62 didFinishProcessingPhoto:(AVCapturePhoto *)photo
63 error:(NSError *)nsError
64{
65 q23::expected<QVideoFrame, ImageCaptureErrorPair> processResult = processAvCaptureOutput(
66 photo,
67 self,
68 nsError);
69
70 if (processResult) {
71 emit self->m_notifier.succeeded(std::move(*processResult));
72 } else {
73 emit self->m_notifier.failed(
74 processResult.error().type,
75 std::move(processResult.error().message));
76 }
77}
78
79@end
80
81static q23::expected<QVideoFrame, ImageCaptureErrorPair> processAvCaptureOutput(
82 AVCapturePhoto *photo,
83 QT_MANGLE_NAMESPACE(QAVFCapturePhotoOutputDelegate) *captureDelegate,
84 NSError *nsError)
85{
86 Q_ASSERT(photo);
87 Q_ASSERT(captureDelegate);
88
89 using namespace Qt::Literals::StringLiterals;
90
91 if (nsError) {
92 qCWarning(qLcCamera)
93 << "Error while finalizing AVCapturePhotoOutput capture:"
94 << QString::fromNSString(nsError.localizedDescription);
95 return q23::unexpected{ ImageCaptureErrorPair {
96 QImageCapture::Error::ResourceError,
97 u"Internal error while finalizing still photo capture"_s } };
98 }
99
100 if (!photo.pixelBuffer) {
101 qCWarning(qLcCamera)
102 << "When finalizing AVCapturePhotoOutput capture, pixelBuffer was null";
103 return q23::unexpected{ ImageCaptureErrorPair {
104 QImageCapture::Error::ResourceError,
105 u"Internal error while finalizing still photo capture"_s } };
106 }
107
108 QVideoFrameFormat format = QAVFHelpers::videoFormatForImageBuffer(photo.pixelBuffer);
109 if (!format.isValid()) {
110 qCWarning(qLcCamera)
111 << "Unable to determine QVideoFrameFormat based on "
112 "AVCapturePhotoOutput result. Likely an issue with the"
113 "with the configuration of the still photo capture";
114 return q23::unexpected{ ImageCaptureErrorPair {
115 QImageCapture::Error::ResourceError,
116 u"Internal error while finalizing still photo capture"_s } };
117 }
118
119 // Apply rotation data to the format
120 const int cameraRotationDegrees = captureDelegate->m_qAvfCameraRotationTracker
121 .rotationDegrees();
122 format.setRotation(qVideoRotationFromDegrees(cameraRotationDegrees));
123
124 auto sharedPixelBuffer = QAVFHelpers::QSharedCVPixelBuffer(
125 photo.pixelBuffer,
126 QAVFHelpers::QSharedCVPixelBuffer::RefMode::NeedsRef);
127 auto videoFrame = QVideoFramePrivate::createFrame(
128 std::make_unique<QFFmpeg::CVImageVideoBuffer>(std::move(sharedPixelBuffer)),
129 std::move(format));
130 if (!videoFrame.isValid()) {
131 qCWarning(qLcCamera) << "Unable to create QVideoFrame from AVCapturePhotoOutput result";
132 return q23::unexpected{ ImageCaptureErrorPair {
133 QImageCapture::Error::ResourceError,
134 u"Internal error while finalizing still photo capture"_s } };
135 }
136
137 // If we are the front-facing camera, we need to provide the flip horizontally flag to the
138 // frame (not the format).
139 AVCaptureDevice *avCaptureDevice = captureDelegate->m_qAvfCameraRotationTracker
140 .avCaptureDevice();
141 Q_ASSERT(avCaptureDevice);
142 videoFrame.setMirrored(avCaptureDevice.position == AVCaptureDevicePositionFront);
143
144 return videoFrame;
145}
static q23::expected< QVideoFrame, ImageCaptureErrorPair > processAvCaptureOutput(AVCapturePhoto *, QT_MANGLE_NAMESPACE(QAVFCapturePhotoOutputDelegate) *, NSError *)