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