10 #include <sys/socket.h>
11 #include <linux/input.h>
13 #include <arpa/inet.h>
18 #include <GLES2/gl2.h>
19 #include <GLES2/gl2ext.h>
23 #define DEFAULT_WIDTH (1920)
24 #define DEFAULT_HEIGHT (1080)
25 #define WINDOW_BORDER_COLOR (0xFFFFFFFF)
26 #define WINDOW_BORDER_THICKNESS (4)
29 #define DRM_FORMAT_R8 (0x20203852)
32 #ifndef DRM_FORMAT_GR88
33 #define DRM_FORMAT_GR88 (0x38385247)
36 #ifndef DRM_FORMAT_RG88
37 #define DRM_FORMAT_RG88 (0x38384752)
40 #ifndef DRM_FORMAT_RGBA8888
41 #define DRM_FORMAT_RGBA8888 (0x34324152)
46 #define MAX_TEXTURES (2)
56 int frameBufferCapacity;
59 unsigned char *frameBuffer;
61 GLuint textureId[MAX_TEXTURES];
62 EGLImageKHR eglImage[MAX_TEXTURES];
63 pthread_mutex_t mutex;
71 PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
72 PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
73 PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
117 EGLDisplay eglDisplay;
118 bool haveDmaBufImport;
119 bool haveExternalImage;
122 GLuint shaderVertFill;
123 GLuint shaderFragFill;
125 GLuint attrFillVertex;
126 GLuint uniFillMatrix;
127 GLuint uniFillTarget;
129 long long frameTimePrev;
131 GstElement *pipeline;
139 static void signalHandler(
int signum);
140 static bool createShaders(
AppCtx *ctx,
141 const char *vertSrc, GLuint *vShader,
142 const char *fragSrc, GLuint *fShader );
143 static bool linkProgram(
AppCtx *ctx, GLuint prog );
144 static bool setupFill(
AppCtx *ctx );
145 static bool setupGL(
AppCtx *ctx );
146 static void fillRect(
AppCtx *ctx,
int x,
int y,
int w,
int h,
unsigned argb );
147 static void terminated(
void * );
148 static void keyPressed(
void *userData,
unsigned int key );
149 static void keyReleased(
void *userData,
unsigned int );
150 static void pointerMotion(
void *userData,
int,
int );
151 static void pointerButtonPressed(
void *userData,
int button,
int x,
int y );
152 static void pointerButtonReleased(
void *userData,
int,
int,
int );
153 static void showUsage();
155 static bool gRunning;
156 static int gDisplayWidth;
157 static int gDisplayHeight;
159 static long long getMonotonicTimeMicros(
void )
164 static bool reportedError=
false;
165 if ( !reportedError )
167 rc= clock_gettime( CLOCK_MONOTONIC, &tm );
169 if ( reportedError || rc )
172 if ( !reportedError )
175 printf(
"clock_gettime failed rc %d - using timeofday\n", rc);
178 timeMicro= tv.tv_sec*1000000LL+tv.tv_usec;
182 timeMicro= tm.tv_sec*1000000LL+(tm.tv_nsec/1000LL);
187 static void signalHandler(
int signum)
189 printf(
"signalHandler: signum %d\n", signum);
193 static const char *vertFillSrc=
194 "uniform mat4 matrix;\n"
195 "uniform vec2 targetSize;\n"
196 "attribute vec2 vertex;\n"
199 " vec4 pos= matrix * vec4(vertex, 0, 1);\n"
200 " vec4 scale= vec4( targetSize, 1, 1) * vec4( 0.5, -0.5, 1, 1);\n"
201 " pos= pos / scale;\n"
202 " pos= pos - vec4( 1, -1, 0, 0 );\n"
203 " gl_Position= pos;\n"
205 static const char *fragFillSrc=
207 "precision mediump float;\n"
209 "uniform vec4 color;\n"
212 " gl_FragColor= color;\n"
215 static bool createShaders(
AppCtx *ctx,
216 const char *vertSrc, GLuint *vShader,
217 const char *fragSrc, GLuint *fShader )
222 GLuint shader, type, vshader, fshader;
224 const char *src, *typeName;
226 for( pass= 0; pass < 2; ++pass )
228 type= (pass == 0) ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER;
229 src= (pass == 0) ? vertSrc : fragSrc;
230 typeName= (pass == 0) ?
"vertex" :
"fragment";
231 shader= glCreateShader( type );
234 printf(
"Error: glCreateShader failed for %s shader\n", typeName);
237 glShaderSource( shader, 1, (
const char **)&src, NULL );
238 glCompileShader( shader );
239 glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
242 glGetShaderInfoLog( shader,
sizeof(log), &length, log );
243 printf(
"Error compiling %s shader: %*s\n",
259 static bool linkProgram(
AppCtx *ctx, GLuint prog )
264 glGetProgramiv(prog, GL_LINK_STATUS, &status);
269 glGetProgramInfoLog(prog, 1000, &len, log);
270 printf(
"Error: linking:\n%*s\n", len, log);
278 static bool setupFill(
AppCtx *ctx )
281 if ( !createShaders( ctx, vertFillSrc, &ctx->shaderVertFill, fragFillSrc, &ctx->shaderFragFill ) )
285 ctx->progFill= glCreateProgram();
286 glAttachShader( ctx->progFill, ctx->shaderVertFill );
287 glAttachShader( ctx->progFill, ctx->shaderFragFill );
288 ctx->attrFillVertex= 0;
289 glBindAttribLocation(ctx->progFill, ctx->attrFillVertex,
"vertex");
290 if ( !linkProgram( ctx, ctx->progFill ) )
294 ctx->uniFillMatrix= glGetUniformLocation( ctx->progFill,
"matrix" );
295 if ( ctx->uniFillTarget == -1 )
297 printf(
"Error: uniform 'natrix' error\n");
300 ctx->uniFillTarget= glGetUniformLocation( ctx->progFill,
"targetSize" );
301 if ( ctx->uniFillTarget == -1 )
303 printf(
"Error: uniform 'targetSize' error\n");
306 ctx->uniFillColor= glGetUniformLocation( ctx->progFill,
"color" );
307 if ( ctx->uniFillColor == -1 )
309 printf(
"Error: uniform 'color' error\n");
316 static bool setupGL(
AppCtx *ctx )
319 if ( !setupFill( ctx ) )
328 static void fillRect(
AppCtx *ctx,
int x,
int y,
int w,
int h,
unsigned argb )
330 GLfloat verts[4][2]= {
331 { (float)x, (
float)y },
332 { (float)x+w, (
float)y },
333 { (float)x, (
float)y+h },
334 { (float)x+w, (
float)y+h }
338 ((float)((argb>>16)&0xFF))/255.0f,
339 ((float)((argb>>8)&0xFF))/255.0f,
340 ((float)((argb)&0xFF))/255.0f,
341 ((float)((argb>>24)&0xFF))/255.0f,
352 glUseProgram( ctx->progFill );
353 glUniformMatrix4fv( ctx->uniFillMatrix, 1, GL_FALSE, (GLfloat*)matrix );
354 glUniform2f( ctx->uniFillTarget, ctx->windowWidth, ctx->windowHeight );
355 glUniform4fv( ctx->uniFillColor, 1, color );
356 glVertexAttribPointer( ctx->attrFillVertex, 2, GL_FLOAT, GL_FALSE, 0, verts );
357 glEnableVertexAttribArray( ctx->attrFillVertex );
358 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
359 glDisableVertexAttribArray( ctx->attrFillVertex );
360 int err= glGetError();
363 printf(
"glError: %d\n", err);
367 static void terminated(
void * )
369 printf(
"terminated event\n");
373 static EssTerminateListener terminateListener=
378 static void keyPressed(
void *userData,
unsigned int key )
391 static void keyReleased(
void *userData,
unsigned int key )
399 static EssKeyListener keyListener=
405 static void pointerMotion(
void *userData,
int,
int )
410 static void pointerButtonPressed(
void *userData,
int button,
int x,
int y )
418 static void pointerButtonReleased(
void *userData,
int,
int,
int )
423 static EssPointerListener pointerListener=
426 pointerButtonPressed,
427 pointerButtonReleased
430 void displaySize(
void *userData,
int width,
int height )
434 if ( (gDisplayWidth != width) || (gDisplayHeight != height) )
436 printf(
"nwvidtex: display size changed: %dx%d\n", width, height);
438 gDisplayWidth= width;
439 gDisplayHeight= height;
441 EssContextResizeWindow( ctx->essCtx, width, height );
446 static EssSettingsListener settingsListener=
451 static void showUsage()
454 printf(
" nwvidtex [options] <streamURI>\n" );
455 printf(
" streamURI - input media stream URI\n");
456 printf(
"where [options] are:\n" );
457 printf(
" --window-size <width>x<height> (eg --window-size 640x480)\n");
458 printf(
" --video-rect <x>,<y>,<w>,<h> (eg --video-rect 100,100,320,200)\n");
459 printf(
" -? : show usage\n" );
463 static const char *vertColor=
464 "uniform mat4 u_matrix;\n"
465 "uniform vec4 u_offset;\n"
466 "attribute vec4 pos;\n"
467 "attribute vec4 color;\n"
468 "varying vec4 v_color;\n"
471 " gl_Position= u_matrix * pos + u_offset;\n"
475 static const char *fragColor=
477 "precision mediump float;\n"
479 "varying vec4 v_color;\n"
482 " gl_FragColor= v_color;\n"
485 static const char *vertTexture=
486 "attribute vec2 pos;\n"
487 "attribute vec2 texcoord;\n"
488 "uniform mat4 u_matrix;\n"
489 "uniform vec2 u_resolution;\n"
493 " vec4 v1= u_matrix * vec4(pos, 0, 1);\n"
494 " vec4 v2= v1 / vec4(u_resolution, u_resolution.x, 1);\n"
495 " vec4 v3= v2 * vec4(2.0, 2.0, 1, 1);\n"
496 " vec4 v4= v3 - vec4(1.0, 1.0, 0, 0);\n"
498 " gl_Position= v4 * vec4(1, -1, 1, 1);\n"
502 static const char *fragTexture=
504 "precision mediump float;\n"
506 "uniform sampler2D texture;\n"
510 " gl_FragColor= texture2D(texture, tx);\n"
513 static const char *fragTextureExternal=
514 "#extension GL_OES_EGL_image_external : require\n"
516 "precision mediump float;\n"
518 "uniform samplerExternalOES texture;\n"
522 " gl_FragColor= texture2D(texture, tx);\n"
525 static const char *vertTextureYUV=
526 "attribute vec2 pos;\n"
527 "attribute vec2 texcoord;\n"
528 "attribute vec2 texcoorduv;\n"
529 "uniform mat4 u_matrix;\n"
530 "uniform vec2 u_resolution;\n"
532 "varying vec2 txuv;\n"
535 " vec4 v1= u_matrix * vec4(pos, 0, 1);\n"
536 " vec4 v2= v1 / vec4(u_resolution, u_resolution.x, 1);\n"
537 " vec4 v3= v2 * vec4(2.0, 2.0, 1, 1);\n"
538 " vec4 v4= v3 - vec4(1.0, 1.0, 0, 0);\n"
540 " gl_Position= v4 * vec4(1, -1, 1, 1);\n"
542 " txuv= texcoorduv;\n"
545 static const char *fragTextureYUV=
547 "precision mediump float;\n"
549 "uniform sampler2D texture;\n"
550 "uniform sampler2D textureuv;\n"
551 "const vec3 cc_r= vec3(1.0, -0.8604, 1.59580);\n"
552 "const vec4 cc_g= vec4(1.0, 0.539815, -0.39173, -0.81290);\n"
553 "const vec3 cc_b= vec3(1.0, -1.071, 2.01700);\n"
555 "varying vec2 txuv;\n"
558 " vec4 y_vec= texture2D(texture, tx);\n"
559 " vec4 c_vec= texture2D(textureuv, txuv);\n"
560 " vec4 temp_vec= vec4(y_vec.r, 1.0, c_vec.r, c_vec.g);\n"
561 " gl_FragColor= vec4( dot(cc_r,temp_vec.xyw), dot(cc_g,temp_vec), dot(cc_b,temp_vec.xyz), 1 );\n"
564 static bool initGL(
GLCtx *ctx )
570 const char *fragSrc, *vertSrc;
572 ctx->eglCreateImageKHR= (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress(
"eglCreateImageKHR");
573 if ( !ctx->eglCreateImageKHR )
575 printf(
"Error: initGL: no eglCreateImageKHR\n");
579 ctx->eglDestroyImageKHR= (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress(
"eglDestroyImageKHR");
580 if ( !ctx->eglDestroyImageKHR )
582 printf(
"Error: initGL: no eglDestroyImageKHR\n");
586 ctx->glEGLImageTargetTexture2DOES= (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress(
"glEGLImageTargetTexture2DOES");
587 if ( !ctx->glEGLImageTargetTexture2DOES )
589 printf(
"Error: initGL: no glEGLImageTargetTexture2DOES\n");
594 ctx->fragColor= glCreateShader( GL_FRAGMENT_SHADER );
595 if ( !ctx->fragColor )
597 printf(
"Error: initGL: failed to create color fragment shader\n");
601 glShaderSource( ctx->fragColor, 1, (
const char **)&fragColor, NULL );
602 glCompileShader( ctx->fragColor );
603 glGetShaderiv( ctx->fragColor, GL_COMPILE_STATUS, &status );
606 glGetShaderInfoLog( ctx->fragColor,
sizeof(infoLog), &length, infoLog );
607 printf(
"Error: initGL: compiling color fragment shader: %*s\n", length, infoLog );
611 ctx->vertColor= glCreateShader( GL_VERTEX_SHADER );
612 if ( !ctx->vertColor )
614 printf(
"Error: initGL: failed to create color vertex shader\n");
618 glShaderSource( ctx->vertColor, 1, (
const char **)&vertColor, NULL );
619 glCompileShader( ctx->vertColor );
620 glGetShaderiv( ctx->vertColor, GL_COMPILE_STATUS, &status );
623 glGetShaderInfoLog( ctx->vertColor,
sizeof(infoLog), &length, infoLog );
624 printf(
"Error: initGL: compiling color vertex shader: \n%*s\n", length, infoLog );
628 ctx->progColor= glCreateProgram();
629 glAttachShader(ctx->progColor, ctx->fragColor);
630 glAttachShader(ctx->progColor, ctx->vertColor);
633 ctx->locColorColor= 1;
634 glBindAttribLocation(ctx->progColor, ctx->locPosColor,
"pos");
635 glBindAttribLocation(ctx->progColor, ctx->locColorColor,
"color");
637 glLinkProgram(ctx->progColor);
638 glGetProgramiv(ctx->progColor, GL_LINK_STATUS, &status);
641 glGetProgramInfoLog(ctx->progColor,
sizeof(infoLog), &length, infoLog);
642 printf(
"Error: initGL: linking:\n%*s\n", length, infoLog);
646 ctx->locOffsetColor= glGetUniformLocation(ctx->progColor,
"u_offset");
647 ctx->locMatrixColor= glGetUniformLocation(ctx->progColor,
"u_matrix");
651 if ( ctx->haveYUVShaders )
653 fragSrc= fragTextureYUV;
654 vertSrc= vertTextureYUV;
658 fragSrc= (ctx->appCtx->haveExternalImage ? fragTextureExternal : fragTexture);
659 vertSrc= vertTexture;
662 ctx->fragTex= glCreateShader( GL_FRAGMENT_SHADER );
665 printf(
"Error: initGL: failed to create texture fragment shader\n");
669 glShaderSource( ctx->fragTex, 1, (
const char **)&fragSrc, NULL );
670 glCompileShader( ctx->fragTex );
671 glGetShaderiv( ctx->fragTex, GL_COMPILE_STATUS, &status );
674 glGetShaderInfoLog( ctx->fragTex,
sizeof(infoLog), &length, infoLog );
675 printf(
"Error: initGL: compiling texture fragment shader: %*s\n", length, infoLog );
679 ctx->vertTex= glCreateShader( GL_VERTEX_SHADER );
682 printf(
"Error: initGL: failed to create texture vertex shader\n");
686 glShaderSource( ctx->vertTex, 1, (
const char **)&vertSrc, NULL );
687 glCompileShader( ctx->vertTex );
688 glGetShaderiv( ctx->vertTex, GL_COMPILE_STATUS, &status );
691 glGetShaderInfoLog( ctx->vertTex,
sizeof(infoLog), &length, infoLog );
692 printf(
"Error: initGL: compiling texture vertex shader: \n%*s\n", length, infoLog );
696 ctx->progTex= glCreateProgram();
697 glAttachShader(ctx->progTex, ctx->fragTex);
698 glAttachShader(ctx->progTex, ctx->vertTex);
702 glBindAttribLocation(ctx->progTex, ctx->locPosTex,
"pos");
703 glBindAttribLocation(ctx->progTex, ctx->locTC,
"texcoord");
704 if ( ctx->haveYUVShaders )
707 glBindAttribLocation(ctx->progTex, ctx->locTCUV,
"texcoorduv");
710 glLinkProgram(ctx->progTex);
711 glGetProgramiv(ctx->progTex, GL_LINK_STATUS, &status);
714 glGetProgramInfoLog(ctx->progTex,
sizeof(infoLog), &length, infoLog);
715 printf(
"Error: initGL: linking:\n%*s\n", length, infoLog);
719 ctx->locResTex= glGetUniformLocation(ctx->progTex,
"u_resolution");
720 ctx->locMatrixTex= glGetUniformLocation(ctx->progTex,
"u_matrix");
721 ctx->locTexture= glGetUniformLocation(ctx->progTex,
"texture");
722 if ( ctx->haveYUVShaders )
724 ctx->locTextureUV= glGetUniformLocation(ctx->progTex,
"textureuv");
734 static void termGL(
GLCtx *glCtx )
736 if ( glCtx->fragTex )
738 glDeleteShader( glCtx->fragTex );
741 if ( glCtx->vertTex )
743 glDeleteShader( glCtx->vertTex );
746 if ( glCtx->progTex )
748 glDeleteProgram( glCtx->progTex );
753 static void drawSurface(
GLCtx *glCtx,
Surface *surface )
755 AppCtx *appCtx= glCtx->appCtx;
764 const float verts[4][2]=
766 { float(x), float(y) },
767 { float(x+w), float(y) },
768 { float(x), float(y+h) },
769 { float(x+w), float(y+h) }
772 const float uv[4][2]=
780 const float identityMatrix[4][4]=
788 if ( glCtx->haveYUVShaders != surface->haveYUVTextures )
791 glCtx->haveYUVShaders= surface->haveYUVTextures;
792 if ( !initGL( glCtx ) )
794 printf(
"Error: drawSurface: initGL failed while changing shaders\n");
798 if ( (surface->textureId[0] == GL_NONE) || surface->dirty || surface->externalImage )
800 for(
int i= 0; i < surface->textureCount; ++i )
802 if ( surface->textureId[i] == GL_NONE )
804 glGenTextures(1, &surface->textureId[i] );
807 glActiveTexture(GL_TEXTURE0+i);
808 glBindTexture(GL_TEXTURE_2D, surface->textureId[i] );
809 if ( surface->eglImage[i] )
811 if ( surface->externalImage )
813 glCtx->glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, surface->eglImage[i]);
817 glCtx->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, surface->eglImage[i]);
820 else if ( surface->frameBuffer )
823 glTexImage2D( GL_TEXTURE_2D, 0, GL_BGRA_EXT, surface->frameWidth, surface->frameHeight,
824 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, surface->frameBuffer );
826 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface->frameWidth, surface->frameHeight,
827 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->frameBuffer );
829 surface->dirty=
false;
832 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
833 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
834 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
835 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
839 glUseProgram(glCtx->progTex);
840 glUniform2f(glCtx->locResTex, appCtx->windowWidth, appCtx->windowHeight);
841 glUniformMatrix4fv(glCtx->locMatrixTex, 1, GL_FALSE, (GLfloat*)identityMatrix);
843 glActiveTexture(GL_TEXTURE0);
844 glBindTexture(GL_TEXTURE_2D, surface->textureId[0]);
845 glUniform1i(glCtx->locTexture, 0);
846 glVertexAttribPointer(glCtx->locPosTex, 2, GL_FLOAT, GL_FALSE, 0, verts);
847 glVertexAttribPointer(glCtx->locTC, 2, GL_FLOAT, GL_FALSE, 0, uv);
848 glEnableVertexAttribArray(glCtx->locPosTex);
849 glEnableVertexAttribArray(glCtx->locTC);
850 if ( surface->haveYUVTextures )
852 glActiveTexture(GL_TEXTURE1);
853 glBindTexture(GL_TEXTURE_2D, surface->textureId[1]);
854 glUniform1i(glCtx->locTextureUV, 1);
855 glVertexAttribPointer(glCtx->locTCUV, 2, GL_FLOAT, GL_FALSE, 0, uv);
856 glEnableVertexAttribArray(glCtx->locTCUV);
858 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
859 glDisableVertexAttribArray(glCtx->locPosTex);
860 glDisableVertexAttribArray(glCtx->locTC);
861 if ( surface->haveYUVTextures )
863 glDisableVertexAttribArray(glCtx->locTCUV);
867 if ( glerr != GL_NO_ERROR )
869 printf(
"Warning: drawSurface: glGetError: %X\n", glerr);
873 static void newVideoTexture( GstElement *elmnt, guint format, guint width, guint height,
874 gint fd0, guint p0l, guint p0s, gpointer p0d,
875 gint fd1, guint p1l, guint p1s, gpointer p1d,
876 gint fd2, guint p2l, guint p2s, gpointer p2d,
880 GLCtx *gl= &appCtx->gl;
881 Surface *surface= &appCtx->surface;
883 pthread_mutex_lock( &surface->mutex );
886 #ifdef EGL_LINUX_DMA_BUF_EXT
887 for(
int i= 0; i < MAX_TEXTURES; ++i )
889 if ( surface->eglImage[i] )
891 gl->eglDestroyImageKHR( appCtx->eglDisplay, surface->eglImage[i] );
892 surface->eglImage[i]= 0;
896 #ifdef GL_OES_EGL_image_external
898 attr[i++]= EGL_WIDTH;
900 attr[i++]= EGL_HEIGHT;
902 attr[i++]= EGL_LINUX_DRM_FOURCC_EXT;
904 attr[i++]= EGL_DMA_BUF_PLANE0_FD_EXT;
906 attr[i++]= EGL_DMA_BUF_PLANE0_OFFSET_EXT;
908 attr[i++]= EGL_DMA_BUF_PLANE0_PITCH_EXT;
910 attr[i++]= EGL_DMA_BUF_PLANE1_FD_EXT;
912 attr[i++]= EGL_DMA_BUF_PLANE1_OFFSET_EXT;
913 attr[i++]= (fd0 != fd1 ? 0 : width*height);
914 attr[i++]= EGL_DMA_BUF_PLANE1_PITCH_EXT;
916 attr[i++]= EGL_YUV_COLOR_SPACE_HINT_EXT;
917 attr[i++]= EGL_ITU_REC709_EXT;
918 attr[i++]= EGL_SAMPLE_RANGE_HINT_EXT;
919 attr[i++]= EGL_YUV_FULL_RANGE_EXT;
922 surface->eglImage[0]= gl->eglCreateImageKHR( appCtx->eglDisplay,
924 EGL_LINUX_DMA_BUF_EXT,
925 (EGLClientBuffer)NULL,
927 if ( surface->eglImage[0] == 0 )
929 printf(
"Error: updateFrame: eglCreateImageKHR failed for fd %d: errno %X\n", fd0, eglGetError());
931 if ( surface->textureId[0] != GL_NONE )
933 glDeleteTextures( 1, &surface->textureId[0] );
934 surface->textureId[0]= GL_NONE;
937 surface->textureCount= 1;
938 surface->haveYUVTextures=
false;
939 surface->externalImage=
true;
945 attr[4]= EGL_LINUX_DRM_FOURCC_EXT;
946 attr[5]= DRM_FORMAT_R8;
947 attr[6]= EGL_DMA_BUF_PLANE0_FD_EXT;
949 attr[8]= EGL_DMA_BUF_PLANE0_OFFSET_EXT;
951 attr[10]= EGL_DMA_BUF_PLANE0_PITCH_EXT;
955 surface->eglImage[0]= gl->eglCreateImageKHR( appCtx->eglDisplay,
957 EGL_LINUX_DMA_BUF_EXT,
958 (EGLClientBuffer)NULL,
960 if ( surface->eglImage[0] == 0 )
962 printf(
"Error: updateFrame: eglCreateImageKHR failed for fd %d: errno %X\n", fd0, eglGetError());
964 if ( surface->textureId[0] != GL_NONE )
966 glDeleteTextures( 1, &surface->textureId[0] );
967 surface->textureId[0]= GL_NONE;
974 attr[4]= EGL_LINUX_DRM_FOURCC_EXT;
975 attr[5]= DRM_FORMAT_GR88;
976 attr[6]= EGL_DMA_BUF_PLANE0_FD_EXT;
978 attr[8]= EGL_DMA_BUF_PLANE0_OFFSET_EXT;
979 attr[9]= width*height;
980 attr[10]= EGL_DMA_BUF_PLANE0_PITCH_EXT;
984 surface->eglImage[1]= gl->eglCreateImageKHR( appCtx->eglDisplay,
986 EGL_LINUX_DMA_BUF_EXT,
987 (EGLClientBuffer)NULL,
989 if ( surface->eglImage[1] == 0 )
991 printf(
"Error: updateFrame: eglCreateImageKHR failed for fd %d: errno %X\n", fd0, eglGetError());
993 if ( surface->textureId[1] != GL_NONE )
995 glDeleteTextures( 1, &surface->textureId[1] );
996 surface->textureId[1]= GL_NONE;
998 surface->textureCount= 2;
999 surface->haveYUVTextures=
true;
1000 surface->externalImage=
false;
1006 if ( format == DRM_FORMAT_RGBA8888 )
1008 if ( !surface->frameBuffer ||
1009 (width != surface->frameWidth) ||
1010 (height != surface->frameHeight) )
1012 if ( surface->frameBuffer )
1014 free( surface->frameBuffer );
1015 surface->frameBuffer= 0;
1017 surface->frameBuffer= (
unsigned char*)malloc( p0l );
1018 if ( surface->frameBuffer )
1020 surface->frameBufferCapacity= p0l;
1021 surface->frameWidth= width;
1022 surface->frameHeight= height;
1025 if ( surface->frameBuffer )
1028 memcpy( surface->frameBuffer, p0d, p0l );
1030 unsigned char a, r, g, b;
1031 unsigned char *s= (
unsigned char *)p0d;
1032 unsigned char *d= surface->frameBuffer;
1033 for(
int i= 0; i < height; ++i )
1035 for(
int j= 0; j < width; ++j )
1048 surface->textureCount= 1;
1049 surface->haveYUVTextures=
false;
1050 surface->externalImage=
false;
1051 surface->dirty=
true;
1055 appCtx->dirty=
true;
1056 pthread_mutex_unlock( &surface->mutex );
1059 static gboolean busCallback(GstBus *bus, GstMessage *message, gpointer data)
1063 switch ( GST_MESSAGE_TYPE(message) )
1065 case GST_MESSAGE_ERROR:
1070 gst_message_parse_error(message, &error, &debug);
1071 g_print(
"Error: %s\n", error->message);
1074 g_print(
"Debug info: %s\n", debug);
1076 g_error_free(error);
1079 g_main_loop_quit( ctx->loop );
1082 case GST_MESSAGE_EOS:
1083 g_print(
"EOS ctx %p\n", ctx );
1085 g_main_loop_quit( ctx->loop );
1093 static bool createPipeline(
AppCtx *ctx )
1099 gst_init( &argc, &argv );
1101 ctx->pipeline= gst_pipeline_new(
"pipeline");
1102 if ( !ctx->pipeline )
1104 printf(
"Error: unable to create pipeline instance\n" );
1108 ctx->bus= gst_pipeline_get_bus( GST_PIPELINE(ctx->pipeline) );
1111 printf(
"Error: unable to get pipeline bus\n");
1114 gst_bus_add_watch( ctx->bus, busCallback, ctx );
1116 ctx->playbin= gst_element_factory_make(
"playbin",
"playbin" );
1117 if ( !ctx->playbin )
1119 printf(
"Error: unable to create playbin instance\n" );
1122 gst_object_ref( ctx->playbin );
1124 if ( !gst_bin_add( GST_BIN(ctx->pipeline), ctx->playbin) )
1126 printf(
"Error: unable to add playbin to pipeline\n");
1130 ctx->vidsink= gst_element_factory_make(
"westerossink",
"vidsink" );
1131 if ( !ctx->vidsink )
1133 printf(
"Error: unable to create westerossink instance\n" );
1136 gst_object_ref( ctx->vidsink );
1138 g_object_set(G_OBJECT(ctx->playbin),
"video-sink", ctx->vidsink, NULL );
1147 static void destroyPipeline(
AppCtx *ctx )
1149 if ( ctx->pipeline )
1151 gst_element_set_state(ctx->pipeline, GST_STATE_NULL);
1155 gst_object_unref( ctx->vidsink );
1160 gst_object_unref( ctx->playbin );
1165 gst_object_unref( ctx->bus );
1168 if ( ctx->pipeline )
1170 gst_object_unref( GST_OBJECT(ctx->pipeline) );
1175 void render(
AppCtx *ctx )
1178 int boundsX, boundsY, boundsW, boundsH;
1180 glViewport( 0, 0, gDisplayWidth, gDisplayHeight );
1182 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1183 glClear(GL_COLOR_BUFFER_BIT);
1184 glFrontFace( GL_CW );
1185 glBlendFuncSeparate( GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE );
1190 boundsW= ctx->windowWidth;
1191 boundsH= ctx->windowHeight;
1192 fillRect( ctx, boundsX, boundsY, boundsW, WINDOW_BORDER_THICKNESS, WINDOW_BORDER_COLOR );
1193 fillRect( ctx, boundsX, boundsY+boundsH-WINDOW_BORDER_THICKNESS, boundsW, WINDOW_BORDER_THICKNESS, WINDOW_BORDER_COLOR );
1194 fillRect( ctx, boundsX, boundsY, WINDOW_BORDER_THICKNESS, boundsH, WINDOW_BORDER_COLOR );
1195 fillRect( ctx, boundsX+boundsW-WINDOW_BORDER_THICKNESS, boundsY, WINDOW_BORDER_THICKNESS, boundsH, WINDOW_BORDER_COLOR );
1197 surface= &ctx->surface;
1198 pthread_mutex_lock( &surface->mutex );
1199 if ( surface->eglImage[0] || surface->frameBuffer )
1201 drawSurface( &ctx->gl, surface );
1203 pthread_mutex_unlock( &surface->mutex );
1206 int main(
int argc,
char **argv )
1212 const char *streamURI= 0;
1214 printf(
"nwvidtex v1.0\n");
1218 printf(
"Error: no memory for app context\n");
1222 ctx->windowWidth= DEFAULT_WIDTH;
1223 ctx->windowHeight= DEFAULT_HEIGHT;
1226 ctx->videoWidth= DEFAULT_WIDTH;
1227 ctx->videoHeight= DEFAULT_HEIGHT;
1230 ctx->essCtx= EssContextCreate();
1233 printf(
"Error: EssContextCreate failed\n");
1238 while ( argidx < argc )
1240 if ( argv[argidx][0] ==
'-' )
1242 len= strlen(argv[argidx]);
1243 if ( (len == 13) && !strncmp( argv[argidx],
"--window-size", len) )
1245 if ( argidx+1 < argc )
1249 if ( sscanf( argv[argidx],
"%dx%d", &w, &h ) == 2 )
1251 if ( (w > 0) && (h > 0) )
1253 ctx->windowWidth= w;
1254 ctx->windowHeight= h;
1259 else if ( (len == 12) && !strncmp( argv[argidx],
"--video-rect", len) )
1262 if ( argidx < argc )
1265 if ( sscanf( argv[argidx],
"%d,%d,%d,%d", &x, &y, &w, &h ) == 4 )
1270 ctx->videoHeight= h;
1274 else if ( (len == 2) && !strncmp( (
const char*)argv[argidx],
"-?", len ) )
1280 printf(
"Unrecognized option: (%s)\n", argv[argidx] );
1287 streamURI= argv[argidx];
1291 printf(
"ignoring extra argument: %s\n", argv[argidx] );
1297 if ( !EssContextSetInitialWindowSize( ctx->essCtx, ctx->windowWidth, ctx->windowHeight) )
1302 if ( !EssContextSetName( ctx->essCtx,
"nwvidtex" ) )
1307 if ( !EssContextSetTerminateListener( ctx->essCtx, ctx, &terminateListener ) )
1312 if ( !EssContextSetKeyListener( ctx->essCtx, ctx, &keyListener ) )
1317 if ( !EssContextSetPointerListener( ctx->essCtx, ctx, &pointerListener ) )
1322 if ( !EssContextSetSettingsListener( ctx->essCtx, ctx, &settingsListener ) )
1329 struct sigaction sigint;
1331 sigint.sa_handler= signalHandler;
1332 sigemptyset(&sigint.sa_mask);
1333 sigint.sa_flags= SA_RESETHAND;
1334 sigaction(SIGINT, &sigint, NULL);
1336 if ( !EssContextStart( ctx->essCtx ) )
1341 if ( !EssContextGetDisplaySize( ctx->essCtx, &gDisplayWidth, &gDisplayHeight ) )
1346 if ( !setupGL( ctx ) )
1354 const char *eglExtensions= 0;
1355 const char *glExtensions= 0;
1358 ctx->eglDisplay= eglGetCurrentDisplay();
1359 if ( ctx->eglDisplay == EGL_NO_DISPLAY )
1361 printf(
"unable to get EGL display\n");
1365 eglExtensions= eglQueryString( ctx->eglDisplay, EGL_EXTENSIONS );
1366 if ( eglExtensions )
1368 if ( strstr( eglExtensions,
"EGL_EXT_image_dma_buf_import" ) )
1370 ctx->haveDmaBufImport=
true;
1374 glExtensions= (
const char *)glGetString(GL_EXTENSIONS);
1377 #ifdef GL_OES_EGL_image_external
1378 if ( strstr( glExtensions,
"GL_OES_EGL_image_external" ) )
1380 ctx->haveExternalImage= ctx->haveDmaBufImport;
1385 printf(
"Have dmabuf import: %d\n", ctx->haveDmaBufImport );
1386 printf(
"Have external image: %d\n", ctx->haveExternalImage );
1388 surface= &ctx->surface;
1389 memset( surface, 0,
sizeof(
Surface) );
1390 surface->x= ctx->videoX;
1391 surface->y= ctx->videoY;
1392 surface->w= ctx->videoWidth;
1393 surface->h= ctx->videoHeight;
1394 pthread_mutex_init( &surface->mutex, 0 );
1396 ctx->gl.appCtx= ctx;
1397 if ( !initGL( &ctx->gl ) )
1399 printf(
"Error: failed to setup GL\n");
1404 memset( ctx->matrix, 0,
sizeof(ctx->matrix) );
1405 ctx->matrix[0]= ctx->matrix[5]= ctx->matrix[10]= ctx->matrix[15]= 1.0;
1407 if ( !createPipeline( ctx ) )
1412 printf(
"pipeline created\n");
1414 g_object_set(G_OBJECT(ctx->playbin),
"uri", streamURI, NULL );
1416 sprintf( work,
"%d,%d,%d,%d", ctx->videoX, ctx->videoY, ctx->videoWidth, ctx->videoHeight );
1417 g_object_set(G_OBJECT(ctx->vidsink),
"rectangle", work, NULL );
1419 g_signal_connect( G_OBJECT(ctx->vidsink),
"new-video-texture-callback", G_CALLBACK(newVideoTexture), ctx );
1421 g_object_set(G_OBJECT(ctx->vidsink),
"enable-texture", 1, NULL );
1423 g_object_set(G_OBJECT(ctx->vidsink),
"show-video-window", 0, NULL );
1425 ctx->loop= g_main_loop_new(NULL,FALSE);
1428 if ( GST_STATE_CHANGE_FAILURE != gst_element_set_state(ctx->pipeline, GST_STATE_PLAYING) )
1433 g_main_context_iteration( NULL, FALSE );
1435 EssContextRunEventLoopOnce( ctx->essCtx );
1443 EssContextUpdateDisplay( ctx->essCtx );
1457 const char *detail= EssContextGetLastErrorDetail( ctx->essCtx );
1458 printf(
"Essos error: (%s)\n", detail );
1467 destroyPipeline( ctx );
1471 g_main_loop_unref(ctx->loop);
1475 surface= &ctx->surface;
1476 for(
int i= 0; i < MAX_TEXTURES; ++i )
1478 if ( surface->eglImage[i] )
1480 ctx->gl.eglDestroyImageKHR( ctx->eglDisplay, surface->eglImage[i] );
1481 surface->eglImage[i]= 0;
1489 EssContextDestroy( ctx->essCtx );
1492 pthread_mutex_destroy( &ctx->surface.mutex );