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