diff options
author | Josep Torra <n770galaxy@gmail.com> | 2014-03-26 13:48:22 +0100 |
---|---|---|
committer | Josep Torra <n770galaxy@gmail.com> | 2014-03-26 16:51:45 +0100 |
commit | 11a0fccf59774c6d927b6b299e87fee99cbdabac (patch) | |
tree | 72479e95eabe136e7bd735970549d6635c0e1d91 | |
parent | c269c64c624c5c69e8e977c65df950285966ea32 (diff) |
Initial conversion to glib
- Added a main loop and a keyboard handler
- Added a dedicated thread for GL stuff
- Reindented the code
- Some minor random fixes
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | triangle.c | 725 | ||||
-rw-r--r-- | triangle.h | 3 | ||||
-rw-r--r-- | video.c | 409 |
4 files changed, 655 insertions, 485 deletions
@@ -8,6 +8,9 @@ LDFLAGS+=-L$(SDKSTAGE)/opt/vc/lib/ -lGLESv2 -lEGL -lopenmaxil -lbcm_host -lvcos INCLUDES+=-I$(SDKSTAGE)/opt/vc/include/ -I$(SDKSTAGE)/opt/vc/include/interface/vcos/pthreads -I$(SDKSTAGE)/opt/vc/include/interface/vmcs_host/linux -I./ +CFLAGS += $(shell pkg-config --cflags glib-2.0) +LDFLAGS += $(shell pkg-config --libs glib-2.0) + all: $(BIN) $(LIB) %.o: %.c @@ -1,6 +1,9 @@ /* Copyright (c) 2012, Broadcom Europe Ltd Copyright (c) 2012, OtherCrashOverride +Copyright (C) 2014, Fluendo S.A. + @author: Josep Torra <josep@fluendo.com> + All rights reserved. Redistribution and use in source and binary forms, with or without @@ -26,7 +29,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// A rotating cube rendered with OpenGL|ES. Three images used as textures on the cube faces. +/* A rotating cube rendered with OpenGL|ES with a video on it */ #include <stdio.h> #include <stdlib.h> @@ -34,6 +37,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <math.h> #include <assert.h> #include <unistd.h> +#include <termios.h> + +#include <glib.h> #include "bcm_host.h" @@ -44,8 +50,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "cube_texture_and_coords.h" #include "triangle.h" -#include <pthread.h> - #define PATH "./" @@ -53,234 +57,268 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define IMAGE_SIZE_HEIGHT 1080 #ifndef M_PI - #define M_PI 3.141592654 +#define M_PI 3.141592654 #endif - typedef struct { - uint32_t screen_width; - uint32_t screen_height; -// OpenGL|ES objects - EGLDisplay display; - EGLSurface surface; - EGLContext context; - GLuint tex; -// model rotation vector and direction - GLfloat rot_angle_x_inc; - GLfloat rot_angle_y_inc; - GLfloat rot_angle_z_inc; -// current model rotation angles - GLfloat rot_angle_x; - GLfloat rot_angle_y; - GLfloat rot_angle_z; -// current distance from camera - GLfloat distance; - GLfloat distance_inc; - - IPC_T ipc; -} CUBE_STATE_T; - -static void init_ogl(CUBE_STATE_T *state); -static void init_model_proj(CUBE_STATE_T *state); -static void reset_model(CUBE_STATE_T *state); -static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc); -static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc); -static void redraw_scene(CUBE_STATE_T *state); -static void update_model(CUBE_STATE_T *state); -static void init_textures(CUBE_STATE_T *state); -static void exit_func(void); + DISPMANX_DISPLAY_HANDLE_T dispman_display; + DISPMANX_ELEMENT_HANDLE_T dispman_element; + + uint32_t screen_width; + uint32_t screen_height; + + gboolean animate; + + /* OpenGL|ES objects */ + EGLDisplay display; + EGLSurface surface; + EGLContext context; + GLuint tex; + /* model rotation vector and direction */ + GLfloat rot_angle_x_inc; + GLfloat rot_angle_y_inc; + GLfloat rot_angle_z_inc; + /* current model rotation angles */ + GLfloat rot_angle_x; + GLfloat rot_angle_y; + GLfloat rot_angle_z; + /* current distance from camera */ + GLfloat distance; + GLfloat distance_inc; + + /* GLib mainloop */ + GMainLoop *main_loop; + /* Rendering thread state */ + gboolean running; + + IPC_T ipc; +} AppState; + +static void init_ogl (AppState * state); +static void init_model_proj (AppState * state); +static void reset_model (AppState * state); +static GLfloat inc_and_wrap_angle (GLfloat angle, GLfloat angle_inc); +static GLfloat inc_and_clip_distance (GLfloat distance, GLfloat distance_inc); +static void redraw_scene (AppState * state); +static void update_model (AppState * state); +static void init_textures (AppState * state); static volatile int terminate; -static CUBE_STATE_T _state, *state=&_state; - -static pthread_t thread1; - +static AppState _state, *state = &_state; /*********************************************************** * Name: init_ogl * * Arguments: - * CUBE_STATE_T *state - holds OGLES model info + * AppState *state - holds OGLES model info * * Description: Sets the display, OpenGL|ES context and screen stuff * * Returns: void * ***********************************************************/ -static void init_ogl(CUBE_STATE_T *state) +static void +init_ogl (AppState * state) { - int32_t success = 0; - EGLBoolean result; - EGLint num_config; - - static EGL_DISPMANX_WINDOW_T nativewindow; - - DISPMANX_ELEMENT_HANDLE_T dispman_element; - DISPMANX_DISPLAY_HANDLE_T dispman_display; - DISPMANX_UPDATE_HANDLE_T dispman_update; - VC_RECT_T dst_rect; - VC_RECT_T src_rect; - - static const EGLint attribute_list[] = - { - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_DEPTH_SIZE, 16, - //EGL_SAMPLES, 4, - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_NONE - }; - - EGLConfig config; - - // get an EGL display connection - state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - assert(state->display!=EGL_NO_DISPLAY); - - // initialize the EGL display connection - result = eglInitialize(state->display, NULL, NULL); - assert(EGL_FALSE != result); - - // get an appropriate EGL frame buffer configuration - // this uses a BRCM extension that gets the closest match, rather than standard which returns anything that matches - result = eglSaneChooseConfigBRCM(state->display, attribute_list, &config, 1, &num_config); - assert(EGL_FALSE != result); - - // create an EGL rendering context - state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, NULL); - assert(state->context!=EGL_NO_CONTEXT); - - // create an EGL window surface - success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height); - assert( success >= 0 ); - - dst_rect.x = 0; - dst_rect.y = 0; - dst_rect.width = state->screen_width; - dst_rect.height = state->screen_height; - - src_rect.x = 0; - src_rect.y = 0; - src_rect.width = state->screen_width << 16; - src_rect.height = state->screen_height << 16; - - dispman_display = vc_dispmanx_display_open( 0 /* LCD */); - dispman_update = vc_dispmanx_update_start( 0 ); - - dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display, - 0/*layer*/, &dst_rect, 0/*src*/, - &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, 0/*transform*/); - - nativewindow.element = dispman_element; - nativewindow.width = state->screen_width; - nativewindow.height = state->screen_height; - vc_dispmanx_update_submit_sync( dispman_update ); - - state->surface = eglCreateWindowSurface( state->display, config, &nativewindow, NULL ); - assert(state->surface != EGL_NO_SURFACE); - - // connect the context to the surface - result = eglMakeCurrent(state->display, state->surface, state->surface, state->context); - assert(EGL_FALSE != result); - - // Set background color and clear buffers - glClearColor(0.15f, 0.25f, 0.35f, 1.0f); - - // Enable back face culling. - glEnable(GL_CULL_FACE); - - glMatrixMode(GL_MODELVIEW); + int32_t success = 0; + EGLBoolean result; + EGLint num_config; + + static EGL_DISPMANX_WINDOW_T nativewindow; + + DISPMANX_UPDATE_HANDLE_T dispman_update; + DISPMANX_MODEINFO_T mode_info; + VC_RECT_T dst_rect; + VC_RECT_T src_rect; + + static const EGLint attribute_list[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 16, + //EGL_SAMPLES, 4, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_NONE + }; + + EGLConfig config; + + /* get an EGL display connection */ + state->display = eglGetDisplay (EGL_DEFAULT_DISPLAY); + assert (state->display != EGL_NO_DISPLAY); + + /* initialize the EGL display connection */ + result = eglInitialize (state->display, NULL, NULL); + assert (EGL_FALSE != result); + + /* get an appropriate EGL frame buffer configuration + * this uses a BRCM extension that gets the closest match, rather + * than standard which returns anything that matches. */ + result = + eglSaneChooseConfigBRCM (state->display, attribute_list, &config, 1, + &num_config); + assert (EGL_FALSE != result); + + /* create an EGL rendering context */ + state->context = + eglCreateContext (state->display, config, EGL_NO_CONTEXT, NULL); + assert (state->context != EGL_NO_CONTEXT); + + /* Open display */ + state->dispman_display = vc_dispmanx_display_open (0 /* LCD */ ); + assert (state->dispman_display); + + /* Get display dimensions */ + success = vc_dispmanx_display_get_info(state->dispman_display, &mode_info); + assert (success >= 0); + state->screen_width = mode_info.width; + state->screen_height = mode_info.height; + + /* create an EGL window surface */ + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.width = state->screen_width; + dst_rect.height = state->screen_height; + + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = state->screen_width << 16; + src_rect.height = state->screen_height << 16; + + dispman_update = vc_dispmanx_update_start (0); + + state->dispman_element = + vc_dispmanx_element_add (dispman_update, state->dispman_display, + 0 /*layer */ , &dst_rect, 0 /*src */ , + &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha */ , 0 /*clamp */ , + 0 /*transform */ ); + + nativewindow.element = state->dispman_element; + nativewindow.width = state->screen_width; + nativewindow.height = state->screen_height; + vc_dispmanx_update_submit_sync (dispman_update); + + state->surface = + eglCreateWindowSurface (state->display, config, &nativewindow, NULL); + assert (state->surface != EGL_NO_SURFACE); + + /* connect the context to the surface */ + result = + eglMakeCurrent (state->display, state->surface, state->surface, + state->context); + assert (EGL_FALSE != result); + + /* Set background color and clear buffers */ + glClearColor (0.15f, 0.25f, 0.35f, 1.0f); + + /* Enable back face culling. */ + glEnable (GL_CULL_FACE); + + glMatrixMode (GL_MODELVIEW); } /*********************************************************** * Name: init_model_proj * * Arguments: - * CUBE_STATE_T *state - holds OGLES model info + * AppState *state - holds OGLES model info * * Description: Sets the OpenGL|ES model to default values * * Returns: void * ***********************************************************/ -static void init_model_proj(CUBE_STATE_T *state) +static void +init_model_proj (AppState * state) { - float nearp = 1.0f; - float farp = 500.0f; - float hht; - float hwd; + float nearp = 1.0f; + float farp = 500.0f; + float hht; + float hwd; + + glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); + glViewport (0, 0, (GLsizei) state->screen_width, + (GLsizei) state->screen_height); - glViewport(0, 0, (GLsizei)state->screen_width, (GLsizei)state->screen_height); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); - hht = nearp * (float)tan(45.0 / 2.0 / 180.0 * M_PI); - hwd = hht * (float)state->screen_width / (float)state->screen_height; + hht = nearp * (float) tan (45.0 / 2.0 / 180.0 * M_PI); + hwd = hht * (float) state->screen_width / (float) state->screen_height; - glFrustumf(-hwd, hwd, -hht, hht, nearp, farp); - - glEnableClientState( GL_VERTEX_ARRAY ); - glVertexPointer( 3, GL_BYTE, 0, quadx ); + glFrustumf (-hwd, hwd, -hht, hht, nearp, farp); - reset_model(state); + glEnableClientState (GL_VERTEX_ARRAY); + glVertexPointer (3, GL_BYTE, 0, quadx); + + reset_model (state); } /*********************************************************** * Name: reset_model * * Arguments: - * CUBE_STATE_T *state - holds OGLES model info + * AppState *state - holds OGLES model info * * Description: Resets the Model projection and rotation direction * * Returns: void * ***********************************************************/ -static void reset_model(CUBE_STATE_T *state) +static void +reset_model (AppState * state) { - // reset model position - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.f, 0.f, -50.f); - - // reset model rotation - state->rot_angle_x = 45.f; state->rot_angle_y = 30.f; state->rot_angle_z = 0.f; - state->rot_angle_x_inc = 0.5f; state->rot_angle_y_inc = 0.5f; state->rot_angle_z_inc = 0.f; - state->distance = 40.f; + /* reset model position */ + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + glTranslatef (0.f, 0.f, -50.f); + + /* reset model rotation */ + state->rot_angle_x = 45.f; + state->rot_angle_y = 30.f; + state->rot_angle_z = 0.f; + state->rot_angle_x_inc = 0.5f; + state->rot_angle_y_inc = 0.5f; + state->rot_angle_z_inc = 0.f; + state->distance = 40.f; } /*********************************************************** * Name: update_model * * Arguments: - * CUBE_STATE_T *state - holds OGLES model info + * AppState *state - holds OGLES model info * * Description: Updates model projection to current position/rotation * * Returns: void * ***********************************************************/ -static void update_model(CUBE_STATE_T *state) +static void +update_model (AppState * state) { - // update position - state->rot_angle_x = inc_and_wrap_angle(state->rot_angle_x, state->rot_angle_x_inc); - state->rot_angle_y = inc_and_wrap_angle(state->rot_angle_y, state->rot_angle_y_inc); - state->rot_angle_z = inc_and_wrap_angle(state->rot_angle_z, state->rot_angle_z_inc); - state->distance = inc_and_clip_distance(state->distance, state->distance_inc); - - glLoadIdentity(); - // move camera back to see the cube - glTranslatef(0.f, 0.f, -state->distance); - - // Rotate model to new position - glRotatef(state->rot_angle_x, 1.f, 0.f, 0.f); - glRotatef(state->rot_angle_y, 0.f, 1.f, 0.f); - glRotatef(state->rot_angle_z, 0.f, 0.f, 1.f); + if (state->animate) { + /* update position */ + state->rot_angle_x = + inc_and_wrap_angle (state->rot_angle_x, state->rot_angle_x_inc); + state->rot_angle_y = + inc_and_wrap_angle (state->rot_angle_y, state->rot_angle_y_inc); + state->rot_angle_z = + inc_and_wrap_angle (state->rot_angle_z, state->rot_angle_z_inc); + state->distance = + inc_and_clip_distance (state->distance, state->distance_inc); + } + + glLoadIdentity (); + /* move camera back to see the cube */ + glTranslatef (0.f, 0.f, -state->distance); + + /* Rotate model to new position */ + glRotatef (state->rot_angle_x, 1.f, 0.f, 0.f); + glRotatef (state->rot_angle_y, 0.f, 1.f, 0.f); + glRotatef (state->rot_angle_z, 0.f, 0.f, 1.f); } /*********************************************************** @@ -296,16 +334,17 @@ static void update_model(CUBE_STATE_T *state) * Returns: new value of angle * ***********************************************************/ -static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc) +static GLfloat +inc_and_wrap_angle (GLfloat angle, GLfloat angle_inc) { - angle += angle_inc; + angle += angle_inc; - if (angle >= 360.0) - angle -= 360.f; - else if (angle <=0) - angle += 360.f; + if (angle >= 360.0) + angle -= 360.f; + else if (angle <= 0) + angle += 360.f; - return angle; + return angle; } /*********************************************************** @@ -321,23 +360,24 @@ static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc) * Returns: new value of angle * ***********************************************************/ -static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc) +static GLfloat +inc_and_clip_distance (GLfloat distance, GLfloat distance_inc) { - distance += distance_inc; + distance += distance_inc; - if (distance >= 120.0f) - distance = 120.f; - else if (distance <= 40.0f) - distance = 40.0f; + if (distance >= 120.0f) + distance = 120.f; + else if (distance <= 40.0f) + distance = 40.0f; - return distance; + return distance; } /*********************************************************** * Name: redraw_scene * * Arguments: - * CUBE_STATE_T *state - holds OGLES model info + * AppState *state - holds OGLES model info * * Description: Draws the model and calls eglSwapBuffers * to render to screen @@ -345,41 +385,42 @@ static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc) * Returns: void * ***********************************************************/ -static void redraw_scene(CUBE_STATE_T *state) +static void +redraw_scene (AppState * state) { - // Start with a clear screen - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + /* Start with a clear screen */ + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // Need to rotate textures - do this by rotating each cube face - glRotatef(270.f, 0.f, 0.f, 1.f ); // front face normal along z axis + /* Need to rotate textures - do this by rotating each cube face */ + glRotatef (270.f, 0.f, 0.f, 1.f); /* front face normal along z axis */ - // draw first 4 vertices - glDrawArrays( GL_TRIANGLE_STRIP, 0, 4); + /* draw first 4 vertices */ + glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); - // same pattern for other 5 faces - rotation chosen to make image orientation 'nice' - glRotatef(90.f, 0.f, 0.f, 1.f ); // back face normal along z axis - glDrawArrays( GL_TRIANGLE_STRIP, 4, 4); + /* same pattern for other 5 faces - rotation chosen to make image orientation 'nice' */ + glRotatef (90.f, 0.f, 0.f, 1.f); /* back face normal along z axis */ + glDrawArrays (GL_TRIANGLE_STRIP, 4, 4); - glRotatef(90.f, 1.f, 0.f, 0.f ); // left face normal along x axis - glDrawArrays( GL_TRIANGLE_STRIP, 8, 4); + glRotatef (90.f, 1.f, 0.f, 0.f); /* left face normal along x axis */ + glDrawArrays (GL_TRIANGLE_STRIP, 8, 4); - glRotatef(90.f, 1.f, 0.f, 0.f ); // right face normal along x axis - glDrawArrays( GL_TRIANGLE_STRIP, 12, 4); + glRotatef (90.f, 1.f, 0.f, 0.f); /* right face normal along x axis */ + glDrawArrays (GL_TRIANGLE_STRIP, 12, 4); - glRotatef(270.f, 0.f, 1.f, 0.f ); // top face normal along y axis - glDrawArrays( GL_TRIANGLE_STRIP, 16, 4); + glRotatef (270.f, 0.f, 1.f, 0.f); /* top face normal along y axis */ + glDrawArrays (GL_TRIANGLE_STRIP, 16, 4); - glRotatef(90.f, 0.f, 1.f, 0.f ); // bottom face normal along y axis - glDrawArrays( GL_TRIANGLE_STRIP, 20, 4); + glRotatef (90.f, 0.f, 1.f, 0.f); /* bottom face normal along y axis */ + glDrawArrays (GL_TRIANGLE_STRIP, 20, 4); - eglSwapBuffers(state->display, state->surface); + eglSwapBuffers (state->display, state->surface); } /*********************************************************** * Name: init_textures * * Arguments: - * CUBE_STATE_T *state - holds OGLES model info + * AppState *state - holds OGLES model info * * Description: Initialise OGL|ES texture surfaces to use image * buffers @@ -387,96 +428,210 @@ static void redraw_scene(CUBE_STATE_T *state) * Returns: void * ***********************************************************/ -static void init_textures(CUBE_STATE_T *state) +static void +init_textures (AppState * state) { - //// load three texture buffers but use them on six OGL|ES texture surfaces - glGenTextures(1, &state->tex); - - glBindTexture(GL_TEXTURE_2D, state->tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - - /* Create EGL Image */ - state->ipc.eglImage = eglCreateImageKHR( - state->display, - state->context, - EGL_GL_TEXTURE_2D_KHR, - (EGLClientBuffer)state->tex, - 0); - - if (state->ipc.eglImage == EGL_NO_IMAGE_KHR) - { - printf("eglCreateImageKHR failed.\n"); - exit(1); - } - - // Start rendering - pthread_create(&thread1, NULL, video_decode_test, &state->ipc); - - // setup overall texture environment - glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - glEnable(GL_TEXTURE_2D); - - // Bind texture surface to current vertices - glBindTexture(GL_TEXTURE_2D, state->tex); + glGenTextures (1, &state->tex); + + glBindTexture (GL_TEXTURE_2D, state->tex); + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT, + 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + +#if 0 + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +#else + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#endif + + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + + /* Create EGL Image */ + state->ipc.eglImage = eglCreateImageKHR (state->display, + state->context, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer) state->tex, 0); + + if (state->ipc.eglImage == EGL_NO_IMAGE_KHR) { + g_print ("eglCreateImageKHR failed.\n"); + exit (1); + } + + /* setup overall texture environment */ + glTexCoordPointer (2, GL_FLOAT, 0, texCoords); + glEnableClientState (GL_TEXTURE_COORD_ARRAY); + + glEnable (GL_TEXTURE_2D); + + /* Bind texture surface to current vertices */ + glBindTexture (GL_TEXTURE_2D, state->tex); } + //------------------------------------------------------------------------------ -static void exit_func(void) -// Function to be passed to atexit(). +static void +close_ogl (void) { - if (state->ipc.eglImage != 0) - { - if (!eglDestroyImageKHR(state->display, (EGLImageKHR) state->ipc.eglImage)) - printf("eglDestroyImageKHR failed."); - } + DISPMANX_UPDATE_HANDLE_T dispman_update; + + if (state->ipc.eglImage != 0) { + if (!eglDestroyImageKHR (state->display, (EGLImageKHR) state->ipc.eglImage)) + g_print ("eglDestroyImageKHR failed."); + } + + /* clear screen */ + glClear (GL_COLOR_BUFFER_BIT); + eglSwapBuffers (state->display, state->surface); + + /* Release OpenGL resources */ + eglMakeCurrent (state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + eglDestroySurface (state->display, state->surface); + eglDestroyContext (state->display, state->context); + eglTerminate (state->display); + + dispman_update = vc_dispmanx_update_start (0); + vc_dispmanx_element_remove (dispman_update, state->dispman_element); + vc_dispmanx_update_submit_sync (dispman_update); + vc_dispmanx_display_close (state->dispman_display); +} - // clear screen - glClear( GL_COLOR_BUFFER_BIT ); - eglSwapBuffers(state->display, state->surface); +//============================================================================== - // Release OpenGL resources - eglMakeCurrent( state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); - eglDestroySurface( state->display, state->surface ); - eglDestroyContext( state->display, state->context ); - eglTerminate( state->display ); +static void +open_ogl (void) +{ - printf("\ncube closed\n"); -} // exit_func() + bcm_host_init (); -//============================================================================== + /* Start OpenGLES */ + init_ogl (state); -int main () + /* Setup the model world */ + init_model_proj (state); + + /* initialize the OGLES texture(s) */ + init_textures (state); +} + +static gpointer +render_func (gpointer data) { - bcm_host_init(); - printf("Note: ensure you have sufficient gpu_mem configured\n"); - - // Clear application state - memset( state, 0, sizeof( *state ) ); - - // Start OGLES - init_ogl(state); - - // Setup the model world - init_model_proj(state); - - // initialise the OGLES texture(s) - init_textures(state); - - while (!terminate) - { - update_model(state); - redraw_scene(state); - } - exit_func(); - return 0; + open_ogl (); + state->running = TRUE; + + do { + update_model (state); + redraw_scene (state); + + g_usleep (0); + } while (state->running == TRUE); + + close_ogl (); + return NULL; } +/* Process keyboard input */ +static gboolean +handle_keyboard (GIOChannel * source, GIOCondition cond, AppState * state) +{ + gsize bytesread; + gchar op; + + if (g_io_channel_read_chars (source, &op, 1, &bytesread, + NULL) == G_IO_STATUS_NORMAL) { + switch (op) { + case 'a': + if (state->animate) { + state->animate = FALSE; + g_print ("Animation disabled\n"); + } else { + state->animate = TRUE; + g_print ("Animation enabled\n"); + } + break; + case 'q': + video_decode_stop (); + g_main_loop_quit (state->main_loop); + break; + default: + /* g_print ("%02x ", op); */ + break; + } + } + return TRUE; +} + +int +main () +{ + GThread *rthread = NULL, *mthread = NULL; + GIOChannel *io_stdin; + struct termios cooked, raw; + + /* must initialise the threading system before using any other GLib funtion */ + if (!g_thread_supported ()) + g_thread_init (NULL); + + /* Clear application state */ + memset (state, 0, sizeof (*state)); + state->animate = TRUE; + + /* Create a GLib Main Loop and set it to run */ + state->main_loop = g_main_loop_new (NULL, FALSE); + + /* Get the state of the tty */ + tcgetattr (0, &cooked); + /* Make a copy we can mess with */ + memcpy (&raw, &cooked, sizeof (struct termios)); + /* Turn off linebuffering, and special-character processing, + * but not the SIGINT or SIGQUIT keys. */ + raw.c_lflag &= ~(ICANON | ECHO); + /* Ship the raw control blts */ + tcsetattr (0, TCSANOW, &raw); + /* Add a keyboard watch so we get notified of keystrokes */ + io_stdin = g_io_channel_unix_new (fileno (stdin)); + g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc) handle_keyboard, state); + g_io_channel_unref (io_stdin); + + /* *INDENT-OFF* */ + g_print ("Available commands: \n" + " a - Toggle animation \n" + " q - Quit \n"); + /* *INDENT-ON* */ + + if (!(rthread = g_thread_new ("render", (GThreadFunc) render_func, NULL))) { + g_print ("Render thread creation failed\n"); + goto done; + } + + g_usleep(50000); + if (!(mthread = g_thread_new ("media", (GThreadFunc) video_decode_test, &state->ipc))) { + g_print ("Media thread creation failed\n"); + goto done; + } + + /* Start the mainloop */ + g_main_loop_run (state->main_loop); + +done: + + /* Unref the mainloop */ + if (state->main_loop) { + g_main_loop_unref (state->main_loop); + } + + /* Stop media thread */ + if (mthread) + g_thread_join (mthread); + + /* Stop rendering thread */ + state->running = FALSE; + if (rthread) + g_thread_join (rthread); + + tcsetattr (0, TCSANOW, &cooked); + g_print ("test finished\n"); + return 0; +} @@ -31,4 +31,5 @@ typedef struct void* eglImage; } IPC_T; -void* video_decode_test(void* arg); +void* video_decode_test (void* arg); +void video_decode_stop (); @@ -1,6 +1,8 @@ /* Copyright (c) 2012, Broadcom Europe Ltd Copyright (c) 2012, OtherCrashOverride +Copyright (C) 2014, Fluendo S.A. + @author: Josep Torra <josep@fluendo.com> All rights reserved. Redistribution and use in source and binary forms, with or without @@ -26,232 +28,241 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Video decode demo using OpenMAX IL though the ilcient helper library +/* Video decode demo using OpenMAX IL though the ilcient helper library */ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <glib.h> + #include "bcm_host.h" #include "ilclient.h" #include "triangle.h" -static OMX_BUFFERHEADERTYPE* eglBuffer = NULL; -static COMPONENT_T* egl_render = NULL; +static OMX_BUFFERHEADERTYPE *eglBuffer = NULL; +static COMPONENT_T *egl_render = NULL; -static void* eglImage = 0; +static void *eglImage = 0; +static gboolean running = FALSE; -void my_fill_buffer_done(void* data, COMPONENT_T* comp) +void +my_fill_buffer_done (void *data, COMPONENT_T * comp) { - if (OMX_FillThisBuffer(ilclient_get_handle(egl_render), eglBuffer) != OMX_ErrorNone) - { - printf("WARNING: OMX_FillThisBuffer failed in callback\n"); - //exit(1); - } + if (OMX_FillThisBuffer (ilclient_get_handle (egl_render), + eglBuffer) != OMX_ErrorNone) { + g_print ("WARNING: OMX_FillThisBuffer failed in callback\n"); + } } - -// Modified function prototype to work with pthreads -void *video_decode_test(void* arg) +void * +video_decode_test (void *arg) { - const char* filename = "/opt/vc/src/hello_pi/hello_video/test.h264"; - IPC_T * ipc = (IPC_T *) arg; - eglImage = ipc->eglImage; - - if (eglImage == 0) - { - printf("eglImage is null.\n"); - exit(1); - } - - OMX_VIDEO_PARAM_PORTFORMATTYPE format; - COMPONENT_T *video_decode = NULL; - COMPONENT_T *list[5]; - TUNNEL_T tunnel[4]; - ILCLIENT_T *client; - FILE *in; - int status = 0; - unsigned int data_len = 0; - - memset(list, 0, sizeof(list)); - memset(tunnel, 0, sizeof(tunnel)); - - if((in = fopen(filename, "rb")) == NULL) - return (void *)-2; - - if((client = ilclient_init()) == NULL) - { - fclose(in); - return (void *)-3; - } - - if(OMX_Init() != OMX_ErrorNone) - { - ilclient_destroy(client); - fclose(in); - return (void *)-4; - } - - // callback - ilclient_set_fill_buffer_done_callback(client, my_fill_buffer_done, 0); - - // create video_decode - if(ilclient_create_component(client, &video_decode, "video_decode", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0) - status = -14; - list[0] = video_decode; - - // create egl_render - if(status == 0 && ilclient_create_component(client, &egl_render, "egl_render", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_OUTPUT_BUFFERS) != 0) - status = -14; - list[1] = egl_render; - - - set_tunnel(tunnel, video_decode, 131, egl_render, 220); - - if(status == 0) - ilclient_change_component_state(video_decode, OMX_StateIdle); - - memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE)); - format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE); - format.nVersion.nVersion = OMX_VERSION; - format.nPortIndex = 130; - format.eCompressionFormat = OMX_VIDEO_CodingAVC; - - if(status == 0 && - OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamVideoPortFormat, &format) == OMX_ErrorNone && - ilclient_enable_port_buffers(video_decode, 130, NULL, NULL, NULL) == 0) - { - OMX_BUFFERHEADERTYPE *buf; - int port_settings_changed = 0; - int first_packet = 1; - - ilclient_change_component_state(video_decode, OMX_StateExecuting); - - while((buf = ilclient_get_input_buffer(video_decode, 130, 1)) != NULL) - { - // feed data and wait until we get port settings changed - unsigned char *dest = buf->pBuffer; - - // loop if at end - if (feof(in)) { - printf ("EOS\n"); - break; // rewind(in); - } - data_len += fread(dest, 1, buf->nAllocLen-data_len, in); - - if(port_settings_changed == 0 && - ((data_len > 0 && ilclient_remove_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) || - (data_len == 0 && ilclient_wait_for_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1, - ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0))) - { - port_settings_changed = 1; - - { + const char *filename = "/opt/vc/src/hello_pi/hello_video/test.h264"; + IPC_T *ipc = (IPC_T *) arg; + eglImage = ipc->eglImage; + + running = TRUE; + + if (eglImage == 0) { + g_print ("eglImage is null.\n"); + exit (1); + } + + OMX_VIDEO_PARAM_PORTFORMATTYPE format; + COMPONENT_T *video_decode = NULL; + COMPONENT_T *list[5]; + TUNNEL_T tunnel[4]; + ILCLIENT_T *client; + FILE *in; + int status = 0; + unsigned int data_len = 0; + + memset (list, 0, sizeof (list)); + memset (tunnel, 0, sizeof (tunnel)); + + if ((in = fopen (filename, "rb")) == NULL) + return (void *) -2; + + if ((client = ilclient_init ()) == NULL) { + fclose (in); + return (void *) -3; + } + + if (OMX_Init () != OMX_ErrorNone) { + ilclient_destroy (client); + fclose (in); + return (void *) -4; + } + /* callback */ + ilclient_set_fill_buffer_done_callback (client, my_fill_buffer_done, 0); + + /* create video_decode */ + if (ilclient_create_component (client, &video_decode, "video_decode", + ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0) + status = -14; + list[0] = video_decode; + + /* create egl_render */ + if (status == 0 + && ilclient_create_component (client, &egl_render, "egl_render", + ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_OUTPUT_BUFFERS) != 0) + status = -14; + list[1] = egl_render; + + + set_tunnel (tunnel, video_decode, 131, egl_render, 220); + + if (status == 0) + ilclient_change_component_state (video_decode, OMX_StateIdle); + + memset (&format, 0, sizeof (OMX_VIDEO_PARAM_PORTFORMATTYPE)); + format.nSize = sizeof (OMX_VIDEO_PARAM_PORTFORMATTYPE); + format.nVersion.nVersion = OMX_VERSION; + format.nPortIndex = 130; + format.eCompressionFormat = OMX_VIDEO_CodingAVC; + + if (status == 0 && + OMX_SetParameter (ILC_GET_HANDLE (video_decode), + OMX_IndexParamVideoPortFormat, &format) == OMX_ErrorNone + && ilclient_enable_port_buffers (video_decode, 130, NULL, NULL, + NULL) == 0) { + OMX_BUFFERHEADERTYPE *buf; + int port_settings_changed = 0; + int first_packet = 1; + + ilclient_change_component_state (video_decode, OMX_StateExecuting); + + while ((buf = ilclient_get_input_buffer (video_decode, 130, 1)) != NULL) { + /* feed data and wait until we get port settings changed */ + unsigned char *dest = buf->pBuffer; + + /* loop if at end */ + if (feof (in) || !running) { + g_print ("EOS\n"); + break; + } + data_len += fread (dest, 1, buf->nAllocLen - data_len, in); + + if (port_settings_changed == 0 && + ((data_len > 0 + && ilclient_remove_event (video_decode, + OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) + || (data_len == 0 + && ilclient_wait_for_event (video_decode, + OMX_EventPortSettingsChanged, 131, 0, 0, 1, + ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, + 10000) == 0))) { + port_settings_changed = 1; + + { #define OMX_IndexParamBrcmVideoEGLRenderDiscardMode 0x7f0000db - OMX_CONFIG_PORTBOOLEANTYPE discardMode; - memset (&discardMode, 0, sizeof (discardMode)); - discardMode.nSize = sizeof (discardMode); - discardMode.nPortIndex = 220; - discardMode.nVersion.nVersion = OMX_VERSION; - discardMode.bEnabled = OMX_FALSE; - if (OMX_SetParameter(ILC_GET_HANDLE(egl_render), OMX_IndexParamBrcmVideoEGLRenderDiscardMode, &discardMode) != OMX_ErrorNone) { - status = -7; - break; - } -#undef OMX_IndexParamBrcmVideoEGLRenderDiscardMode - } - - if(ilclient_setup_tunnel(tunnel, 0, 0) != 0) - { - status = -7; - break; - } - - // Set egl_render to idle - ilclient_change_component_state(egl_render, OMX_StateIdle); - - // Enable the output port and tell egl_render to use the texture as a buffer - //ilclient_enable_port(egl_render, 221); THIS BLOCKS SO CANT BE USED - if (OMX_SendCommand(ILC_GET_HANDLE(egl_render), OMX_CommandPortEnable, 221, NULL) != OMX_ErrorNone) - { - printf("OMX_CommandPortEnable failed.\n"); - exit(1); - } - - if (OMX_UseEGLImage(ILC_GET_HANDLE(egl_render), &eglBuffer, 221, NULL, eglImage) != OMX_ErrorNone) - { - printf("OMX_UseEGLImage failed.\n"); - exit(1); - } - - // Set egl_render to executing - ilclient_change_component_state(egl_render, OMX_StateExecuting); - - - // Request egl_render to write data to the texture buffer - if(OMX_FillThisBuffer(ILC_GET_HANDLE(egl_render), eglBuffer) != OMX_ErrorNone) - { - printf("OMX_FillThisBuffer failed.\n"); - exit(1); - } - } - if(!data_len) - break; - - buf->nFilledLen = data_len; - data_len = 0; - - buf->nOffset = 0; - if(first_packet) - { - buf->nFlags = OMX_BUFFERFLAG_STARTTIME; - first_packet = 0; - } - else - buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN; - - if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone) - { - status = -6; + OMX_CONFIG_PORTBOOLEANTYPE discardMode; + memset (&discardMode, 0, sizeof (discardMode)); + discardMode.nSize = sizeof (discardMode); + discardMode.nPortIndex = 220; + discardMode.nVersion.nVersion = OMX_VERSION; + discardMode.bEnabled = OMX_FALSE; + if (OMX_SetParameter (ILC_GET_HANDLE (egl_render), + OMX_IndexParamBrcmVideoEGLRenderDiscardMode, + &discardMode) != OMX_ErrorNone) { + status = -7; break; - } + } +#undef OMX_IndexParamBrcmVideoEGLRenderDiscardMode + } + + if (ilclient_setup_tunnel (tunnel, 0, 0) != 0) { + status = -7; + break; + } + /* Set egl_render to idle */ + ilclient_change_component_state (egl_render, OMX_StateIdle); + + /* Enable the output port and tell egl_render to use the texture as a buffer + * ilclient_enable_port(egl_render, 221); THIS BLOCKS SO CANT BE USED */ + if (OMX_SendCommand (ILC_GET_HANDLE (egl_render), OMX_CommandPortEnable, + 221, NULL) != OMX_ErrorNone) { + g_print ("OMX_CommandPortEnable failed.\n"); + exit (1); + } + + if (OMX_UseEGLImage (ILC_GET_HANDLE (egl_render), &eglBuffer, 221, NULL, + eglImage) != OMX_ErrorNone) { + g_print ("OMX_UseEGLImage failed.\n"); + exit (1); + } + /* Set egl_render to executing */ + ilclient_change_component_state (egl_render, OMX_StateExecuting); + + + /* Request egl_render to write data to the texture buffer */ + if (OMX_FillThisBuffer (ILC_GET_HANDLE (egl_render), + eglBuffer) != OMX_ErrorNone) { + g_print ("OMX_FillThisBuffer failed.\n"); + exit (1); + } + } + if (!data_len) + break; + + buf->nFilledLen = data_len; + data_len = 0; + + buf->nOffset = 0; + if (first_packet) { + buf->nFlags = OMX_BUFFERFLAG_STARTTIME; + first_packet = 0; + } else + buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN; + + if (OMX_EmptyThisBuffer (ILC_GET_HANDLE (video_decode), + buf) != OMX_ErrorNone) { + status = -6; + break; } + } - printf ("Sending EOS buffer\n"); - buf->nFilledLen = 0; - buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS; + g_print ("Sending EOS buffer\n"); + buf->nFilledLen = 0; + buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS; - if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone) - status = -20; + if (OMX_EmptyThisBuffer (ILC_GET_HANDLE (video_decode), + buf) != OMX_ErrorNone) + status = -20; - printf ("Pause media processing pipeline\n"); - ilclient_state_transition(list, OMX_StatePause); - printf ("Flushing tunnel\n"); - // need to flush the renderer to allow video_decode to disable its input port - ilclient_flush_tunnels(tunnel, 0); - printf ("Disable video decoder input port\n"); - ilclient_disable_port_buffers(video_decode, 130, NULL, NULL, NULL); - } + g_print ("Pause media processing pipeline\n"); + ilclient_state_transition (list, OMX_StatePause); + g_print ("Flushing tunnel\n"); + /* need to flush the renderer to allow video_decode to disable its input port */ + ilclient_flush_tunnels (tunnel, 0); + g_print ("Disable video decoder input port\n"); + ilclient_disable_port_buffers (video_decode, 130, NULL, NULL, NULL); + } - fclose(in); + fclose (in); - printf ("change media processing pipeline to idle state\n"); - ilclient_state_transition(list, OMX_StateIdle); + g_print ("change media processing pipeline to idle state\n"); + ilclient_state_transition (list, OMX_StateIdle); - printf ("Disable tunnels\n"); - ilclient_disable_tunnel(tunnel); - ilclient_teardown_tunnels(tunnel); + g_print ("Disable tunnels\n"); + ilclient_disable_tunnel (tunnel); + ilclient_teardown_tunnels (tunnel); - printf ("release components\n"); - ilclient_cleanup_components(list); + g_print ("release components\n"); + ilclient_cleanup_components (list); - printf ("deinit OpenMAX\n"); - OMX_Deinit(); + g_print ("deinit OpenMAX\n"); + OMX_Deinit (); - printf ("destroy IL client\n"); - ilclient_destroy(client); - exit(1); - return (void *)status; + g_print ("destroy IL client\n"); + ilclient_destroy (client); + return (void *) status; } +void +video_decode_stop () +{ + running = FALSE; +} |