iOS video frame render implementation.

Uses CVTextureCache, iOS only for now, OS-X code could be ported
but will need further work to support TEXTURE_RECTANGLE in the
QVideoNode classes.

When we can’t share a context, falls back to an offscreen window,
FBO rendering and grabbing a QImage.

Change-Id: I23b831fdcc63aeb1b67b7741d8d56779470240d3
Reviewed-by: Yoann Lopes <yoann.lopes@theqtcompany.com>
This commit is contained in:
James Turner
2015-01-12 13:51:25 +00:00
committed by Yoann Lopes
parent 3e94b7ce2d
commit 9444c8ec61
8 changed files with 576 additions and 62 deletions

View File

@@ -46,8 +46,70 @@
#include <QtCore/qdebug.h>
#endif
#if defined(Q_OS_IOS)
#import <QuartzCore/CADisplayLink.h>
#import <Foundation/NSRunLoop.h>
#define _m_displayLink static_cast<DisplayLinkObserver*>(m_displayLink)
#else
#endif
QT_USE_NAMESPACE
#if defined(Q_OS_IOS)
@interface DisplayLinkObserver : NSObject
{
AVFDisplayLink *m_avfDisplayLink;
CADisplayLink *m_displayLink;
}
- (void)start;
- (void)stop;
- (void)displayLinkNotification:(CADisplayLink *)sender;
@end
@implementation DisplayLinkObserver
- (id)initWithAVFDisplayLink:(AVFDisplayLink *)link
{
self = [super init];
if (self) {
m_avfDisplayLink = link;
m_displayLink = [[CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkNotification:)] retain];
}
return self;
}
- (void) dealloc
{
if (m_displayLink) {
[m_displayLink release];
m_displayLink = NULL;
}
[super dealloc];
}
- (void)start
{
[m_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)stop
{
[m_displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)displayLinkNotification:(CADisplayLink *)sender
{
Q_UNUSED(sender);
m_avfDisplayLink->displayLinkEvent(nullptr);
}
@end
#else
static CVReturn CVDisplayLinkCallback(CVDisplayLinkRef displayLink,
const CVTimeStamp *inNow,
const CVTimeStamp *inOutputTime,
@@ -65,12 +127,17 @@ static CVReturn CVDisplayLinkCallback(CVDisplayLinkRef displayLink,
link->displayLinkEvent(inOutputTime);
return kCVReturnSuccess;
}
#endif
AVFDisplayLink::AVFDisplayLink(QObject *parent)
: QObject(parent)
, m_displayLink(0)
, m_pendingDisplayLinkEvent(false)
, m_isActive(false)
{
#if defined(Q_OS_IOS)
m_displayLink = [[DisplayLinkObserver alloc] initWithAVFDisplayLink:this];
#else
// create display link for the main display
CVDisplayLinkCreateWithCGDisplay(kCGDirectMainDisplay, &m_displayLink);
if (m_displayLink) {
@@ -80,6 +147,7 @@ AVFDisplayLink::AVFDisplayLink(QObject *parent)
// set the renderer output callback function
CVDisplayLinkSetOutputCallback(m_displayLink, &CVDisplayLinkCallback, this);
}
#endif
}
AVFDisplayLink::~AVFDisplayLink()
@@ -89,8 +157,12 @@ AVFDisplayLink::~AVFDisplayLink()
#endif
if (m_displayLink) {
CVDisplayLinkStop(m_displayLink);
stop();
#if defined(Q_OS_IOS)
[_m_displayLink release];
#else
CVDisplayLinkRelease(m_displayLink);
#endif
m_displayLink = NULL;
}
}
@@ -108,20 +180,27 @@ bool AVFDisplayLink::isActive() const
void AVFDisplayLink::start()
{
if (m_displayLink && !m_isActive) {
CVDisplayLinkStart(m_displayLink);
m_isActive = true;
#if defined(Q_OS_IOS)
[_m_displayLink start];
#else
CVDisplayLinkStart(m_displayLink);
#endif
m_isActive = true;
}
}
void AVFDisplayLink::stop()
{
if (m_displayLink && m_isActive) {
#if defined(Q_OS_IOS)
[_m_displayLink stop];
#else
CVDisplayLinkStop(m_displayLink);
#endif
m_isActive = false;
}
}
void AVFDisplayLink::displayLinkEvent(const CVTimeStamp *ts)
{
// This function is called from a
@@ -131,7 +210,12 @@ void AVFDisplayLink::displayLinkEvent(const CVTimeStamp *ts)
m_displayLinkMutex.lock();
bool pending = m_pendingDisplayLinkEvent;
m_pendingDisplayLinkEvent = true;
#if defined(Q_OS_IOS)
Q_UNUSED(ts);
memset(&m_frameTimeStamp, 0, sizeof(CVTimeStamp));
#else
m_frameTimeStamp = *ts;
#endif
m_displayLinkMutex.unlock();
if (!pending)