~phablet-team/+junk/qtmultimedia

« back to all changes in this revision

Viewing changes to src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.mm

  • Committer: Jim Hodapp
  • Date: 2015-05-15 19:17:49 UTC
  • Revision ID: jim.hodapp@canonical.com-20150515191749-r4xausjaaphme9ok
Initial import.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the Qt Toolkit.
 
7
**
 
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.
 
16
**
 
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.
 
24
**
 
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.
 
28
**
 
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.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include "avfvideoframerenderer.h"
 
43
 
 
44
#include <QtMultimedia/qabstractvideosurface.h>
 
45
#include <QtGui/QOpenGLFramebufferObject>
 
46
#include <QtGui/QWindow>
 
47
 
 
48
#ifdef QT_DEBUG_AVF
 
49
#include <QtCore/qdebug.h>
 
50
#endif
 
51
 
 
52
#import <CoreVideo/CVBase.h>
 
53
#import <AVFoundation/AVFoundation.h>
 
54
 
 
55
QT_USE_NAMESPACE
 
56
 
 
57
AVFVideoFrameRenderer::AVFVideoFrameRenderer(QAbstractVideoSurface *surface, QObject *parent)
 
58
    : QObject(parent)
 
59
    , m_videoLayerRenderer(0)
 
60
    , m_surface(surface)
 
61
    , m_glContext(0)
 
62
    , m_currentBuffer(1)
 
63
    , m_isContextShared(true)
 
64
{
 
65
    m_fbo[0] = 0;
 
66
    m_fbo[1] = 0;
 
67
 
 
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();
 
74
}
 
75
 
 
76
AVFVideoFrameRenderer::~AVFVideoFrameRenderer()
 
77
{
 
78
#ifdef QT_DEBUG_AVF
 
79
    qDebug() << Q_FUNC_INFO;
 
80
#endif
 
81
 
 
82
    [m_videoLayerRenderer release];
 
83
    delete m_fbo[0];
 
84
    delete m_fbo[1];
 
85
    delete m_offscreenSurface;
 
86
    delete m_glContext;
 
87
}
 
88
 
 
89
GLuint AVFVideoFrameRenderer::renderLayerToTexture(AVPlayerLayer *layer)
 
90
{
 
91
    //Is layer valid
 
92
    if (!layer)
 
93
        return 0;
 
94
 
 
95
    //If the glContext isn't shared, it doesn't make sense to return a texture for us
 
96
    if (m_offscreenSurface && !m_isContextShared)
 
97
        return 0;
 
98
 
 
99
    QOpenGLFramebufferObject *fbo = initRenderer(layer);
 
100
 
 
101
    if (!fbo)
 
102
        return 0;
 
103
 
 
104
    renderLayerToFBO(layer, fbo);
 
105
    m_glContext->doneCurrent();
 
106
 
 
107
    return fbo->texture();
 
108
}
 
109
 
 
110
QImage AVFVideoFrameRenderer::renderLayerToImage(AVPlayerLayer *layer)
 
111
{
 
112
    //Is layer valid
 
113
    if (!layer) {
 
114
        return QImage();
 
115
    }
 
116
 
 
117
    QOpenGLFramebufferObject *fbo = initRenderer(layer);
 
118
 
 
119
    if (!fbo)
 
120
        return QImage();
 
121
 
 
122
    renderLayerToFBO(layer, fbo);
 
123
    QImage fboImage = fbo->toImage();
 
124
    m_glContext->doneCurrent();
 
125
 
 
126
    return fboImage;
 
127
}
 
128
 
 
129
QOpenGLFramebufferObject *AVFVideoFrameRenderer::initRenderer(AVPlayerLayer *layer)
 
130
{
 
131
 
 
132
    //Get size from AVPlayerLayer
 
133
    m_targetSize = QSize(layer.bounds.size.width, layer.bounds.size.height);
 
134
 
 
135
    //Make sure we have an OpenGL context to make current
 
136
    if (!m_glContext) {
 
137
        //Create OpenGL context and set share context from surface
 
138
        QOpenGLContext *shareContext = 0;
 
139
        if (m_surface) {
 
140
            //QOpenGLContext *renderThreadContext = 0;
 
141
            shareContext = qobject_cast<QOpenGLContext*>(m_surface->property("GLContext").value<QObject*>());
 
142
        }
 
143
        m_glContext = new QOpenGLContext();
 
144
        m_glContext->setFormat(m_offscreenSurface->requestedFormat());
 
145
 
 
146
        if (shareContext) {
 
147
            m_glContext->setShareContext(shareContext);
 
148
            m_isContextShared = true;
 
149
        } else {
 
150
#ifdef QT_DEBUG_AVF
 
151
            qWarning("failed to get Render Thread context");
 
152
#endif
 
153
            m_isContextShared = false;
 
154
        }
 
155
        if (!m_glContext->create()) {
 
156
            qWarning("failed to create QOpenGLContext");
 
157
            return 0;
 
158
        }
 
159
    }
 
160
 
 
161
    //Need current context
 
162
    m_glContext->makeCurrent(m_offscreenSurface);
 
163
 
 
164
    //Create the CARenderer if needed
 
165
    if (!m_videoLayerRenderer) {
 
166
        m_videoLayerRenderer = [CARenderer rendererWithCGLContext: CGLGetCurrentContext() options: nil];
 
167
        [m_videoLayerRenderer retain];
 
168
    }
 
169
 
 
170
    //Set/Change render source if needed
 
171
    if (m_videoLayerRenderer.layer != layer) {
 
172
        m_videoLayerRenderer.layer = layer;
 
173
        m_videoLayerRenderer.bounds = layer.bounds;
 
174
    }
 
175
 
 
176
    //Do we have FBO's already?
 
177
    if ((!m_fbo[0] && !m_fbo[0]) || (m_fbo[0]->size() != m_targetSize)) {
 
178
        delete m_fbo[0];
 
179
        delete m_fbo[1];
 
180
        m_fbo[0] = new QOpenGLFramebufferObject(m_targetSize);
 
181
        m_fbo[1] = new QOpenGLFramebufferObject(m_targetSize);
 
182
    }
 
183
 
 
184
    //Switch buffer target
 
185
    m_currentBuffer = !m_currentBuffer;
 
186
    return m_fbo[m_currentBuffer];
 
187
}
 
188
 
 
189
void AVFVideoFrameRenderer::renderLayerToFBO(AVPlayerLayer *layer, QOpenGLFramebufferObject *fbo)
 
190
{
 
191
    //Start Rendering
 
192
    //NOTE: This rendering method will NOT work on iOS as there is no CARenderer in iOS
 
193
    if (!fbo->bind()) {
 
194
        qWarning("AVFVideoRender FBO failed to bind");
 
195
        return;
 
196
    }
 
197
 
 
198
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
 
199
    glClear(GL_COLOR_BUFFER_BIT);
 
200
 
 
201
    glViewport(0, 0, m_targetSize.width(), m_targetSize.height());
 
202
 
 
203
    glMatrixMode(GL_PROJECTION);
 
204
    glPushMatrix();
 
205
    glLoadIdentity();
 
206
 
 
207
    //Render to FBO with inverted Y
 
208
    glOrtho(0.0, m_targetSize.width(), 0.0, m_targetSize.height(), 0.0, 1.0);
 
209
 
 
210
    glMatrixMode(GL_MODELVIEW);
 
211
    glPushMatrix();
 
212
    glLoadIdentity();
 
213
 
 
214
    [m_videoLayerRenderer beginFrameAtTime:CACurrentMediaTime() timeStamp:NULL];
 
215
    [m_videoLayerRenderer addUpdateRect:layer.bounds];
 
216
    [m_videoLayerRenderer render];
 
217
    [m_videoLayerRenderer endFrame];
 
218
 
 
219
    glMatrixMode(GL_MODELVIEW);
 
220
    glPopMatrix();
 
221
    glMatrixMode(GL_PROJECTION);
 
222
    glPopMatrix();
 
223
 
 
224
    glFinish(); //Rendering needs to be done before passing texture to video frame
 
225
 
 
226
    fbo->release();
 
227
}