4#include <QtFFmpegMediaPluginImpl/private/qavfcamera_p.h>
6#include <QtCore/qscopeguard.h>
7#include <QtCore/private/qcore_mac_p.h>
9#include <QtFFmpegMediaPluginImpl/private/qavfcapturephotooutputdelegate_p.h>
10#include <QtFFmpegMediaPluginImpl/private/qavfsamplebufferdelegate_p.h>
11#include <QtFFmpegMediaPluginImpl/private/qffmpegdarwinintegrationfactory_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>
32[[nodiscard]] AVCaptureFlashMode toAvfFlashMode(QCamera::FlashMode flashMode)
35 case QCamera::FlashMode::FlashOff:
36 return AVCaptureFlashModeOff;
37 case QCamera::FlashMode::FlashAuto:
38 return AVCaptureFlashModeAuto;
39 case QCamera::FlashMode::FlashOn:
40 return AVCaptureFlashModeOn;
42 return AVCaptureFlashModeOff;
45[[nodiscard]]
bool checkAvCapturePhotoFormatSupport(AVCapturePhotoOutput *output,
int cvPixelFormat)
48 NSArray<NSNumber *> *supportedFormats = output.availablePhotoPixelFormatTypes;
49 for (NSNumber *format : supportedFormats) {
50 if (format.intValue == cvPixelFormat)
56[[nodiscard]] QAVFSampleBufferDelegateTransform surfaceTransform(
57 const QFFmpeg::AvfCameraRotationTracker *rotationTracker,
58 const AVCaptureConnection *connection)
60 QAVFSampleBufferDelegateTransform transform = {};
64 if (rotationTracker !=
nullptr) {
65 captureAngle = rotationTracker->rotationDegrees();
67 bool cameraIsFrontFacing =
68 rotationTracker->avCaptureDevice() !=
nullptr
69 && rotationTracker->avCaptureDevice().position == AVCaptureDevicePositionFront;
70 if (cameraIsFrontFacing)
71 transform.presentationTransform.mirroredHorizontallyAfterRotation =
true;
80 int connectionAngle = 0;
82 if (@available(macOS 14.0, iOS 17.0, *))
83 connectionAngle =
std::lround(connection.videoRotationAngle);
85 if (connection.videoMirrored)
86 transform.surfaceTransform.mirroredHorizontallyAfterRotation =
true;
89 transform.surfaceTransform.rotation = qVideoRotationFromDegrees(captureAngle - connectionAngle);
96[[nodiscard]]
static AVCaptureDeviceFormat* findSuitableAvCaptureDeviceFormat(
97 AVCaptureDevice *avCaptureDevice,
98 const QCameraFormat &format)
100 Q_ASSERT(avCaptureDevice !=
nullptr);
101 Q_ASSERT(!format.isNull());
105 AVCaptureDeviceFormat *newDeviceFormat = qt_convert_to_capture_device_format(
108 &QFFmpeg::isCVFormatSupported);
112 if (!newDeviceFormat)
113 newDeviceFormat = qt_convert_to_capture_device_format(avCaptureDevice, format);
115 return newDeviceFormat;
118[[nodiscard]]
static q23::expected<CvPixelFormat, QString> tryFindVideoDataOutputPixelFormat(
119 QVideoFrameFormat::PixelFormat cameraPixelFormat,
120 CvPixelFormat inputCvPixFormat,
121 AVCaptureVideoDataOutput *avCaptureVideoDataOutput)
123 Q_ASSERT(cameraPixelFormat != QVideoFrameFormat::PixelFormat::Format_Invalid);
124 Q_ASSERT(inputCvPixFormat != CvPixelFormatInvalid);
125 Q_ASSERT(avCaptureVideoDataOutput);
127 using namespace Qt::Literals::StringLiterals;
129 if (avCaptureVideoDataOutput.availableVideoCVPixelFormatTypes.count == 0)
130 return q23::unexpected{
131 u"AVCaptureVideoDataOutput.availableVideoCVPixelFormatTypes is empty"_s };
133 auto bestScore = MinAVScore;
134 NSNumber *bestFormat =
nullptr;
135 for (NSNumber *cvPixFmtNumber in avCaptureVideoDataOutput.availableVideoCVPixelFormatTypes) {
136 const CvPixelFormat cvPixFmt = [cvPixFmtNumber unsignedIntValue];
137 const QVideoFrameFormat::PixelFormat pixFmt = QAVFHelpers::fromCVPixelFormat(cvPixFmt);
138 if (pixFmt == QVideoFrameFormat::Format_Invalid)
141 auto score = DefaultAVScore;
142 if (cvPixFmt == inputCvPixFormat)
144 if (pixFmt == cameraPixelFormat)
152 constexpr bool ShouldSuppressNotSupportedByFFmpeg =
false;
154 if (!isCVFormatSupported(cvPixFmt))
155 score -= ShouldSuppressNotSupportedByFFmpeg ? 100000 : 5;
157 if (score > bestScore) {
159 bestFormat = cvPixFmtNumber;
163 if (bestScore < DefaultAVScore)
164 qWarning() <<
"QAVFCamera::tryFindVideoDataOutputPixelFormat: "
165 "Cannot find hw FFmpeg supported cv pix format";
167 return [bestFormat unsignedIntValue];
174 return std::make_unique<QAVFCamera>(parent);
211 u"Camera object was destroyed before still photo capture was completed"_s);
248 u"Cannot attach AVCaptureDeviceInput to AVCaptureSession"_s };
321 u"Unable to connect AVCaptureVideoDataOutput to AVCaptureSession"_s };
437 return q23::
unexpected{ u"AVCaptureDevice not available"_s };
457 u"Unable to find any suitable AVCaptureDeviceFormat when attempting to "
458 "apply QCameraFormat"_s };
508 qWarning() <<
"QAVFCamera::onActiveChanged: Device not available";
518 qWarning() <<
"QAVFCamera::onActiveChanged: Failed to lock AVCaptureDevice";
529 <<
"QAVFCamera::onActiveChanged: Error when trying to activate camera:"
594 <<
"Error when trying to activate new camera-device: "
616 qWarning() <<
"QAVFCamera::tryApplyCameraFormat: Unable to find any suitable "
617 "AVCaptureDeviceFormat when attempting to apply QCameraFormat";
633 qWarning() <<
"QAVFCamera::tryApplyCameraFormat: Failed to lock AVCaptureDevice when "
634 "trying to apply new QCameraFormat.";
651 <<
"Error when trying to activate camera with new format: "
754 qCWarning(
qLcCamera) <<
"Attempted to take a still photo with an AVCapturePhotoOutput that "
755 "does not support output with 32BGRA format.";
756 return q23::
unexpected{ u"Internal camera configuration error"_s };
784 u"Attempted to start still photo capture with "
785 "capture-settings that are not supported by AVCapturePhotoOutput: '%1'"_s
789 return q23::
unexpected{ u"Internal camera configuration error"_s };
827#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