1
/****************************************************************************
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include "avfvideoframerenderer.h"
44
#include <QtMultimedia/qabstractvideosurface.h>
45
#include <QtGui/QOpenGLFramebufferObject>
46
#include <QtGui/QWindow>
49
#include <QtCore/qdebug.h>
52
#import <CoreVideo/CVBase.h>
53
#import <AVFoundation/AVFoundation.h>
57
AVFVideoFrameRenderer::AVFVideoFrameRenderer(QAbstractVideoSurface *surface, QObject *parent)
59
, m_videoLayerRenderer(0)
63
, m_isContextShared(true)
68
//Create Hidden QWindow surface to create context in this thread
69
m_offscreenSurface = new QWindow();
70
m_offscreenSurface->setSurfaceType(QWindow::OpenGLSurface);
71
//Needs geometry to be a valid surface, but size is not important
72
m_offscreenSurface->setGeometry(0, 0, 1, 1);
73
m_offscreenSurface->create();
76
AVFVideoFrameRenderer::~AVFVideoFrameRenderer()
79
qDebug() << Q_FUNC_INFO;
82
[m_videoLayerRenderer release];
85
delete m_offscreenSurface;
89
GLuint AVFVideoFrameRenderer::renderLayerToTexture(AVPlayerLayer *layer)
95
//If the glContext isn't shared, it doesn't make sense to return a texture for us
96
if (m_offscreenSurface && !m_isContextShared)
99
QOpenGLFramebufferObject *fbo = initRenderer(layer);
104
renderLayerToFBO(layer, fbo);
105
m_glContext->doneCurrent();
107
return fbo->texture();
110
QImage AVFVideoFrameRenderer::renderLayerToImage(AVPlayerLayer *layer)
117
QOpenGLFramebufferObject *fbo = initRenderer(layer);
122
renderLayerToFBO(layer, fbo);
123
QImage fboImage = fbo->toImage();
124
m_glContext->doneCurrent();
129
QOpenGLFramebufferObject *AVFVideoFrameRenderer::initRenderer(AVPlayerLayer *layer)
132
//Get size from AVPlayerLayer
133
m_targetSize = QSize(layer.bounds.size.width, layer.bounds.size.height);
135
//Make sure we have an OpenGL context to make current
137
//Create OpenGL context and set share context from surface
138
QOpenGLContext *shareContext = 0;
140
//QOpenGLContext *renderThreadContext = 0;
141
shareContext = qobject_cast<QOpenGLContext*>(m_surface->property("GLContext").value<QObject*>());
143
m_glContext = new QOpenGLContext();
144
m_glContext->setFormat(m_offscreenSurface->requestedFormat());
147
m_glContext->setShareContext(shareContext);
148
m_isContextShared = true;
151
qWarning("failed to get Render Thread context");
153
m_isContextShared = false;
155
if (!m_glContext->create()) {
156
qWarning("failed to create QOpenGLContext");
161
//Need current context
162
m_glContext->makeCurrent(m_offscreenSurface);
164
//Create the CARenderer if needed
165
if (!m_videoLayerRenderer) {
166
m_videoLayerRenderer = [CARenderer rendererWithCGLContext: CGLGetCurrentContext() options: nil];
167
[m_videoLayerRenderer retain];
170
//Set/Change render source if needed
171
if (m_videoLayerRenderer.layer != layer) {
172
m_videoLayerRenderer.layer = layer;
173
m_videoLayerRenderer.bounds = layer.bounds;
176
//Do we have FBO's already?
177
if ((!m_fbo[0] && !m_fbo[0]) || (m_fbo[0]->size() != m_targetSize)) {
180
m_fbo[0] = new QOpenGLFramebufferObject(m_targetSize);
181
m_fbo[1] = new QOpenGLFramebufferObject(m_targetSize);
184
//Switch buffer target
185
m_currentBuffer = !m_currentBuffer;
186
return m_fbo[m_currentBuffer];
189
void AVFVideoFrameRenderer::renderLayerToFBO(AVPlayerLayer *layer, QOpenGLFramebufferObject *fbo)
192
//NOTE: This rendering method will NOT work on iOS as there is no CARenderer in iOS
194
qWarning("AVFVideoRender FBO failed to bind");
198
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
199
glClear(GL_COLOR_BUFFER_BIT);
201
glViewport(0, 0, m_targetSize.width(), m_targetSize.height());
203
glMatrixMode(GL_PROJECTION);
207
//Render to FBO with inverted Y
208
glOrtho(0.0, m_targetSize.width(), 0.0, m_targetSize.height(), 0.0, 1.0);
210
glMatrixMode(GL_MODELVIEW);
214
[m_videoLayerRenderer beginFrameAtTime:CACurrentMediaTime() timeStamp:NULL];
215
[m_videoLayerRenderer addUpdateRect:layer.bounds];
216
[m_videoLayerRenderer render];
217
[m_videoLayerRenderer endFrame];
219
glMatrixMode(GL_MODELVIEW);
221
glMatrixMode(GL_PROJECTION);
224
glFinish(); //Rendering needs to be done before passing texture to video frame