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
avfdisplaylink.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
5
6#include <QtCore/qcoreapplication.h>
7
8#ifdef QT_DEBUG_AVF
9#include <QtCore/qdebug.h>
10#endif
11
12#include <mutex>
13
14#if defined(QT_PLATFORM_UIKIT)
15#import <QuartzCore/CADisplayLink.h>
16#import <Foundation/NSRunLoop.h>
17#endif
18
19QT_USE_NAMESPACE
20
21#if defined(QT_PLATFORM_UIKIT)
22
23@implementation DisplayLinkObserver
24{
25 AVFDisplayLink *m_avfDisplayLink;
26 CADisplayLink *m_displayLink;
27}
28
29- (id)initWithAVFDisplayLink:(AVFDisplayLink *)link
30{
31 self = [super init];
32
33 if (self) {
34 m_avfDisplayLink = link;
35 m_displayLink = [[CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkNotification:)] retain];
36 }
37
38 return self;
39}
40
41- (void) dealloc
42{
43 if (m_displayLink) {
44 [m_displayLink release];
45 m_displayLink = nullptr;
46 }
47
48 [super dealloc];
49}
50
51- (void)start
52{
53 [m_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
54}
55
56- (void)stop
57{
58 [m_displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
59}
60
61- (void)displayLinkNotification:(CADisplayLink *)sender
62{
63 Q_UNUSED(sender);
64 m_avfDisplayLink->displayLinkEvent(nullptr);
65}
66
67@end
68#else
69static CVReturn CVDisplayLinkCallback([[maybe_unused]] CVDisplayLinkRef displayLink,
70 [[maybe_unused]] const CVTimeStamp *inNow,
71 const CVTimeStamp *inOutputTime,
72 [[maybe_unused]] CVOptionFlags flagsIn,
73 [[maybe_unused]] CVOptionFlags *flagsOut,
74 void *displayLinkContext)
75{
76 AVFDisplayLink *link = (AVFDisplayLink *)displayLinkContext;
77
78 link->displayLinkEvent(inOutputTime);
79 return kCVReturnSuccess;
80}
81#endif
82
83AVFDisplayLink::AVFDisplayLink(QObject *parent)
84 : QObject(parent)
85{
86#if defined(QT_PLATFORM_UIKIT)
87 m_displayLink = [[DisplayLinkObserver alloc] initWithAVFDisplayLink:this];
88#else
89 // create display link for the main display
90 CVDisplayLinkCreateWithCGDisplay(kCGDirectMainDisplay, &m_displayLink);
91 if (m_displayLink) {
92 // set the current display of a display link.
93 CVDisplayLinkSetCurrentCGDisplay(m_displayLink, kCGDirectMainDisplay);
94
95 // set the renderer output callback function
96 CVDisplayLinkSetOutputCallback(m_displayLink, &CVDisplayLinkCallback, this);
97 }
98#endif
99}
100
101AVFDisplayLink::~AVFDisplayLink()
102{
103#ifdef QT_DEBUG_AVF
104 qDebug() << Q_FUNC_INFO;
105#endif
106
107 if (m_displayLink) {
108 stop();
109#if defined(QT_PLATFORM_UIKIT)
110 [m_displayLink release];
111#else
112 CVDisplayLinkRelease(m_displayLink);
113#endif
114 m_displayLink = nullptr;
115 }
116}
117
118bool AVFDisplayLink::isValid() const
119{
120 return m_displayLink != nullptr;
121}
122
123bool AVFDisplayLink::isActive() const
124{
125 return m_isActive;
126}
127
128void AVFDisplayLink::start()
129{
130 if (m_displayLink && !m_isActive) {
131#if defined(QT_PLATFORM_UIKIT)
132 [m_displayLink start];
133#else
134 CVDisplayLinkStart(m_displayLink);
135#endif
136 m_isActive = true;
137 }
138}
139
140void AVFDisplayLink::stop()
141{
142 if (m_displayLink && m_isActive) {
143#if defined(QT_PLATFORM_UIKIT)
144 [m_displayLink stop];
145#else
146 CVDisplayLinkStop(m_displayLink);
147#endif
148 m_isActive = false;
149
150 // cancel pending events
151 std::lock_guard guard{ m_displayLinkMutex };
152 m_frameTimeStamp = std::nullopt;
153 }
154}
155
156void AVFDisplayLink::displayLinkEvent(const CVTimeStamp *ts)
157{
158 // This function is called from a
159 // thread != gui thread. So we post the event.
160 // But we need to make sure that we don't post faster
161 // than the event loop can eat:
162 std::unique_lock guard{ m_displayLinkMutex };
163
164 bool pending = m_frameTimeStamp.has_value();
165#if defined(QT_PLATFORM_UIKIT)
166 Q_UNUSED(ts);
167 m_frameTimeStamp = CVTimeStamp{};
168#else
169 m_frameTimeStamp = *ts;
170#endif
171 guard.unlock();
172
173 if (!pending)
174 qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority);
175}
176
177bool AVFDisplayLink::event(QEvent *event)
178{
179 switch (event->type()){
180 case QEvent::User: {
181 std::unique_lock guard{ m_displayLinkMutex };
182 if (!m_frameTimeStamp)
183 return false;
184
185 CVTimeStamp ts = *m_frameTimeStamp;
186 m_frameTimeStamp = std::nullopt;
187 guard.unlock();
188
189 Q_EMIT tick(ts);
190
191 return false;
192 }
193 default:
194 break;
195 }
196 return QObject::event(event);
197}
198
199#include "moc_avfdisplaylink_p.cpp"