~ubuntu-branches/ubuntu/saucy/qt-gstreamer/saucy-proposed

« back to all changes in this revision

Viewing changes to elements/gstqtvideosink/openglsurfacepainter.cpp

  • Committer: Package Import Robot
  • Author(s): Felix Geyer
  • Date: 2012-06-15 15:03:26 UTC
  • mfrom: (1.1.5 sid)
  • Revision ID: package-import@ubuntu.com-20120615150326-pkmdog620pkytcgt
Tags: 0.10.2-2ubuntu1
* Merge from Debian unstable, remaining changes:
  - Enable unit tests.
    + Build-depend on gstreamer0.10-plugins-base.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). <qt-info@nokia.com>
 
3
    Copyright (C) 2011-2012 Collabora Ltd. <info@collabora.com>
 
4
 
 
5
    This library is free software; you can redistribute it and/or modify
 
6
    it under the terms of the GNU Lesser General Public License version 2.1
 
7
    as published by the Free Software Foundation.
 
8
 
 
9
    This program is distributed in the hope that it will be useful,
 
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
    GNU Lesser General Public License for more details.
 
13
 
 
14
    You should have received a copy of the GNU Lesser General Public License
 
15
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
*/
 
17
#include "openglsurfacepainter.h"
 
18
#include <QtCore/qmath.h>
 
19
 
 
20
#ifndef GL_TEXTURE0
 
21
#  define GL_TEXTURE0    0x84C0
 
22
#  define GL_TEXTURE1    0x84C1
 
23
#  define GL_TEXTURE2    0x84C2
 
24
#endif
 
25
 
 
26
#ifndef GL_PROGRAM_ERROR_STRING_ARB
 
27
#  define GL_PROGRAM_ERROR_STRING_ARB       0x8874
 
28
#endif
 
29
 
 
30
#ifndef GL_UNSIGNED_SHORT_5_6_5
 
31
#  define GL_UNSIGNED_SHORT_5_6_5 33635
 
32
#endif
 
33
 
 
34
#define QRECT_TO_GLMATRIX(rect) \
 
35
    { \
 
36
        GLfloat(rect.left())     , GLfloat(rect.bottom() + 1), \
 
37
        GLfloat(rect.right() + 1), GLfloat(rect.bottom() + 1), \
 
38
        GLfloat(rect.left())     , GLfloat(rect.top()), \
 
39
        GLfloat(rect.right() + 1), GLfloat(rect.top()) \
 
40
    }
 
41
 
 
42
OpenGLSurfacePainter::OpenGLSurfacePainter()
 
43
    : m_textureFormat(0)
 
44
    , m_textureInternalFormat(0)
 
45
    , m_textureType(0)
 
46
    , m_textureCount(0)
 
47
    , m_videoColorMatrix(GST_VIDEO_COLOR_MATRIX_UNKNOWN)
 
48
{
 
49
#ifndef QT_OPENGL_ES
 
50
    glActiveTexture = (_glActiveTexture) QGLContext::currentContext()->getProcAddress(
 
51
            QLatin1String("glActiveTexture"));
 
52
#endif
 
53
}
 
54
 
 
55
//static
 
56
QSet<GstVideoFormat> OpenGLSurfacePainter::supportedPixelFormats()
 
57
{
 
58
    return QSet<GstVideoFormat>()
 
59
        //also handled by the generic painter on LE
 
60
        << GST_VIDEO_FORMAT_BGRA
 
61
        << GST_VIDEO_FORMAT_BGRx
 
62
 
 
63
        //also handled by the generic painter on BE
 
64
        << GST_VIDEO_FORMAT_ARGB
 
65
        << GST_VIDEO_FORMAT_xRGB
 
66
 
 
67
        //also handled by the generic painter everywhere
 
68
        << GST_VIDEO_FORMAT_RGB
 
69
        << GST_VIDEO_FORMAT_RGB16
 
70
 
 
71
        //not handled by the generic painter
 
72
        << GST_VIDEO_FORMAT_BGR
 
73
        << GST_VIDEO_FORMAT_v308
 
74
        << GST_VIDEO_FORMAT_AYUV
 
75
        << GST_VIDEO_FORMAT_YV12
 
76
        << GST_VIDEO_FORMAT_I420
 
77
        ;
 
78
}
 
79
 
 
80
void OpenGLSurfacePainter::updateColors(int brightness, int contrast, int hue, int saturation)
 
81
{
 
82
    const qreal b = brightness / 200.0;
 
83
    const qreal c = contrast / 100.0 + 1.0;
 
84
    const qreal h = hue / 100.0;
 
85
    const qreal s = saturation / 100.0 + 1.0;
 
86
 
 
87
    const qreal cosH = qCos(M_PI * h);
 
88
    const qreal sinH = qSin(M_PI * h);
 
89
 
 
90
    const qreal h11 =  0.787 * cosH - 0.213 * sinH + 0.213;
 
91
    const qreal h21 = -0.213 * cosH + 0.143 * sinH + 0.213;
 
92
    const qreal h31 = -0.213 * cosH - 0.787 * sinH + 0.213;
 
93
 
 
94
    const qreal h12 = -0.715 * cosH - 0.715 * sinH + 0.715;
 
95
    const qreal h22 =  0.285 * cosH + 0.140 * sinH + 0.715;
 
96
    const qreal h32 = -0.715 * cosH + 0.715 * sinH + 0.715;
 
97
 
 
98
    const qreal h13 = -0.072 * cosH + 0.928 * sinH + 0.072;
 
99
    const qreal h23 = -0.072 * cosH - 0.283 * sinH + 0.072;
 
100
    const qreal h33 =  0.928 * cosH + 0.072 * sinH + 0.072;
 
101
 
 
102
    const qreal sr = (1.0 - s) * 0.3086;
 
103
    const qreal sg = (1.0 - s) * 0.6094;
 
104
    const qreal sb = (1.0 - s) * 0.0820;
 
105
 
 
106
    const qreal sr_s = sr + s;
 
107
    const qreal sg_s = sg + s;
 
108
    const qreal sb_s = sr + s;
 
109
 
 
110
    const float m4 = (s + sr + sg + sb) * (0.5 - 0.5 * c + b);
 
111
 
 
112
    m_colorMatrix(0, 0) = c * (sr_s * h11 + sg * h21 + sb * h31);
 
113
    m_colorMatrix(0, 1) = c * (sr_s * h12 + sg * h22 + sb * h32);
 
114
    m_colorMatrix(0, 2) = c * (sr_s * h13 + sg * h23 + sb * h33);
 
115
    m_colorMatrix(0, 3) = m4;
 
116
 
 
117
    m_colorMatrix(1, 0) = c * (sr * h11 + sg_s * h21 + sb * h31);
 
118
    m_colorMatrix(1, 1) = c * (sr * h12 + sg_s * h22 + sb * h32);
 
119
    m_colorMatrix(1, 2) = c * (sr * h13 + sg_s * h23 + sb * h33);
 
120
    m_colorMatrix(1, 3) = m4;
 
121
 
 
122
    m_colorMatrix(2, 0) = c * (sr * h11 + sg * h21 + sb_s * h31);
 
123
    m_colorMatrix(2, 1) = c * (sr * h12 + sg * h22 + sb_s * h32);
 
124
    m_colorMatrix(2, 2) = c * (sr * h13 + sg * h23 + sb_s * h33);
 
125
    m_colorMatrix(2, 3) = m4;
 
126
 
 
127
    m_colorMatrix(3, 0) = 0.0;
 
128
    m_colorMatrix(3, 1) = 0.0;
 
129
    m_colorMatrix(3, 2) = 0.0;
 
130
    m_colorMatrix(3, 3) = 1.0;
 
131
 
 
132
    switch (m_videoColorMatrix) {
 
133
#if 0
 
134
    //I have no idea what this is - it's not needed currently in this code
 
135
    case BufferFormat::YCbCr_JPEG:
 
136
        m_colorMatrix *= QMatrix4x4(
 
137
                    1.0,  0.000,  1.402, -0.701,
 
138
                    1.0, -0.344, -0.714,  0.529,
 
139
                    1.0,  1.772,  0.000, -0.886,
 
140
                    0.0,  0.000,  0.000,  1.0000);
 
141
        break;
 
142
#endif
 
143
    case GST_VIDEO_COLOR_MATRIX_BT709:
 
144
        m_colorMatrix *= QMatrix4x4(
 
145
                    1.164,  0.000,  1.793, -0.5727,
 
146
                    1.164, -0.534, -0.213,  0.3007,
 
147
                    1.164,  2.115,  0.000, -1.1302,
 
148
                    0.0,    0.000,  0.000,  1.0000);
 
149
        break;
 
150
    case GST_VIDEO_COLOR_MATRIX_BT601:
 
151
        m_colorMatrix *= QMatrix4x4(
 
152
                    1.164,  0.000,  1.596, -0.8708,
 
153
                    1.164, -0.392, -0.813,  0.5296,
 
154
                    1.164,  2.017,  0.000, -1.081,
 
155
                    0.0,    0.000,  0.000,  1.0000);
 
156
        break;
 
157
    default:
 
158
        break;
 
159
    }
 
160
}
 
161
 
 
162
void OpenGLSurfacePainter::paint(quint8 *data,
 
163
        const BufferFormat & frameFormat,
 
164
        const QRectF & clipRect,
 
165
        QPainter *painter,
 
166
        const PaintAreas & areas)
 
167
{
 
168
    // if these are enabled, we need to reenable them after beginNativePainting()
 
169
    // has been called, as they may get disabled
 
170
    bool stencilTestEnabled = glIsEnabled(GL_STENCIL_TEST);
 
171
    bool scissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST);
 
172
 
 
173
    painter->beginNativePainting();
 
174
 
 
175
    if (stencilTestEnabled)
 
176
        glEnable(GL_STENCIL_TEST);
 
177
    if (scissorTestEnabled)
 
178
        glEnable(GL_SCISSOR_TEST);
 
179
 
 
180
    const GLfloat vertexCoordArray[] = QRECT_TO_GLMATRIX(areas.videoArea);
 
181
 
 
182
    const GLfloat txLeft = clipRect.left() / frameFormat.frameSize().width();
 
183
    const GLfloat txRight = (clipRect.right() + 1) / frameFormat.frameSize().width();
 
184
    const GLfloat txTop = clipRect.top() / frameFormat.frameSize().height();
 
185
    const GLfloat txBottom = (clipRect.bottom() + 1) / frameFormat.frameSize().height();
 
186
 
 
187
    const GLfloat textureCoordArray[] =
 
188
    {
 
189
        txLeft , txBottom,
 
190
        txRight, txBottom,
 
191
        txLeft , txTop,
 
192
        txRight, txTop
 
193
    };
 
194
 
 
195
    for (int i = 0; i < m_textureCount; ++i) {
 
196
        glBindTexture(GL_TEXTURE_2D, m_textureIds[i]);
 
197
        glTexImage2D(
 
198
                GL_TEXTURE_2D,
 
199
                0,
 
200
                m_textureInternalFormat,
 
201
                m_textureWidths[i],
 
202
                m_textureHeights[i],
 
203
                0,
 
204
                m_textureFormat,
 
205
                m_textureType,
 
206
                data + m_textureOffsets[i]);
 
207
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
208
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 
209
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
210
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
211
    }
 
212
 
 
213
    paintImpl(painter, vertexCoordArray, textureCoordArray);
 
214
 
 
215
    painter->endNativePainting();
 
216
    painter->fillRect(areas.blackArea1, Qt::black);
 
217
    painter->fillRect(areas.blackArea2, Qt::black);
 
218
}
 
219
 
 
220
void OpenGLSurfacePainter::initRgbTextureInfo(
 
221
        GLenum internalFormat, GLuint format, GLenum type, const QSize &size)
 
222
{
 
223
#ifndef QT_OPENGL_ES
 
224
    //make sure we get 8 bits per component, at least on the desktop GL where we can
 
225
    switch(internalFormat) {
 
226
    case GL_RGBA:
 
227
        internalFormat = GL_RGBA8;
 
228
        break;
 
229
    case GL_RGB:
 
230
        internalFormat = GL_RGB8;
 
231
        break;
 
232
    default:
 
233
        break;
 
234
    }
 
235
#endif
 
236
 
 
237
    m_textureInternalFormat = internalFormat;
 
238
    m_textureFormat = format;
 
239
    m_textureType = type;
 
240
    m_textureCount = 1;
 
241
    m_textureWidths[0] = size.width();
 
242
    m_textureHeights[0] = size.height();
 
243
    m_textureOffsets[0] = 0;
 
244
}
 
245
 
 
246
void OpenGLSurfacePainter::initYuv420PTextureInfo(const QSize &size)
 
247
{
 
248
    int bytesPerLine = (size.width() + 3) & ~3;
 
249
    int bytesPerLine2 = (size.width() / 2 + 3) & ~3;
 
250
 
 
251
    m_textureInternalFormat = GL_LUMINANCE;
 
252
    m_textureFormat = GL_LUMINANCE;
 
253
    m_textureType = GL_UNSIGNED_BYTE;
 
254
    m_textureCount = 3;
 
255
    m_textureWidths[0] = bytesPerLine;
 
256
    m_textureHeights[0] = size.height();
 
257
    m_textureOffsets[0] = 0;
 
258
    m_textureWidths[1] = bytesPerLine2;
 
259
    m_textureHeights[1] = size.height() / 2;
 
260
    m_textureOffsets[1] = bytesPerLine * size.height();
 
261
    m_textureWidths[2] = bytesPerLine2;
 
262
    m_textureHeights[2] = size.height() / 2;
 
263
    m_textureOffsets[2] = bytesPerLine * size.height() + bytesPerLine2 * size.height()/2;
 
264
}
 
265
 
 
266
void OpenGLSurfacePainter::initYv12TextureInfo(const QSize &size)
 
267
{
 
268
    int bytesPerLine = (size.width() + 3) & ~3;
 
269
    int bytesPerLine2 = (size.width() / 2 + 3) & ~3;
 
270
 
 
271
    m_textureInternalFormat = GL_LUMINANCE;
 
272
    m_textureFormat = GL_LUMINANCE;
 
273
    m_textureType = GL_UNSIGNED_BYTE;
 
274
    m_textureCount = 3;
 
275
    m_textureWidths[0] = bytesPerLine;
 
276
    m_textureHeights[0] = size.height();
 
277
    m_textureOffsets[0] = 0;
 
278
    m_textureWidths[1] = bytesPerLine2;
 
279
    m_textureHeights[1] = size.height() / 2;
 
280
    m_textureOffsets[1] = bytesPerLine * size.height() + bytesPerLine2 * size.height()/2;
 
281
    m_textureWidths[2] = bytesPerLine2;
 
282
    m_textureHeights[2] = size.height() / 2;
 
283
    m_textureOffsets[2] = bytesPerLine * size.height();
 
284
}
 
285
 
 
286
#ifndef QT_OPENGL_ES
 
287
 
 
288
# ifndef GL_FRAGMENT_PROGRAM_ARB
 
289
#  define GL_FRAGMENT_PROGRAM_ARB           0x8804
 
290
#  define GL_PROGRAM_FORMAT_ASCII_ARB       0x8875
 
291
# endif
 
292
 
 
293
// Interprets the RGBA texture as in fact being BGRx and paints it.
 
294
static const char *qt_arbfp_bgrxShaderProgram =
 
295
    "!!ARBfp1.0\n"
 
296
    "PARAM matrix[4] = { program.local[0..2],"
 
297
    "{ 0.0, 0.0, 0.0, 1.0 } };\n"
 
298
    "TEMP bgrx;\n"
 
299
    "TEX bgrx.xyz, fragment.texcoord[0], texture[0], 2D;\n"
 
300
    "MOV bgrx.w, matrix[3].w;\n"
 
301
    "DP4 result.color.x, bgrx.zyxw, matrix[0];\n"
 
302
    "DP4 result.color.y, bgrx.zyxw, matrix[1];\n"
 
303
    "DP4 result.color.z, bgrx.zyxw, matrix[2];\n"
 
304
    "END";
 
305
 
 
306
// Interprets the RGBA texture as in fact being BGRA and paints it.
 
307
static const char *qt_arbfp_bgraShaderProgram =
 
308
    "!!ARBfp1.0\n"
 
309
    "PARAM matrix[4] = { program.local[0..2],"
 
310
    "{ 0.0, 0.0, 0.0, 1.0 } };\n"
 
311
    "TEMP bgra;\n"
 
312
    "TEX bgra, fragment.texcoord[0], texture[0], 2D;\n"
 
313
    "MOV bgra.w, matrix[3].w;\n"
 
314
    "DP4 result.color.x, bgra.zyxw, matrix[0];\n"
 
315
    "DP4 result.color.y, bgra.zyxw, matrix[1];\n"
 
316
    "DP4 result.color.z, bgra.zyxw, matrix[2];\n"
 
317
    "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n"
 
318
    "END";
 
319
 
 
320
// Interprets the RGBA texture as in fact being xRGB and paints it.
 
321
static const char *qt_arbfp_xrgbShaderProgram =
 
322
    "!!ARBfp1.0\n"
 
323
    "PARAM matrix[4] = { program.local[0..2],"
 
324
    "{ 0.0, 0.0, 0.0, 1.0 } };\n"
 
325
    "TEMP xrgb;\n"
 
326
    "TEX xrgb, fragment.texcoord[0], texture[0], 2D;\n"
 
327
    "MOV xrgb.x, matrix[3].w;\n"
 
328
    "DP4 result.color.x, xrgb.yzwx, matrix[0];\n"
 
329
    "DP4 result.color.y, xrgb.yzwx, matrix[1];\n"
 
330
    "DP4 result.color.z, xrgb.yzwx, matrix[2];\n"
 
331
    "END";
 
332
 
 
333
// Interprets the RGBA texture as in fact being ARGB and paints it.
 
334
static const char *qt_arbfp_argbShaderProgram =
 
335
    "!!ARBfp1.0\n"
 
336
    "PARAM matrix[4] = { program.local[0..2],"
 
337
    "{ 0.0, 0.0, 0.0, 1.0 } };\n"
 
338
    "TEMP argb;\n"
 
339
    "TEX argb, fragment.texcoord[0], texture[0], 2D;\n"
 
340
    "MOV argb.x, matrix[3].w;\n"
 
341
    "DP4 result.color.x, argb.yzwx, matrix[0];\n"
 
342
    "DP4 result.color.y, argb.yzwx, matrix[1];\n"
 
343
    "DP4 result.color.z, argb.yzwx, matrix[2];\n"
 
344
    "TEX result.color.w, fragment.texcoord[0], texture, 2D;\n"
 
345
    "END";
 
346
 
 
347
// Paints RGB frames without doing any color channel flipping.
 
348
static const char *qt_arbfp_rgbxShaderProgram =
 
349
    "!!ARBfp1.0\n"
 
350
    "PARAM matrix[4] = { program.local[0..2],"
 
351
    "{ 0.0, 0.0, 0.0, 1.0 } };\n"
 
352
    "TEMP rgb;\n"
 
353
    "TEX rgb.xyz, fragment.texcoord[0], texture[0], 2D;\n"
 
354
    "MOV rgb.w, matrix[3].w;\n"
 
355
    "DP4 result.color.x, rgb, matrix[0];\n"
 
356
    "DP4 result.color.y, rgb, matrix[1];\n"
 
357
    "DP4 result.color.z, rgb, matrix[2];\n"
 
358
    "END";
 
359
 
 
360
// Paints a YUV420P or YV12 frame.
 
361
static const char *qt_arbfp_yuvPlanarShaderProgram =
 
362
    "!!ARBfp1.0\n"
 
363
    "PARAM matrix[4] = { program.local[0..2],"
 
364
    "{ 0.0, 0.0, 0.0, 1.0 } };\n"
 
365
    "TEMP yuv;\n"
 
366
    "TEX yuv.x, fragment.texcoord[0], texture[0], 2D;\n"
 
367
    "TEX yuv.y, fragment.texcoord[0], texture[1], 2D;\n"
 
368
    "TEX yuv.z, fragment.texcoord[0], texture[2], 2D;\n"
 
369
    "MOV yuv.w, matrix[3].w;\n"
 
370
    "DP4 result.color.x, yuv, matrix[0];\n"
 
371
    "DP4 result.color.y, yuv, matrix[1];\n"
 
372
    "DP4 result.color.z, yuv, matrix[2];\n"
 
373
    "END";
 
374
 
 
375
 
 
376
 
 
377
ArbFpSurfacePainter::ArbFpSurfacePainter()
 
378
    : OpenGLSurfacePainter()
 
379
    , m_programId(0)
 
380
{
 
381
    const QGLContext *context = QGLContext::currentContext();
 
382
 
 
383
    glProgramStringARB = (_glProgramStringARB) context->getProcAddress(
 
384
                QLatin1String("glProgramStringARB"));
 
385
    glBindProgramARB = (_glBindProgramARB) context->getProcAddress(
 
386
                QLatin1String("glBindProgramARB"));
 
387
    glDeleteProgramsARB = (_glDeleteProgramsARB) context->getProcAddress(
 
388
                QLatin1String("glDeleteProgramsARB"));
 
389
    glGenProgramsARB = (_glGenProgramsARB) context->getProcAddress(
 
390
                QLatin1String("glGenProgramsARB"));
 
391
    glProgramLocalParameter4fARB = (_glProgramLocalParameter4fARB) context->getProcAddress(
 
392
                QLatin1String("glProgramLocalParameter4fARB"));
 
393
}
 
394
 
 
395
void ArbFpSurfacePainter::init(const BufferFormat &format)
 
396
{
 
397
    Q_ASSERT(m_textureCount == 0);
 
398
 
 
399
    const char *program = 0;
 
400
 
 
401
    switch (format.videoFormat()) {
 
402
    case GST_VIDEO_FORMAT_BGRx:
 
403
        initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
 
404
        program = qt_arbfp_bgrxShaderProgram;
 
405
        break;
 
406
    case GST_VIDEO_FORMAT_xRGB:
 
407
        initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
 
408
        program = qt_arbfp_xrgbShaderProgram;
 
409
        break;
 
410
    case GST_VIDEO_FORMAT_BGRA:
 
411
        initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
 
412
        program = qt_arbfp_bgraShaderProgram;
 
413
        break;
 
414
    case GST_VIDEO_FORMAT_ARGB:
 
415
        initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
 
416
        program = qt_arbfp_argbShaderProgram;
 
417
        break;
 
418
    case GST_VIDEO_FORMAT_RGB:
 
419
        initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize());
 
420
        program = qt_arbfp_rgbxShaderProgram;
 
421
        break;
 
422
    case GST_VIDEO_FORMAT_BGR:
 
423
        initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize());
 
424
        program = qt_arbfp_bgrxShaderProgram;
 
425
        break;
 
426
    //NOTE: unlike the other formats, this is endianness-dependent,
 
427
    //but using GL_UNSIGNED_SHORT_5_6_5 ensures that it's handled correctly
 
428
    case GST_VIDEO_FORMAT_RGB16:
 
429
        initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, format.frameSize());
 
430
        program = qt_arbfp_rgbxShaderProgram;
 
431
        break;
 
432
    case GST_VIDEO_FORMAT_v308:
 
433
        initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize());
 
434
        program = qt_arbfp_rgbxShaderProgram;
 
435
        break;
 
436
    case GST_VIDEO_FORMAT_AYUV:
 
437
        initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
 
438
        program = qt_arbfp_argbShaderProgram;
 
439
        break;
 
440
    case GST_VIDEO_FORMAT_YV12:
 
441
        initYv12TextureInfo(format.frameSize());
 
442
        program = qt_arbfp_yuvPlanarShaderProgram;
 
443
        break;
 
444
    case GST_VIDEO_FORMAT_I420:
 
445
        initYuv420PTextureInfo(format.frameSize());
 
446
        program = qt_arbfp_yuvPlanarShaderProgram;
 
447
        break;
 
448
    default:
 
449
        Q_ASSERT(false);
 
450
        break;
 
451
    }
 
452
 
 
453
    m_videoColorMatrix = format.colorMatrix();
 
454
 
 
455
    glGenProgramsARB(1, &m_programId);
 
456
 
 
457
    GLenum glError = glGetError();
 
458
    if (glError != GL_NO_ERROR) {
 
459
        throw QString("ARBfb Shader allocation error ") +
 
460
            QString::number(static_cast<int>(glError), 16);
 
461
    } else {
 
462
        glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_programId);
 
463
        glProgramStringARB(
 
464
                GL_FRAGMENT_PROGRAM_ARB,
 
465
                GL_PROGRAM_FORMAT_ASCII_ARB,
 
466
                qstrlen(program),
 
467
                reinterpret_cast<const GLvoid *>(program));
 
468
 
 
469
        if ((glError = glGetError()) != GL_NO_ERROR) {
 
470
            const GLubyte* errorString = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
 
471
 
 
472
            glDeleteProgramsARB(1, &m_programId);
 
473
            m_textureCount = 0;
 
474
            m_programId = 0;
 
475
 
 
476
            throw QString("ARBfp Shader compile error ") +
 
477
                QString::number(static_cast<int>(glError), 16) +
 
478
                reinterpret_cast<const char *>(errorString);
 
479
        } else {
 
480
            glGenTextures(m_textureCount, m_textureIds);
 
481
        }
 
482
    }
 
483
}
 
484
 
 
485
void ArbFpSurfacePainter::cleanup()
 
486
{
 
487
    glDeleteTextures(m_textureCount, m_textureIds);
 
488
    glDeleteProgramsARB(1, &m_programId);
 
489
 
 
490
    m_textureCount = 0;
 
491
    m_programId = 0;
 
492
}
 
493
 
 
494
void ArbFpSurfacePainter::paintImpl(const QPainter *painter,
 
495
        const GLfloat *vertexCoordArray,
 
496
        const GLfloat *textureCoordArray)
 
497
{
 
498
    Q_UNUSED(painter);
 
499
 
 
500
    glEnable(GL_FRAGMENT_PROGRAM_ARB);
 
501
    glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_programId);
 
502
 
 
503
    glProgramLocalParameter4fARB(
 
504
            GL_FRAGMENT_PROGRAM_ARB,
 
505
            0,
 
506
            m_colorMatrix(0, 0),
 
507
            m_colorMatrix(0, 1),
 
508
            m_colorMatrix(0, 2),
 
509
            m_colorMatrix(0, 3));
 
510
    glProgramLocalParameter4fARB(
 
511
            GL_FRAGMENT_PROGRAM_ARB,
 
512
            1,
 
513
            m_colorMatrix(1, 0),
 
514
            m_colorMatrix(1, 1),
 
515
            m_colorMatrix(1, 2),
 
516
            m_colorMatrix(1, 3));
 
517
    glProgramLocalParameter4fARB(
 
518
            GL_FRAGMENT_PROGRAM_ARB,
 
519
            2,
 
520
            m_colorMatrix(2, 0),
 
521
            m_colorMatrix(2, 1),
 
522
            m_colorMatrix(2, 2),
 
523
            m_colorMatrix(2, 3));
 
524
 
 
525
    glActiveTexture(GL_TEXTURE0);
 
526
    glBindTexture(GL_TEXTURE_2D, m_textureIds[0]);
 
527
 
 
528
    if (m_textureCount == 3) {
 
529
        glActiveTexture(GL_TEXTURE1);
 
530
        glBindTexture(GL_TEXTURE_2D, m_textureIds[1]);
 
531
        glActiveTexture(GL_TEXTURE2);
 
532
        glBindTexture(GL_TEXTURE_2D, m_textureIds[2]);
 
533
        glActiveTexture(GL_TEXTURE0);
 
534
    }
 
535
 
 
536
    glVertexPointer(2, GL_FLOAT, 0, vertexCoordArray);
 
537
    glTexCoordPointer(2, GL_FLOAT, 0, textureCoordArray);
 
538
 
 
539
    glEnableClientState(GL_VERTEX_ARRAY);
 
540
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
541
 
 
542
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
543
 
 
544
    glDisableClientState(GL_VERTEX_ARRAY);
 
545
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 
546
    glDisable(GL_FRAGMENT_PROGRAM_ARB);
 
547
}
 
548
 
 
549
#endif
 
550
 
 
551
static const char *qt_glsl_vertexShaderProgram =
 
552
        "attribute highp vec4 vertexCoordArray;\n"
 
553
        "attribute highp vec2 textureCoordArray;\n"
 
554
        "uniform highp mat4 positionMatrix;\n"
 
555
        "varying highp vec2 textureCoord;\n"
 
556
        "void main(void)\n"
 
557
        "{\n"
 
558
        "   gl_Position = positionMatrix * vertexCoordArray;\n"
 
559
        "   textureCoord = textureCoordArray;\n"
 
560
        "}\n";
 
561
 
 
562
// Interprets the RGBA texture as in fact being BGRx and paints it.
 
563
static const char *qt_glsl_bgrxShaderProgram =
 
564
        "uniform sampler2D texRgb;\n"
 
565
        "uniform mediump mat4 colorMatrix;\n"
 
566
        "varying highp vec2 textureCoord;\n"
 
567
        "void main(void)\n"
 
568
        "{\n"
 
569
        "    highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).bgr, 1.0);\n"
 
570
        "    gl_FragColor = colorMatrix * color;\n"
 
571
        "}\n";
 
572
 
 
573
// Interprets the RGBA texture as in fact being BGRA and paints it.
 
574
static const char *qt_glsl_bgraShaderProgram =
 
575
        "uniform sampler2D texRgb;\n"
 
576
        "uniform mediump mat4 colorMatrix;\n"
 
577
        "varying highp vec2 textureCoord;\n"
 
578
        "void main(void)\n"
 
579
        "{\n"
 
580
        "    highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).bgr, 1.0);\n"
 
581
        "    color = colorMatrix * color;\n"
 
582
        "    gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).a);\n"
 
583
        "}\n";
 
584
 
 
585
// Interprets the RGBA texture as in fact being xRGB and paints it.
 
586
static const char *qt_glsl_xrgbShaderProgram =
 
587
        "uniform sampler2D texRgb;\n"
 
588
        "uniform mediump mat4 colorMatrix;\n"
 
589
        "varying highp vec2 textureCoord;\n"
 
590
        "void main(void)\n"
 
591
        "{\n"
 
592
        "    highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).gba, 1.0);\n"
 
593
        "    gl_FragColor = colorMatrix * color;\n"
 
594
        "}\n";
 
595
 
 
596
// Interprets the RGBA texture as in fact being ARGB and paints it.
 
597
static const char *qt_glsl_argbShaderProgram =
 
598
        "uniform sampler2D texRgb;\n"
 
599
        "uniform mediump mat4 colorMatrix;\n"
 
600
        "varying highp vec2 textureCoord;\n"
 
601
        "void main(void)\n"
 
602
        "{\n"
 
603
        "    highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).gba, 1.0);\n"
 
604
        "    color = colorMatrix * color;\n"
 
605
        "    gl_FragColor = vec4(color.rgb, texture2D(texRgb, textureCoord.st).r);\n"
 
606
        "}\n";
 
607
 
 
608
// Paints RGB frames without doing any color channel flipping.
 
609
static const char *qt_glsl_rgbxShaderProgram =
 
610
        "uniform sampler2D texRgb;\n"
 
611
        "uniform mediump mat4 colorMatrix;\n"
 
612
        "varying highp vec2 textureCoord;\n"
 
613
        "void main(void)\n"
 
614
        "{\n"
 
615
        "    highp vec4 color = vec4(texture2D(texRgb, textureCoord.st).rgb, 1.0);\n"
 
616
        "    gl_FragColor = colorMatrix * color;\n"
 
617
        "}\n";
 
618
 
 
619
// Paints planar yuv frames.
 
620
static const char *qt_glsl_yuvPlanarShaderProgram =
 
621
        "uniform sampler2D texY;\n"
 
622
        "uniform sampler2D texU;\n"
 
623
        "uniform sampler2D texV;\n"
 
624
        "uniform mediump mat4 colorMatrix;\n"
 
625
        "varying highp vec2 textureCoord;\n"
 
626
        "void main(void)\n"
 
627
        "{\n"
 
628
        "    highp vec4 color = vec4(\n"
 
629
        "           texture2D(texY, textureCoord.st).r,\n"
 
630
        "           texture2D(texU, textureCoord.st).r,\n"
 
631
        "           texture2D(texV, textureCoord.st).r,\n"
 
632
        "           1.0);\n"
 
633
        "    gl_FragColor = colorMatrix * color;\n"
 
634
        "}\n";
 
635
 
 
636
 
 
637
GlslSurfacePainter::GlslSurfacePainter()
 
638
    : OpenGLSurfacePainter()
 
639
{
 
640
}
 
641
 
 
642
void GlslSurfacePainter::init(const BufferFormat &format)
 
643
{
 
644
    Q_ASSERT(m_textureCount == 0);
 
645
 
 
646
    const char *fragmentProgram = 0;
 
647
 
 
648
    switch (format.videoFormat()) {
 
649
    case GST_VIDEO_FORMAT_BGRx:
 
650
        initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
 
651
        fragmentProgram = qt_glsl_bgrxShaderProgram;
 
652
        break;
 
653
    case GST_VIDEO_FORMAT_xRGB:
 
654
        initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
 
655
        fragmentProgram = qt_glsl_xrgbShaderProgram;
 
656
        break;
 
657
    case GST_VIDEO_FORMAT_BGRA:
 
658
        initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
 
659
        fragmentProgram = qt_glsl_bgraShaderProgram;
 
660
        break;
 
661
    case GST_VIDEO_FORMAT_ARGB:
 
662
        initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
 
663
        fragmentProgram = qt_glsl_argbShaderProgram;
 
664
        break;
 
665
    case GST_VIDEO_FORMAT_RGB:
 
666
        initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize());
 
667
        fragmentProgram = qt_glsl_rgbxShaderProgram;
 
668
        break;
 
669
    case GST_VIDEO_FORMAT_BGR:
 
670
        initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize());
 
671
        fragmentProgram = qt_glsl_bgrxShaderProgram;
 
672
        break;
 
673
    //NOTE: unlike the other formats, this is endianness-dependent,
 
674
    //but using GL_UNSIGNED_SHORT_5_6_5 ensures that it's handled correctly
 
675
    case GST_VIDEO_FORMAT_RGB16:
 
676
        initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, format.frameSize());
 
677
        fragmentProgram = qt_glsl_rgbxShaderProgram;
 
678
        break;
 
679
    case GST_VIDEO_FORMAT_v308:
 
680
        initRgbTextureInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize());
 
681
        fragmentProgram = qt_glsl_rgbxShaderProgram;
 
682
        break;
 
683
    case GST_VIDEO_FORMAT_AYUV:
 
684
        initRgbTextureInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, format.frameSize());
 
685
        fragmentProgram = qt_glsl_argbShaderProgram;
 
686
        break;
 
687
    case GST_VIDEO_FORMAT_YV12:
 
688
        initYv12TextureInfo(format.frameSize());
 
689
        fragmentProgram = qt_glsl_yuvPlanarShaderProgram;
 
690
        break;
 
691
    case GST_VIDEO_FORMAT_I420:
 
692
        initYuv420PTextureInfo(format.frameSize());
 
693
        fragmentProgram = qt_glsl_yuvPlanarShaderProgram;
 
694
        break;
 
695
    default:
 
696
        Q_ASSERT(false);
 
697
        break;
 
698
    }
 
699
 
 
700
    m_videoColorMatrix = format.colorMatrix();
 
701
 
 
702
    if (!m_program.addShaderFromSourceCode(QGLShader::Vertex, qt_glsl_vertexShaderProgram)) {
 
703
        throw QString("Vertex shader compile error ") + m_program.log();
 
704
    }
 
705
 
 
706
    if (!m_program.addShaderFromSourceCode(QGLShader::Fragment, fragmentProgram)) {
 
707
        throw QString("Shader compile error ") + m_program.log();
 
708
    }
 
709
 
 
710
    if(!m_program.link()) {
 
711
        throw QString("Shader link error ") + m_program.log();
 
712
    }
 
713
 
 
714
    glGenTextures(m_textureCount, m_textureIds);
 
715
}
 
716
 
 
717
void GlslSurfacePainter::cleanup()
 
718
{
 
719
    glDeleteTextures(m_textureCount, m_textureIds);
 
720
    m_program.removeAllShaders();
 
721
 
 
722
    m_textureCount = 0;
 
723
}
 
724
 
 
725
void GlslSurfacePainter::paintImpl(const QPainter *painter,
 
726
        const GLfloat *vertexCoordArray,
 
727
        const GLfloat *textureCoordArray)
 
728
{
 
729
    const int deviceWidth = QGLContext::currentContext()->device()->width();
 
730
    const int deviceHeight = QGLContext::currentContext()->device()->height();
 
731
 
 
732
    const QTransform transform = painter->deviceTransform();
 
733
 
 
734
    const GLfloat wfactor = 2.0 / deviceWidth;
 
735
    const GLfloat hfactor = -2.0 / deviceHeight;
 
736
 
 
737
    const GLfloat positionMatrix[4][4] =
 
738
    {
 
739
        {
 
740
            /*(0,0)*/ GLfloat(wfactor * transform.m11() - transform.m13()),
 
741
            /*(0,1)*/ GLfloat(hfactor * transform.m12() + transform.m13()),
 
742
            /*(0,2)*/ 0.0,
 
743
            /*(0,3)*/ GLfloat(transform.m13())
 
744
        }, {
 
745
            /*(1,0)*/ GLfloat(wfactor * transform.m21() - transform.m23()),
 
746
            /*(1,1)*/ GLfloat(hfactor * transform.m22() + transform.m23()),
 
747
            /*(1,2)*/ 0.0,
 
748
            /*(1,3)*/ GLfloat(transform.m23())
 
749
        }, {
 
750
            /*(2,0)*/ 0.0,
 
751
            /*(2,1)*/ 0.0,
 
752
            /*(2,2)*/ -1.0,
 
753
            /*(2,3)*/ 0.0
 
754
        }, {
 
755
            /*(3,0)*/ GLfloat(wfactor * transform.dx() - transform.m33()),
 
756
            /*(3,1)*/ GLfloat(hfactor * transform.dy() + transform.m33()),
 
757
            /*(3,2)*/ 0.0,
 
758
            /*(3,3)*/ GLfloat(transform.m33())
 
759
        }
 
760
    };
 
761
 
 
762
    m_program.bind();
 
763
 
 
764
    m_program.enableAttributeArray("vertexCoordArray");
 
765
    m_program.enableAttributeArray("textureCoordArray");
 
766
    m_program.setAttributeArray("vertexCoordArray", vertexCoordArray, 2);
 
767
    m_program.setAttributeArray("textureCoordArray", textureCoordArray, 2);
 
768
    m_program.setUniformValue("positionMatrix", positionMatrix);
 
769
 
 
770
    if (m_textureCount == 3) {
 
771
        glActiveTexture(GL_TEXTURE0);
 
772
        glBindTexture(GL_TEXTURE_2D, m_textureIds[0]);
 
773
        glActiveTexture(GL_TEXTURE1);
 
774
        glBindTexture(GL_TEXTURE_2D, m_textureIds[1]);
 
775
        glActiveTexture(GL_TEXTURE2);
 
776
        glBindTexture(GL_TEXTURE_2D, m_textureIds[2]);
 
777
        glActiveTexture(GL_TEXTURE0);
 
778
 
 
779
        m_program.setUniformValue("texY", 0);
 
780
        m_program.setUniformValue("texU", 1);
 
781
        m_program.setUniformValue("texV", 2);
 
782
    } else {
 
783
        glActiveTexture(GL_TEXTURE0);
 
784
        glBindTexture(GL_TEXTURE_2D, m_textureIds[0]);
 
785
 
 
786
        m_program.setUniformValue("texRgb", 0);
 
787
    }
 
788
    m_program.setUniformValue("colorMatrix", m_colorMatrix);
 
789
 
 
790
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 
791
 
 
792
    m_program.release();
 
793
}