4#include <QtFFmpegMediaPluginImpl/private/qavfsamplebufferdelegate_p.h>
6#include <QtMultimedia/private/qavfhelpers_p.h>
7#include <QtMultimedia/private/qvideoframe_p.h>
9#define AVMediaType XAVMediaType
10#include <QtFFmpegMediaPluginImpl/private/qffmpegvideobuffer_p.h>
11#include <QtFFmpegMediaPluginImpl/private/qffmpeghwaccel_p.h>
20 CVPixelBufferRelease(CVPixelBufferRef(data));
25class CVImageVideoBuffer :
public QAbstractVideoBuffer
28 CVImageVideoBuffer(CVImageBufferRef imageBuffer) : m_buffer(imageBuffer)
30 CVPixelBufferRetain(imageBuffer);
35 Q_ASSERT(m_mode == QVideoFrame::NotMapped);
36 CVPixelBufferRelease(m_buffer);
39 CVImageVideoBuffer::MapData map(QVideoFrame::MapMode mode)
override
43 if (m_mode == QVideoFrame::NotMapped) {
44 CVPixelBufferLockBaseAddress(
45 m_buffer, mode == QVideoFrame::ReadOnly ? kCVPixelBufferLock_ReadOnly : 0);
49 mapData.planeCount = CVPixelBufferGetPlaneCount(m_buffer);
50 Q_ASSERT(mapData.planeCount <= 3);
52 if (!mapData.planeCount) {
54 mapData.bytesPerLine[0] = CVPixelBufferGetBytesPerRow(m_buffer);
55 mapData.data[0] =
static_cast<uchar *>(CVPixelBufferGetBaseAddress(m_buffer));
56 mapData.dataSize[0] = CVPixelBufferGetDataSize(m_buffer);
57 mapData.planeCount = mapData.data[0] ? 1 : 0;
62 for (
int i = 0; i < mapData.planeCount; ++i) {
63 mapData.bytesPerLine[i] = CVPixelBufferGetBytesPerRowOfPlane(m_buffer, i);
64 mapData.dataSize[i] = mapData.bytesPerLine[i] * CVPixelBufferGetHeightOfPlane(m_buffer, i);
65 mapData.data[i] =
static_cast<uchar *>(CVPixelBufferGetBaseAddressOfPlane(m_buffer, i));
73 if (m_mode != QVideoFrame::NotMapped) {
74 CVPixelBufferUnlockBaseAddress(
75 m_buffer, m_mode == QVideoFrame::ReadOnly ? kCVPixelBufferLock_ReadOnly : 0);
76 m_mode = QVideoFrame::NotMapped;
80 QVideoFrameFormat format()
const override {
return {}; }
83 CVImageBufferRef m_buffer;
84 QVideoFrame::MapMode m_mode = QVideoFrame::NotMapped;
92 AVHWFramesContext *ctx = (AVHWFramesContext *)hwContext->data;
93 auto frame = QFFmpeg::makeAVFrame();
94 frame->hw_frames_ctx = av_buffer_ref(hwContext);
95 frame->extended_data = frame->data;
97 frame->buf[0] = av_buffer_create((uint8_t *)pixbuf, 1, releaseHwFrame, NULL, 0);
98 frame->data[3] = (uint8_t *)pixbuf;
99 CVPixelBufferRetain(pixbuf);
100 frame->width = ctx->width;
101 frame->height = ctx->height;
102 frame->format = AV_PIX_FMT_VIDEOTOOLBOX;
103 if (frame->width != (
int)CVPixelBufferGetWidth(pixbuf)
104 || frame->height != (
int)CVPixelBufferGetHeight(pixbuf)) {
112@implementation QAVFSampleBufferDelegate {
114 std::function<
void(
const QVideoFrame &)> frameHandler;
115 QFFmpeg::QAVFSampleBufferDelegateTransformProvider transformationProvider;
116 AVBufferRef *hwFramesContext;
117 std::unique_ptr<QFFmpeg::HWAccel> m_accel;
119 std::optional<qint64> baseTime;
123static QVideoFrame createHwVideoFrame(QAVFSampleBufferDelegate &delegate,
124 CVImageBufferRef imageBuffer, QVideoFrameFormat format)
126 Q_ASSERT(delegate.baseTime);
128 if (!delegate.m_accel)
131 auto avFrame = allocHWFrame(delegate.m_accel->hwFramesContextAsBuffer(), imageBuffer);
137 auto swFrame = QFFmpeg::makeAVFrame();
139 const int ret = av_hwframe_transfer_data(swFrame.get(), avFrame.get(), 0);
141 qWarning() <<
"Error transferring the data to system memory:" << ret;
143 avFrame = std::move(swFrame);
148 avFrame->pts = delegate.startTime - *delegate.baseTime;
150 return QVideoFramePrivate::createFrame(std::make_unique<QFFmpegVideoBuffer>(std::move(avFrame)),
154- (instancetype)initWithFrameHandler:(std::function<
void(
const QVideoFrame &)>)handler
156 if (!(self = [super init]))
161 frameHandler = std::move(handler);
162 hwFramesContext =
nullptr;
168- (
void)discardFutureSamples
170 frameHandler =
nullptr;
173- (
void)setTransformationProvider:
174 (
const QFFmpeg::QAVFSampleBufferDelegateTransformProvider &)provider
176 transformationProvider = std::move(provider);
179- (
void)captureOutput:(AVCaptureOutput *)captureOutput
180 didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
181 fromConnection:(AVCaptureConnection *)connection
183 Q_UNUSED(captureOutput);
191 CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
194 qWarning() <<
"Cannot get image buffer from sample buffer";
198 const CMTime time = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
199 const qint64 frameTime = time.timescale ? time.value * 1000000 / time.timescale : 0;
201 baseTime = frameTime;
202 startTime = frameTime;
205 QVideoFrameFormat format = QAVFHelpers::videoFormatForImageBuffer(imageBuffer);
206 if (!format.isValid()) {
207 qWarning() <<
"Cannot get get video format for image buffer"
208 << CVPixelBufferGetWidth(imageBuffer) <<
'x'
209 << CVPixelBufferGetHeight(imageBuffer);
213 std::optional<QFFmpeg::QAVFSampleBufferDelegateTransform> transform;
214 if (transformationProvider) {
215 transform = transformationProvider(connection);
216 const VideoTransformation &surfaceTransform = transform.value().surfaceTransform;
217 format.setRotation(surfaceTransform.rotation);
218 format.setMirrored(surfaceTransform.mirroredHorizontallyAfterRotation);
221 format.setStreamFrameRate(frameRate);
223 auto frame = createHwVideoFrame(*self, imageBuffer, format);
224 if (!frame.isValid())
225 frame = QVideoFramePrivate::createFrame(std::make_unique<CVImageVideoBuffer>(imageBuffer),
228 if (transform.has_value()) {
229 const VideoTransformation &presentationTransform = transform.value().presentationTransform;
230 frame.setRotation(presentationTransform.rotation);
231 frame.setMirrored(presentationTransform.mirroredHorizontallyAfterRotation);
234 frame.setStartTime(startTime - *baseTime);
235 frame.setEndTime(frameTime - *baseTime);
236 startTime = frameTime;
241- (
void)setHWAccel:(std::unique_ptr<QFFmpeg::HWAccel> &&)accel
243 m_accel = std::move(accel);
246- (
void)setVideoFormatFrameRate:(qreal)rate
static QFFmpeg::AVFrameUPtr allocHWFrame(AVBufferRef *hwContext, const CVPixelBufferRef &pixbuf)
static QT_USE_NAMESPACE void releaseHwFrame(void *, uint8_t *data)