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
qavfsamplebufferdelegate.mm
Go to the documentation of this file.
1// Copyright (C) 2022 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/qavfsamplebufferdelegate_p.h>
5
6#include <QtMultimedia/private/qavfhelpers_p.h>
7#include <QtMultimedia/private/qvideoframe_p.h>
8
9#include <QtFFmpegMediaPluginImpl/private/qcvimagevideobuffer_p.h>
10#include <QtFFmpegMediaPluginImpl/private/qffmpegdarwinhwframehelpers_p.h>
11#define AVMediaType XAVMediaType
12#include <QtFFmpegMediaPluginImpl/private/qffmpegvideobuffer_p.h>
13#include <QtFFmpegMediaPluginImpl/private/qffmpeghwaccel_p.h>
14#undef AVMediaType
15
16#include <optional>
17
18QT_USE_NAMESPACE
19
20@implementation QAVFSampleBufferDelegate {
21@private
22 std::function<void(const QVideoFrame &)> frameHandler;
23 QFFmpeg::QAVFSampleBufferDelegateTransformProvider transformationProvider;
24 AVBufferRef *hwFramesContext;
25 std::unique_ptr<QFFmpeg::HWAccel> m_accel;
26 qint64 startTime;
27 std::optional<qint64> baseTime;
28 qreal frameRate;
29}
30
31- (instancetype)initWithFrameHandler:(std::function<void(const QVideoFrame &)>)handler
32{
33 if (!(self = [super init]))
34 return nil;
35
36 Q_ASSERT(handler);
37
38 frameHandler = std::move(handler);
39 return self;
40}
41
42- (void)discardFutureSamples
43{
44 frameHandler = nullptr;
45}
46
47- (void)setTransformationProvider:
48 (const QFFmpeg::QAVFSampleBufferDelegateTransformProvider &)provider
49{
50 transformationProvider = std::move(provider);
51}
52
53- (void)captureOutput:(AVCaptureOutput *)captureOutput
54 didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
55 fromConnection:(AVCaptureConnection *)connection
56{
57 Q_UNUSED(captureOutput);
58
59 if (!frameHandler)
60 return;
61
62 // NB: on iOS captureOutput/connection can be nil (when recording a video -
63 // avfmediaassetwriter).
64
65 CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
66 if (!imageBuffer || CFGetTypeID(imageBuffer) != CVPixelBufferGetTypeID()) {
67 qWarning() << "Cannot get image buffer from sample buffer";
68 return;
69 }
70
71 auto pixelBuffer = QAVFHelpers::QSharedCVPixelBuffer(
72 imageBuffer,
73 QAVFHelpers::QSharedCVPixelBuffer::RefMode::NeedsRef);
74
75 const CMTime time = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
76 const qint64 frameTime = time.timescale ? time.value * 1000000 / time.timescale : 0;
77 if (!baseTime) {
78 baseTime = frameTime;
79 startTime = frameTime;
80 }
81
82 QVideoFrameFormat format = QAVFHelpers::videoFormatForImageBuffer(pixelBuffer.get());
83 if (!format.isValid()) {
84 qWarning() << "Cannot get get video format for image buffer"
85 << CVPixelBufferGetWidth(pixelBuffer.get()) << 'x'
86 << CVPixelBufferGetHeight(pixelBuffer.get());
87 return;
88 }
89
90 std::optional<QFFmpeg::QAVFSampleBufferDelegateTransform> transform;
91 if (transformationProvider) {
92 transform = transformationProvider(connection);
93 const VideoTransformation &surfaceTransform = transform.value().surfaceTransform;
94 format.setRotation(surfaceTransform.rotation);
95 format.setMirrored(surfaceTransform.mirroredHorizontallyAfterRotation);
96 }
97
98 format.setStreamFrameRate(frameRate);
99
100 Q_ASSERT(self->m_accel);
101 auto frame = QFFmpeg::qVideoFrameFromCvPixelBuffer(
102 *m_accel,
103 startTime - *baseTime,
104 pixelBuffer,
105 format);
106 if (!frame.isValid())
107 frame = QVideoFramePrivate::createFrame(
108 std::make_unique<QFFmpeg::CVImageVideoBuffer>(std::move(pixelBuffer)),
109 std::move(format));
110
111 if (transform.has_value()) {
112 const VideoTransformation &presentationTransform = transform.value().presentationTransform;
113 frame.setRotation(presentationTransform.rotation);
114 frame.setMirrored(presentationTransform.mirroredHorizontallyAfterRotation);
115 }
116
117 frame.setStartTime(startTime - *baseTime);
118 frame.setEndTime(frameTime - *baseTime);
119 startTime = frameTime;
120
121 frameHandler(frame);
122}
123
124- (void)setHWAccel:(std::unique_ptr<QFFmpeg::HWAccel> &&)accel
125{
126 m_accel = std::move(accel);
127}
128
129- (void)setVideoFormatFrameRate:(qreal)rate
130{
131 frameRate = rate;
132}
133
134@end