1 /**
2 \brief VDPAU filters Deinterlacer
3 \author mean (C) 2010
4
5 This version uses openGL to convert the output surface to YV12
6
7
8 */
9
10
11 #define __STDC_CONSTANT_MACROS
12 #define GL_GLEXT_PROTOTYPES
13
14 # include <GL/gl.h>
15 # include <GL/glu.h>
16 # include <GL/glext.h>
17
18 #include <QtGui/QImage>
19 #include <QtOpenGL/QtOpenGL>
20 #include <QtOpenGL/QGLShader>
21 #include <list>
22
23 #include "ADM_coreConfig.h"
24 #ifdef USE_VDPAU
25 extern "C" {
26 #include "libavcodec/avcodec.h"
27 #include "libavcodec/vdpau.h"
28 }
29
30 #define ADM_LEGACY_PROGGY
31 #include "ADM_default.h"
32
33 #include "ADM_coreVideoFilterInternal.h"
34 #include "ADM_videoFilterCache.h"
35 #include "DIA_factory.h"
36 #include "ADM_vidMisc.h"
37
38 #include "T_openGLFilter.h"
39
40
41 #include "vdpauFilterDeint.h"
42 #include "ADM_vidVdpauFilterDeint.h"
43 #include "ADM_coreVdpau/include/ADM_coreVdpau.h"
44 //
45 //#define DO_BENCHMARK
46 #define NB_BENCH 100
47
48 #if 0
49 #define aprintf printf
50 #else
51 #define aprintf(...) {}
52 #endif
53
54
55
56 static const char *glShaderRgb =
57 "#extension GL_ARB_texture_rectangle: enable\n"
58 "uniform sampler2DRect myTextureY;\n" // tex unit 0
59 "uniform mat4 metrix;\n"
60 "uniform float myWidth;\n"
61 "uniform float myHeight;\n"
62 "const vec4 offset=vec4(0,0.5,0.5,0);\n"
63 "void main(void) {\n"
64 " float nx = gl_TexCoord[0].x;\n"
65 " float ny = gl_TexCoord[0].y;\n"
66 " vec4 texin = texture2DRect(myTextureY, vec2(nx,ny));\n"
67 " vec4 texout;\n"
68 " texout=metrix*texin ;\n"
69 " texout=texout+offset;\n"
70 " gl_FragColor=texout;"
71 "}\n";
72
73 //--------------------------------------------------------------------------------------
74 /***/
75
76
77 /***/
78 PFNGLVDPAUINITNVPROC VDPAUInitNV=NULL;
79 PFNGLVDPAUFININVPROC VDPAUFiniNV=NULL;
80
81 PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC VDPAURegisterOutputSurfaceNV=NULL;
82 PFNGLVDPAUREGISTERVIDEOSURFACENVPROC VDPAURegisterVideoSurfaceNV=NULL;
83 PFNGLVDPAUUNREGISTERSURFACENVPROC VDPAUUnregisterSurfaceNV=NULL;
84
85 PFNGLVDPAUMAPSURFACESNVPROC VDPAUMapSurfacesNV=NULL;
86 PFNGLVDPAUUNMAPSURFACESNVPROC VDPAUUnmapSurfacesNV=NULL;
87 PFNGLVDPAUSURFACEACCESSNVPROC VDPAUSurfaceAccessNV=NULL;
88
89
90 /***/
91 #define GETFUNC(x) x = (typeof(x) )ADM_getGlWidget()->context()->getProcAddress(QLatin1String("gl"#x));\
92 if(!x) \
93 {\
94 ADM_error("Cannot get "#x"\n");\
95 exit(-1);\
96 }
97
98
99 static bool vdpauGlInited=false;
100 /**
101 \fn processError
102 */
processError(const char * e)103 static bool processError(const char *e)
104 {
105 int x=glGetError();
106 if(x!=GL_NO_ERROR)
107 {
108 ADM_error("%s: Error : %d %s\n",e,x,gluErrorString(x));
109 return false;
110 }
111 return true;
112 }
113 /**
114 \fn initGl
115 */
initOnceGl(void)116 bool vdpauVideoFilterDeint::initOnceGl(void)
117 {
118 ADM_info("Initializing VDPAU<->openGl\n");
119 if(vdpauGlInited)
120 {
121 ADM_info("Already done..\n");
122 return true;
123 }
124 GETFUNC(VDPAUInitNV);
125 GETFUNC(VDPAURegisterOutputSurfaceNV);
126 GETFUNC(VDPAURegisterVideoSurfaceNV);
127 GETFUNC(VDPAUUnregisterSurfaceNV);
128 GETFUNC(VDPAUMapSurfacesNV);
129 GETFUNC(VDPAUUnmapSurfacesNV);
130 GETFUNC(VDPAUSurfaceAccessNV);
131 GETFUNC(VDPAUFiniNV);
132 const void *device=admVdpau::getVdpDevice();
133 const void *proc=admVdpau::getProcAddress();
134 ADM_info("VDPAU InitNv with device=%lx, proc=%lx\n",(long int)device,(long int)proc);
135 VDPAUInitNV(device,proc);
136 if(false==processError("InitNv")) return false;
137 vdpauGlInited=true;
138 return true;
139 }
140 /**
141 \fn initGl
142 */
initGl(void)143 bool vdpauVideoFilterDeint::initGl(void)
144 {
145 initOnceGl();
146 ADM_info("Creating VDPAU GL wrapper\n");
147 rgb=new glRGB(this,NULL);
148 //rgb->probe(outputSurface,NULL);
149 return true;
150 }
151
152 /**
153 \fn deInitGl
154 */
deInitGl(void)155 bool vdpauVideoFilterDeint::deInitGl(void)
156 {
157 ADM_info("Destroying VDPAU GL wrapper\n");
158 delete rgb;
159 rgb=NULL;
160 return true;
161 }
162 /**
163 \fn getResultSlow
164 */
getResultSlow(ADMImage * image)165 bool vdpauVideoFilterDeint::getResultSlow(ADMImage *image)
166 {
167
168 if(VDP_STATUS_OK!=admVdpau::outputSurfaceGetBitsNative(outputSurface,
169 tempBuffer,
170 info.width,info.height))
171 {
172 ADM_warning("[Vdpau] Cannot copy back data from output surface\n");
173 return false;
174 }
175
176 // tempBuffer
177 return rgb->imageToImage((const char *)tempBuffer,image);
178 }
179 /**
180 \fn getResult
181 \brief Convert the output surface into an ADMImage
182 */
getResult(ADMImage * image)183 bool vdpauVideoFilterDeint::getResult(ADMImage *image)
184 {
185
186 if(false==rgb->surfaceToImage(outputSurface,image))
187 return getResultSlow(image);
188 return true;
189 }
190 #else // USE_VDPAU
dummy_fun(void)191 static void dummy_fun(void)
192 {
193 return ;
194 }
195 #endif // use VDPAU
196 //-----------------------------------------------------------------
197 /**
198 \fn render
199 */
render(ADMImage * image,ADM_PLANE plane,QGLFramebufferObject * fbo)200 bool glRGB::render(ADMImage *image,ADM_PLANE plane,QGLFramebufferObject *fbo)
201 {
202 int width=image->GetWidth(plane);
203 int height=image->GetHeight(plane);
204
205 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
206 glViewport(0, 0, width, height);
207 glMatrixMode(GL_PROJECTION);
208 glLoadIdentity();
209 glOrtho(0, width, 0, height, -1, 1);
210
211 //
212 glBegin(GL_QUADS);
213 glTexCoord2i(0, 0);
214 glVertex2i(0, 0);
215 glTexCoord2i(width, 0);
216 glVertex2i(width, 0);
217 glTexCoord2i(width, height);
218 glVertex2i(width ,height);
219 glTexCoord2i(0, height);
220 glVertex2i(0, height);
221 glEnd(); // draw cube background
222 return true;
223 }
224 /**
225 \fn ctor
226 */
glRGB(ADM_coreVideoFilter * previous,CONFcouple * conf)227 glRGB::glRGB(ADM_coreVideoFilter *previous,CONFcouple *conf)
228 : ADM_coreVideoFilterQtGl(previous,conf)
229 {
230 widget->makeCurrent();
231 fboY->bind();
232 ADM_info("Compiling shader \n");
233 glProgramY = new QGLShaderProgram(context);
234 ADM_assert(glShaderRgb);
235 if ( !glProgramY->addShaderFromSourceCode(QGLShader::Fragment, glShaderRgb))
236 {
237 ADM_error("[GL Render] Fragment log: %s\n", glProgramY->log().toUtf8().constData());
238 ADM_assert(0);
239 }
240 if ( !glProgramY->link())
241 {
242 ADM_error("[GL Render] Link log: %s\n", glProgramY->log().toUtf8().constData());
243 ADM_assert(0);
244 }
245
246 if ( !glProgramY->bind())
247 {
248 ADM_error("[GL Render] Binding FAILED\n");
249 ADM_assert(0);
250 }
251
252 fboY->release();
253 widget->doneCurrent();
254 //
255 memset(realMatrix,0,sizeof(realMatrix));
256 realMatrix[0]=0.299;
257 realMatrix[1]=0.587;
258 realMatrix[2]=0.114;
259
260 realMatrix[4]=-0.14713;
261 realMatrix[5]=-0.28886;
262 realMatrix[6]=+0.436;
263
264 realMatrix[8]=+0.615;
265 realMatrix[9]=-0.51499;
266 realMatrix[10]=-0.10001;
267
268 }
269 /**
270 \fn dtor
271 */
~glRGB()272 glRGB::~glRGB()
273 {
274
275 }
276 /**
277
278 */
getNextFrame(uint32_t * fn,ADMImage * image)279 bool glRGB::getNextFrame(uint32_t *fn,ADMImage *image) {ADM_assert(0);return false;}
getCoupledConf(CONFcouple ** couples)280 bool glRGB::getCoupledConf(CONFcouple **couples) {ADM_assert(0);return false;};
281 /**
282 \fn probe
283 */
probe(VdpOutputSurface surf,ADMImage * image)284 bool glRGB::probe(VdpOutputSurface surf,ADMImage *image)
285 {
286 widget->makeCurrent();
287 glPushMatrix();
288 // size is the last one...
289 fboY->bind();
290 processError("Bind");
291 GLvdpauSurfaceNV s=VDPAURegisterOutputSurfaceNV((GLvoid *)surf,GL_TEXTURE_2D,1,texName);
292 VDPAUUnregisterSurfaceNV(s);
293 processError("Unregister");
294 fboY->release();
295 firstRun=false;
296 glPopMatrix();
297 widget->doneCurrent();
298 }
299 /**
300 \fn surfaceToImage
301 */
surfaceToImage(VdpOutputSurface surf,ADMImage * image)302 bool glRGB::surfaceToImage(VdpOutputSurface surf,ADMImage *image)
303 {
304 bool r=true;
305 widget->makeCurrent();
306 glPushMatrix();
307 fboY->bind();
308 processError("Bind");
309 glProgramY->setUniformValue("myTextureY", 0);
310 processError("setUniform myTexture0");
311 QMatrix4x4 quadmat(realMatrix);
312 glProgramY->setUniformValue("metrix",quadmat);
313 processError("setUniform Matrix");
314 myGlActiveTexture(GL_TEXTURE0);
315 processError("Active Texture");
316 glBindTexture(GL_TEXTURE_RECTANGLE_NV, texName[0]);
317 processError("Bind Texture");
318 //
319 GLvdpauSurfaceNV s=VDPAURegisterOutputSurfaceNV((GLvoid *)surf,GL_TEXTURE_2D,1,texName);
320 printf("Surface =%d, GlSurface=%x, texName : %d\n",(int)surf,(int)s,(int)texName[0]);
321 if(false==processError("Register"))
322 {
323 r=false;
324 goto skip;
325 }
326 VDPAUSurfaceAccessNV(s,GL_READ_ONLY);
327 VDPAUMapSurfacesNV(1,&s);
328 processError("Map");
329
330 myGlActiveTexture(GL_TEXTURE0);
331 processError("Active Texture");
332 glBindTexture(GL_TEXTURE_RECTANGLE_NV, texName[0]);
333 processError("Bind Texture");
334
335
336 render(image,PLANAR_Y,fboY);
337 downloadTextures(image,fboY);
338
339 VDPAUUnmapSurfacesNV(1,&s);
340 processError("Unmap");
341 VDPAUUnregisterSurfaceNV(s);
342 processError("Unregister");
343 skip:
344 fboY->release();
345 firstRun=false;
346 glPopMatrix();
347 widget->doneCurrent();
348
349
350 return r;
351 }
352 /**
353 \fn image2image
354 */
imageToImage(const char * buffer,ADMImage * image)355 bool glRGB::imageToImage(const char *buffer,ADMImage *image)
356 {
357 bool r=true;
358 int width=image->GetWidth(PLANAR_Y);
359 int height=image->GetHeight(PLANAR_Y);
360 widget->makeCurrent();
361 glPushMatrix();
362 // size is the last one...
363 fboY->bind();
364 processError("Bind");
365 glProgramY->setUniformValue("myTextureY", 0);
366 processError("setUniform myTexture0");
367 QMatrix4x4 quadmat(realMatrix);
368 glProgramY->setUniformValue("metrix",quadmat);
369 processError("setUniform Matrix");
370 myGlActiveTexture(GL_TEXTURE0);
371 processError("Active Texture");
372 glBindTexture(GL_TEXTURE_RECTANGLE_NV, texName[0]);
373 processError("Bind Texture");
374
375 // upload image
376 glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
377 glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
378 glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
379 glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
380 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
381 if(!firstRun)
382 {
383 glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA,
384 width,
385 height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
386 buffer);
387 }else
388 {
389 glTexSubImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 0, 0,
390 width,
391 height,
392 GL_RGBA, GL_UNSIGNED_BYTE,
393 buffer);
394 }
395 //-----------------
396 render(image,PLANAR_Y,fboY);
397 downloadTextures(image,fboY);
398
399 fboY->release();
400 firstRun=false;
401 glPopMatrix();
402 widget->doneCurrent();
403
404
405 return r;
406 }
407
408 //****************
409 // EOF
410