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
avfvideorenderercontrol.mm
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6#include <avfvideobuffer_p.h>
7#include <QtMultimedia/private/qavfhelpers_p.h>
8#include "private/qvideoframe_p.h"
9
10#include <QtMultimedia/qvideoframeformat.h>
11
12#include <avfvideosink_p.h>
13#include <rhi/qrhi.h>
14
15#include <QtCore/qdebug.h>
16
17#import <AVFoundation/AVFoundation.h>
18#include <CoreVideo/CVPixelBuffer.h>
19#include <CoreVideo/CVImageBuffer.h>
20
21QT_USE_NAMESPACE
22
23@interface SubtitleDelegate : NSObject <AVPlayerItemLegibleOutputPushDelegate>
24{
25 AVFVideoRendererControl *m_renderer;
27
28- (void)legibleOutput:(AVPlayerItemLegibleOutput *)output
29 didOutputAttributedStrings:(NSArray<NSAttributedString *> *)strings
30 nativeSampleBuffers:(NSArray *)nativeSamples
31 forItemTime:(CMTime)itemTime;
32
33@end
34
35@implementation SubtitleDelegate
36
37-(id)initWithRenderer: (AVFVideoRendererControl *)renderer
38{
39 if (!(self = [super init]))
40 return nil;
41
42 m_renderer = renderer;
43
44 return self;
45}
46
47- (void)legibleOutput:(AVPlayerItemLegibleOutput *)output
48 didOutputAttributedStrings:(NSArray<NSAttributedString *> *)strings
49 nativeSampleBuffers:(NSArray *)nativeSamples
50 forItemTime:(CMTime)itemTime
51{
52 QString text;
53 for (NSAttributedString *s : strings) {
54 if (!text.isEmpty())
55 text += QChar::LineSeparator;
56 text += QString::fromNSString(s.string);
57 }
58 m_renderer->setSubtitleText(text);
59}
60
61@end
62
63
64AVFVideoRendererControl::AVFVideoRendererControl(QObject *parent)
65 : QObject(parent)
66{
67 m_displayLink = new AVFDisplayLink(this);
68
69 connect(m_displayLink, &AVFDisplayLink::tick, this, &AVFVideoRendererControl::updateVideoFrame);
70}
71
74#ifdef QT_DEBUG_AVF
75 qDebug() << Q_FUNC_INFO;
76#endif
77 m_displayLink->stop();
78 m_displayLink->disconnect(this);
79 if (m_videoOutput)
80 [m_videoOutput release];
81 if (m_subtitleOutput)
82 [m_subtitleOutput release];
83 if (m_subtitleDelegate)
84 [m_subtitleDelegate release];
85}
86
89#ifdef QT_DEBUG_AVF
90 qDebug() << "reconfigure";
91#endif
92 if (!m_layer) {
93 m_displayLink->stop();
94 return;
95 }
96
97 QMutexLocker locker(&m_mutex);
98
99 m_displayLink->start();
100
102}
103
104void AVFVideoRendererControl::setLayer(CALayer *layer)
106 if (m_layer == layer)
107 return;
108
109 AVPlayerLayer *plLayer = playerLayer();
110 if (plLayer) {
111 if (m_videoOutput)
112 [[[plLayer player] currentItem] removeOutput:m_videoOutput];
113
114 if (m_subtitleOutput)
115 [[[plLayer player] currentItem] removeOutput:m_subtitleOutput];
116 }
117
118 if (!layer && m_sink)
119 m_sink->setVideoFrame(QVideoFrame());
120
121 AVFVideoSinkInterface::setLayer(layer);
122}
123
124void AVFVideoRendererControl::setVideoRotation(QtVideo::Rotation rotation)
126 m_rotation = rotation;
127}
128
129void AVFVideoRendererControl::setVideoMirrored(bool mirrored)
131 m_mirrored = mirrored;
132}
133
134void AVFVideoRendererControl::updateVideoFrame(const CVTimeStamp &ts)
135{
136 Q_UNUSED(ts);
137
138 if (!m_sink)
139 return;
140
141 if (!m_layer)
142 return;
143
144 auto *layer = playerLayer();
145 if (!layer.readyForDisplay)
146 return;
148
149 QVideoFrame frame;
150 size_t width, height;
151 QCFType<CVPixelBufferRef> pixelBuffer = copyPixelBufferFromLayer(width, height);
152 if (!pixelBuffer)
153 return;
154 // qDebug() << "Got pixelbuffer with format" << fmt << Qt::hex <<
155 // CVPixelBufferGetPixelFormatType(pixelBuffer);
156 auto buffer = std::make_unique<AVFVideoBuffer>(this, std::move(pixelBuffer));
157
158 const auto format = buffer->videoFormat();
159 frame = QVideoFramePrivate::createFrame(std::move(buffer), format);
160 frame.setRotation(m_rotation);
161 frame.setMirrored(m_mirrored);
162 m_sink->setVideoFrame(frame);
163}
164
165QCFType<CVPixelBufferRef> AVFVideoRendererControl::copyPixelBufferFromLayer(size_t &width,
166 size_t &height)
167{
168 AVPlayerLayer *layer = playerLayer();
169 //Is layer valid
170 if (!layer) {
171#ifdef QT_DEBUG_AVF
172 qWarning("copyPixelBufferFromLayer: invalid layer");
173#endif
174 return nullptr;
175 }
176
177 AVPlayerItem * item = [[layer player] currentItem];
178
179 if (!m_videoOutput) {
180 if (!m_outputSettings)
181 setOutputSettings();
182 m_videoOutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:m_outputSettings];
183 [m_videoOutput setDelegate:nil queue:nil];
184 }
185 if (!m_subtitleOutput) {
186 m_subtitleOutput = [[AVPlayerItemLegibleOutput alloc] init];
187 m_subtitleDelegate = [[SubtitleDelegate alloc] initWithRenderer:this];
188 [m_subtitleOutput setDelegate:m_subtitleDelegate queue:dispatch_get_main_queue()];
189 }
190 if (![item.outputs containsObject:m_videoOutput])
191 [item addOutput:m_videoOutput];
192 if (![item.outputs containsObject:m_subtitleOutput])
193 [item addOutput:m_subtitleOutput];
194
195 CFTimeInterval currentCAFrameTime = CACurrentMediaTime();
196 CMTime currentCMFrameTime = [m_videoOutput itemTimeForHostTime:currentCAFrameTime];
197 // happens when buffering / loading
198 if (CMTimeCompare(currentCMFrameTime, kCMTimeZero) < 0) {
199 return nullptr;
200 }
201
202 if (![m_videoOutput hasNewPixelBufferForItemTime:currentCMFrameTime])
203 return nullptr;
204
205 CVPixelBufferRef pixelBuffer = [m_videoOutput copyPixelBufferForItemTime:currentCMFrameTime
206 itemTimeForDisplay:nil];
207 if (!pixelBuffer) {
208#ifdef QT_DEBUG_AVF
209 qWarning("copyPixelBufferForItemTime returned nil");
210 CMTimeShow(currentCMFrameTime);
211#endif
212 return nullptr;
213 }
214
215 width = CVPixelBufferGetWidth(pixelBuffer);
216 height = CVPixelBufferGetHeight(pixelBuffer);
217// auto f = CVPixelBufferGetPixelFormatType(pixelBuffer);
218// char fmt[5];
219// memcpy(fmt, &f, 4);
220// fmt[4] = 0;
221// qDebug() << "copyPixelBuffer" << f << fmt << width << height;
222 return QCFType<CVPixelBufferRef>{ pixelBuffer };
223}
224
225#include "moc_avfvideorenderercontrol_p.cpp"
void setVideoRotation(QtVideo::Rotation)
AVFVideoSink * m_sink