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