4#include <QtFFmpegMediaPluginImpl/private/qavfcamera_p.h>
6#include <QtCore/qscopeguard.h>
7#include <QtCore/private/qcore_mac_p.h>
9#include <QtFFmpegMediaPluginImpl/private/qavfcamerafactory_p.h>
10#include <QtFFmpegMediaPluginImpl/private/qavfcapturephotooutputdelegate_p.h>
11#include <QtFFmpegMediaPluginImpl/private/qavfsamplebufferdelegate_p.h>
13#include <QtMultimedia/private/qavfcameradebug_p.h>
14#include <QtMultimedia/private/qavfcamerautility_p.h>
15#include <QtMultimedia/private/qavfhelpers_p.h>
16#include <QtMultimedia/private/qmultimediautils_p.h>
17#include <QtMultimedia/private/qplatformmediacapture_p.h>
19#define AVMediaType XAVMediaType
21#include <libavutil/hwcontext_videotoolbox.h>
22#include <libavutil/hwcontext.h>
34[[nodiscard]] AVCaptureFlashMode toAvfFlashMode(QCamera::FlashMode flashMode)
37 case QCamera::FlashMode::FlashOff:
38 return AVCaptureFlashModeOff;
39 case QCamera::FlashMode::FlashAuto:
40 return AVCaptureFlashModeAuto;
41 case QCamera::FlashMode::FlashOn:
42 return AVCaptureFlashModeOn;
44 return AVCaptureFlashModeOff;
47[[nodiscard]]
bool checkAvCapturePhotoFormatSupport(AVCapturePhotoOutput *output,
int cvPixelFormat)
50 NSArray<NSNumber *> *supportedFormats = output.availablePhotoPixelFormatTypes;
51 for (NSNumber *format : supportedFormats) {
52 if (format.intValue == cvPixelFormat)
58[[nodiscard]] QAVFSampleBufferDelegateTransform surfaceTransform(
59 const QFFmpeg::AvfCameraRotationTracker *rotationTracker,
60 const AVCaptureConnection *connection)
62 QAVFSampleBufferDelegateTransform transform = {};
66 if (rotationTracker !=
nullptr) {
67 captureAngle = rotationTracker->rotationDegrees();
69 bool cameraIsFrontFacing =
70 rotationTracker->avCaptureDevice() !=
nullptr
71 && rotationTracker->avCaptureDevice().position == AVCaptureDevicePositionFront;
72 if (cameraIsFrontFacing)
73 transform.presentationTransform.mirroredHorizontallyAfterRotation =
true;
82 int connectionAngle = 0;
84 if (@available(macOS 14.0, iOS 17.0, *))
85 connectionAngle =
std::lround(connection.videoRotationAngle);
87 if (connection.videoMirrored)
88 transform.surfaceTransform.mirroredHorizontallyAfterRotation =
true;
91 transform.surfaceTransform.rotation = qVideoRotationFromDegrees(captureAngle - connectionAngle);
98[[nodiscard]]
static AVCaptureDeviceFormat* findSuitableAvCaptureDeviceFormat(
99 AVCaptureDevice *avCaptureDevice,
100 const QCameraFormat &format)
102 Q_ASSERT(avCaptureDevice !=
nullptr);
103 Q_ASSERT(!format.isNull());
107 AVCaptureDeviceFormat *newDeviceFormat = qt_convert_to_capture_device_format(
110 &QFFmpeg::isCVFormatSupported);
114 if (!newDeviceFormat)
115 newDeviceFormat = qt_convert_to_capture_device_format(avCaptureDevice, format);
117 return newDeviceFormat;
120[[nodiscard]]
static q23::expected<CvPixelFormat, QString> tryFindVideoDataOutputPixelFormat(
121 QVideoFrameFormat::PixelFormat cameraPixelFormat,
122 CvPixelFormat inputCvPixFormat,
123 AVCaptureVideoDataOutput *avCaptureVideoDataOutput)
125 Q_ASSERT(cameraPixelFormat != QVideoFrameFormat::PixelFormat::Format_Invalid);
126 Q_ASSERT(inputCvPixFormat != CvPixelFormatInvalid);
127 Q_ASSERT(avCaptureVideoDataOutput !=
nullptr);
129 using namespace Qt::Literals::StringLiterals;
131 if (avCaptureVideoDataOutput.availableVideoCVPixelFormatTypes.count == 0)
132 return q23::unexpected{
133 u"AVCaptureVideoDataOutput.availableVideoCVPixelFormatTypes is empty"_s };
135 auto bestScore = MinAVScore;
136 NSNumber *bestFormat =
nullptr;
137 for (NSNumber *cvPixFmtNumber in avCaptureVideoDataOutput.availableVideoCVPixelFormatTypes) {
138 const CvPixelFormat cvPixFmt = [cvPixFmtNumber unsignedIntValue];
139 const QVideoFrameFormat::PixelFormat pixFmt = QAVFHelpers::fromCVPixelFormat(cvPixFmt);
140 if (pixFmt == QVideoFrameFormat::Format_Invalid)
143 auto score = DefaultAVScore;
144 if (cvPixFmt == inputCvPixFormat)
146 if (pixFmt == cameraPixelFormat)
154 constexpr bool ShouldSuppressNotSupportedByFFmpeg =
false;
156 if (!isCVFormatSupported(cvPixFmt))
157 score -= ShouldSuppressNotSupportedByFFmpeg ? 100000 : 5;
159 if (score > bestScore) {
161 bestFormat = cvPixFmtNumber;
165 if (bestScore < DefaultAVScore)
166 qWarning() <<
"QAVFCamera::tryFindVideoDataOutputPixelFormat: "
167 "Cannot find hw FFmpeg supported cv pix format";
169 return [bestFormat unsignedIntValue];
176 return std::make_unique<QAVFCamera>(parent);
213 u"Camera object was destroyed before still photo capture was completed"_s);
252 u"Cannot attach AVCaptureDeviceInput to AVCaptureSession"_s };
329 u"Unable to connect AVCaptureVideoDataOutput to AVCaptureSession"_s };
445 return q23::
unexpected{ u"AVCaptureDevice not available"_s };
465 u"Unable to find any suitable AVCaptureDeviceFormat when attempting to "
466 "apply QCameraFormat"_s };
516 qWarning() <<
"QAVFCamera::onActiveChanged: Device not available";
526 qWarning() <<
"QAVFCamera::onActiveChanged: Failed to lock AVCaptureDevice";
537 <<
"QAVFCamera::onActiveChanged: Error when trying to activate camera:"
602 <<
"Error when trying to activate new camera-device: "
624 qWarning() <<
"QAVFCamera::tryApplyCameraFormat: Unable to find any suitable "
625 "AVCaptureDeviceFormat when attempting to apply QCameraFormat";
641 qWarning() <<
"QAVFCamera::tryApplyCameraFormat: Failed to lock AVCaptureDevice when "
642 "trying to apply new QCameraFormat.";
659 <<
"Error when trying to activate camera with new format: "
762 qCWarning(
qLcCamera) <<
"Attempted to take a still photo with an AVCapturePhotoOutput that "
763 "does not support output with 32BGRA format.";
764 return q23::
unexpected{ u"Internal camera configuration error"_s };
792 u"Attempted to start still photo capture with "
793 "capture-settings that are not supported by AVCapturePhotoOutput: '%1'"_s
797 return q23::
unexpected{ u"Internal camera configuration error"_s };
835#include "moc_qavfcamera_p.cpp"
std::unique_ptr< QPlatformCamera > makeQAvfCamera(QCamera &parent)
std::conditional_t< QT_FFMPEG_AVIO_WRITE_CONST, const uint8_t *, uint8_t * > AvioWriteBufferType
QT_NAMESPACE_ALIAS_OBJC_CLASS(QAVFCapturePhotoOutputDelegate)