RaspiStill example code for YUV fast paths

Update RaspiStill framework to provide access to the new EGL image
targets that provide a fastpath for mapping the individual YUV planes to
one byte per pixel GL_LUMINANCE buffers. These are still accessed as OES
textures so this is effectively a greyscale image created from a single
plane of a MMAL buffer.

Also added some example code (yuv, sobel) that demonstrates how to use
the new EGL image targets.

Also, add -gc to the command line to capture the GL frame-buffer as a TGA file.

Thanks to Tim Gover
This commit is contained in:
Dom Cobley
2013-11-28 22:22:10 +00:00
parent 40f174657f
commit d2c9f912da
28 changed files with 1442 additions and 350 deletions

View File

@@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 2.8)
project(vmcs_host_apps) project(vmcs_host_apps)
set(BUILD_MMAL TRUE) set(BUILD_MMAL TRUE)
set(BUILD_MMAL_COMPONENTS FALSE)
if (ALL_APPS) if (ALL_APPS)
set(BUILD_MMAL_APPS TRUE) set(BUILD_MMAL_APPS TRUE)
else() else()
@@ -70,6 +69,11 @@ if(BUILD_MMAL_APPS)
add_subdirectory(containers) add_subdirectory(containers)
endif() endif()
# VidTex supports Android and Linux
if(BUILD_MMAL_COMPONENTS)
add_subdirectory(host_applications/android/apps/vidtex)
endif(BUILD_MMAL_COMPONENTS)
add_subdirectory(middleware/openmaxil) add_subdirectory(middleware/openmaxil)
# 3d demo code # 3d demo code

View File

@@ -246,6 +246,8 @@ extern "C" {
case VC_IMAGE_TF_PAL4: \ case VC_IMAGE_TF_PAL4: \
case VC_IMAGE_TF_ETC1: \ case VC_IMAGE_TF_ETC1: \
case VC_IMAGE_TF_Y8: \ case VC_IMAGE_TF_Y8: \
case VC_IMAGE_TF_U8: \
case VC_IMAGE_TF_V8: \
case VC_IMAGE_TF_A8: \ case VC_IMAGE_TF_A8: \
case VC_IMAGE_TF_SHORT: \ case VC_IMAGE_TF_SHORT: \
case VC_IMAGE_TF_1BPP case VC_IMAGE_TF_1BPP

View File

@@ -4,13 +4,29 @@
SET(COMPILE_DEFINITIONS -Werror) SET(COMPILE_DEFINITIONS -Werror)
include_directories(${CMAKE_SOURCE_DIR}/host_applications/linux/libs/bcm_host/include) include_directories(${CMAKE_SOURCE_DIR}/host_applications/linux/libs/bcm_host/include)
include_directories(${CMAKE_SOURCE_DIR}/host_applications/linux/apps/raspicam/)
add_executable(raspistill RaspiCamControl.c RaspiCLI.c RaspiPreview.c RaspiStill.c RaspiTex.c RaspiTexUtil.c teapot.c models.c square.c mirror.c) set (GL_SCENE_SOURCES
add_executable(raspiyuv RaspiCamControl.c RaspiCLI.c RaspiPreview.c RaspiStillYUV.c) gl_scenes/models.c
add_executable(raspivid RaspiCamControl.c RaspiCLI.c RaspiPreview.c RaspiVid.c) gl_scenes/mirror.c
gl_scenes/yuv.c
gl_scenes/sobel.c
gl_scenes/square.c
gl_scenes/teapot.c)
target_link_libraries(raspistill mmal_core mmal_util mmal_vc_client vcos bcm_host GLESv2 EGL m) set (COMMON_SOURCES
target_link_libraries(raspiyuv mmal_core mmal_util mmal_vc_client vcos bcm_host) RaspiCamControl.c
target_link_libraries(raspivid mmal_core mmal_util mmal_vc_client vcos bcm_host) RaspiCLI.c
RaspiPreview.c)
add_executable(raspistill ${COMMON_SOURCES} RaspiStill.c RaspiTex.c RaspiTexUtil.c tga.c ${GL_SCENE_SOURCES})
add_executable(raspiyuv ${COMMON_SOURCES} RaspiStillYUV.c)
add_executable(raspivid ${COMMON_SOURCES} RaspiVid.c)
set (MMAL_LIBS mmal_core mmal_util mmal_vc_client)
target_link_libraries(raspistill ${MMAL_LIBS} vcos bcm_host GLESv2 EGL m)
target_link_libraries(raspiyuv ${MMAL_LIBS} vcos bcm_host)
target_link_libraries(raspivid ${MMAL_LIBS} vcos bcm_host)
install(TARGETS raspistill raspiyuv raspivid RUNTIME DESTINATION bin) install(TARGETS raspistill raspiyuv raspivid RUNTIME DESTINATION bin)

View File

@@ -134,6 +134,7 @@ typedef struct
int fullResPreview; /// If set, the camera preview port runs at capture resolution. Reduces fps. int fullResPreview; /// If set, the camera preview port runs at capture resolution. Reduces fps.
int frameNextMethod; /// Which method to use to advance to next frame int frameNextMethod; /// Which method to use to advance to next frame
int useGL; /// Render preview using OpenGL int useGL; /// Render preview using OpenGL
int glCapture; /// Save the GL frame-buffer instead of camera output
RASPIPREVIEW_PARAMETERS preview_parameters; /// Preview setup parameters RASPIPREVIEW_PARAMETERS preview_parameters; /// Preview setup parameters
RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters
@@ -181,6 +182,7 @@ static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag);
#define CommandKeypress 15 #define CommandKeypress 15
#define CommandSignal 16 #define CommandSignal 16
#define CommandGL 17 #define CommandGL 17
#define CommandGLCapture 18
static COMMAND_LIST cmdline_commands[] = static COMMAND_LIST cmdline_commands[] =
{ {
@@ -202,6 +204,7 @@ static COMMAND_LIST cmdline_commands[] =
{ CommandKeypress,"-keypress", "k", "Wait between captures for a ENTER, X then ENTER to exit", 0}, { CommandKeypress,"-keypress", "k", "Wait between captures for a ENTER, X then ENTER to exit", 0},
{ CommandSignal, "-signal", "s", "Wait between captures for a SIGUSR1 from another process", 0}, { CommandSignal, "-signal", "s", "Wait between captures for a SIGUSR1 from another process", 0},
{ CommandGL, "-gl", "g", "Draw preview to texture instead of using video render component", 0}, { CommandGL, "-gl", "g", "Draw preview to texture instead of using video render component", 0},
{ CommandGLCapture, "-glcapture","gc", "Capture the GL frame-buffer instead of the camera image", 0},
}; };
static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]); static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
@@ -276,6 +279,7 @@ static void default_status(RASPISTILL_STATE *state)
state->fullResPreview = 0; state->fullResPreview = 0;
state->frameNextMethod = FRAME_NEXT_SINGLE; state->frameNextMethod = FRAME_NEXT_SINGLE;
state->useGL = 0; state->useGL = 0;
state->glCapture = 0;
// Setup preview window defaults // Setup preview window defaults
raspipreview_set_defaults(&state->preview_parameters); raspipreview_set_defaults(&state->preview_parameters);
@@ -584,6 +588,10 @@ static int parse_cmdline(int argc, const char **argv, RASPISTILL_STATE *state)
state->useGL = 1; state->useGL = 1;
break; break;
case CommandGLCapture:
state->glCapture = 1;
break;
default: default:
{ {
// Try parsing for any image specific parameters // Try parsing for any image specific parameters
@@ -619,8 +627,14 @@ static int parse_cmdline(int argc, const char **argv, RASPISTILL_STATE *state)
state->raspitex_state.width = state->preview_parameters.previewWindow.width; state->raspitex_state.width = state->preview_parameters.previewWindow.width;
state->raspitex_state.height = state->preview_parameters.previewWindow.height; state->raspitex_state.height = state->preview_parameters.previewWindow.height;
} }
state->raspitex_state.opacity = state->preview_parameters.opacity; /* Also pass the preview information through so GL renderer can determine
state->raspitex_state.verbose = state->verbose; * the real resolution of the multi-media image */
state->raspitex_state.preview_x = state->preview_parameters.previewWindow.x;
state->raspitex_state.preview_y = state->preview_parameters.previewWindow.y;
state->raspitex_state.preview_width = state->preview_parameters.previewWindow.width;
state->raspitex_state.preview_height = state->preview_parameters.previewWindow.height;
state->raspitex_state.opacity = state->preview_parameters.opacity;
state->raspitex_state.verbose = state->verbose;
if (!valid) if (!valid)
{ {
@@ -1449,7 +1463,37 @@ static int wait_for_next_frame(RASPISTILL_STATE *state, int *frame)
return keep_running; return keep_running;
} }
static void rename_file(RASPISTILL_STATE *state, FILE *output_file,
const char *final_filename, const char *use_filename, int frame)
{
MMAL_STATUS_T status;
fclose(output_file);
vcos_assert(use_filename != NULL && final_filename != NULL);
if (0 != rename(use_filename, final_filename))
{
vcos_log_error("Could not rename temp file to: %s; %s",
final_filename,strerror(errno));
}
if (state->linkname)
{
char *use_link;
char *final_link;
status = create_filenames(&final_link, &use_link, state->linkname, frame);
// Create hard link if possible, symlink otherwise
if (status != MMAL_SUCCESS
|| (0 != link(final_filename, use_link)
&& 0 != symlink(final_filename, use_link))
|| 0 != rename(use_link, final_link))
{
vcos_log_error("Could not link as filename: %s; %s",
state->linkname,strerror(errno));
}
if (use_link) free(use_link);
if (final_link) free(final_link);
}
}
/** /**
* main * main
@@ -1649,7 +1693,15 @@ int main(int argc, const char **argv)
} }
// We only capture if a filename was specified and it opened // We only capture if a filename was specified and it opened
if (output_file) if (state.useGL && state.glCapture && output_file)
{
/* Save the next GL framebuffer as the next camera still */
int rc = raspitex_capture(&state.raspitex_state, output_file);
if (rc != 0)
vcos_log_error("Failed to capture GL preview");
rename_file(&state, output_file, final_filename, use_filename, frame);
}
else if (output_file)
{ {
int num, q; int num, q;
@@ -1725,32 +1777,8 @@ int main(int argc, const char **argv)
if (output_file != stdout) if (output_file != stdout)
{ {
fclose(output_file); rename_file(&state, output_file, final_filename, use_filename, frame);
vcos_assert(use_filename != NULL && final_filename != NULL); }
if (0 != rename(use_filename, final_filename))
{
vcos_log_error("Could not rename temp file to: %s; %s",
final_filename,strerror(errno));
}
if (state.linkname)
{
char *use_link;
char *final_link;
status = create_filenames(&final_link, &use_link, state.linkname, frame);
// Create hard link if possible, symlink otherwise
if (status != MMAL_SUCCESS
|| (0 != link(final_filename, use_link)
&& 0 != symlink(final_filename, use_link))
|| 0 != rename(use_link, final_link))
{
vcos_log_error("Could not link as filename: %s; %s",
state.linkname,strerror(errno));
}
if (use_link) free(use_link);
if (final_link) free(final_link);
}
}
// Disable encoder output port // Disable encoder output port
status = mmal_port_disable(encoder_output_port); status = mmal_port_disable(encoder_output_port);
} }

View File

@@ -42,10 +42,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "interface/mmal/mmal_buffer.h" #include "interface/mmal/mmal_buffer.h"
#include "interface/mmal/util/mmal_util.h" #include "interface/mmal/util/mmal_util.h"
#include "interface/mmal/util/mmal_util_params.h" #include "interface/mmal/util/mmal_util_params.h"
#include "tga.h"
#include "mirror.h" #include "gl_scenes/mirror.h"
#include "square.h" #include "gl_scenes/sobel.h"
#include "teapot.h" #include "gl_scenes/square.h"
#include "gl_scenes/teapot.h"
#include "gl_scenes/yuv.h"
/** /**
* \file RaspiTex.c * \file RaspiTex.c
@@ -94,7 +97,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
static COMMAND_LIST cmdline_commands[] = static COMMAND_LIST cmdline_commands[] =
{ {
{ CommandGLScene, "-glscene", "gs", "GL scene square,teapot,mirror", 1 }, { CommandGLScene, "-glscene", "gs", "GL scene square,teapot,mirror,yuv,sobel", 1 },
{ CommandGLWin, "-glwin", "gw", "GL window settings <'x,y,w,h'>", 1 }, { CommandGLWin, "-glwin", "gw", "GL window settings <'x,y,w,h'>", 1 },
}; };
@@ -152,6 +155,12 @@ int raspitex_parse_cmdline(RASPITEX_STATE *state,
state->scene_id = RASPITEX_SCENE_TEAPOT; state->scene_id = RASPITEX_SCENE_TEAPOT;
else if (strcmp(arg2, "mirror") == 0) else if (strcmp(arg2, "mirror") == 0)
state->scene_id = RASPITEX_SCENE_MIRROR; state->scene_id = RASPITEX_SCENE_MIRROR;
else if (strcmp(arg2, "yuv") == 0)
state->scene_id = RASPITEX_SCENE_YUV;
else if (strcmp(arg2, "sobel") == 0)
state->scene_id = RASPITEX_SCENE_SOBEL;
else
vcos_log_error("Unknown scene %s", arg2);
used = 2; used = 2;
break; break;
@@ -195,6 +204,51 @@ static void update_fps()
} }
} }
/**
* Captures the frame-buffer if requested.
* @param state RASPITEX STATE
* @return Zero if successful.
*/
static void raspitex_do_capture(RASPITEX_STATE *state)
{
uint8_t *buffer = NULL;
size_t size = 0;
if (state->capture.request)
{
if (state->ops.capture(state, &buffer, &size) == 0)
{
/* Pass ownership of buffer to main thread via capture state */
state->capture.buffer = buffer;
state->capture.size = size;
}
else
{
state->capture.buffer = NULL; // Null indicates an error
state->capture.size = 0;
}
state->capture.request = 0; // Always clear request and post sem
vcos_semaphore_post(&state->capture.completed_sem);
}
}
/**
* Checks if there is at least one valid EGL image.
* @param state RASPITEX STATE
* @return Zero if successful.
*/
static int check_egl_image(RASPITEX_STATE *state)
{
if (state->egl_image == EGL_NO_IMAGE_KHR &&
state->y_egl_image == EGL_NO_IMAGE_KHR &&
state->u_egl_image == EGL_NO_IMAGE_KHR &&
state->v_egl_image == EGL_NO_IMAGE_KHR)
return -1;
else
return 0;
}
/** /**
* Draws the next preview frame. If a new preview buffer is available then the * Draws the next preview frame. If a new preview buffer is available then the
* preview texture is updated first. * preview texture is updated first.
@@ -217,15 +271,48 @@ static int raspitex_draw(RASPITEX_STATE *state, MMAL_BUFFER_HEADER_T *buf)
if (buf) if (buf)
{ {
/* Update the texture to the new viewfinder image which should */ /* Update the texture to the new viewfinder image which should */
rc = state->ops.update_texture(state, (EGLClientBuffer) buf->data); if (state->ops.update_texture)
if (rc != 0)
{ {
vcos_log_error("%s: Failed to update texture", VCOS_FUNCTION); rc = state->ops.update_texture(state, (EGLClientBuffer) buf->data);
goto end; if (rc != 0)
{
vcos_log_error("%s: Failed to update RGBX texture %d",
VCOS_FUNCTION, rc);
goto end;
}
} }
/* Now return the PREVIOUS MMAL buffer header back to the camera preview. if (state->ops.update_y_texture)
*/ {
rc = state->ops.update_y_texture(state, (EGLClientBuffer) buf->data);
if (rc != 0)
{
vcos_log_error("%s: Failed to update Y' plane texture %d", VCOS_FUNCTION, rc);
goto end;
}
}
if (state->ops.update_u_texture)
{
rc = state->ops.update_u_texture(state, (EGLClientBuffer) buf->data);
if (rc != 0)
{
vcos_log_error("%s: Failed to update U plane texture %d", VCOS_FUNCTION, rc);
goto end;
}
}
if (state->ops.update_v_texture)
{
rc = state->ops.update_v_texture(state, (EGLClientBuffer) buf->data);
if (rc != 0)
{
vcos_log_error("%s: Failed to update V texture %d", VCOS_FUNCTION, rc);
goto end;
}
}
/* Now return the PREVIOUS MMAL buffer header back to the camera preview. */
if (state->preview_buf) if (state->preview_buf)
mmal_buffer_header_release(state->preview_buf); mmal_buffer_header_release(state->preview_buf);
@@ -233,7 +320,7 @@ static int raspitex_draw(RASPITEX_STATE *state, MMAL_BUFFER_HEADER_T *buf)
} }
/* Do the drawing */ /* Do the drawing */
if (state->preview_egl_image != EGL_NO_IMAGE_KHR) if (check_egl_image(state) == 0)
{ {
rc = state->ops.update_model(state); rc = state->ops.update_model(state);
if (rc != 0) if (rc != 0)
@@ -243,9 +330,15 @@ static int raspitex_draw(RASPITEX_STATE *state, MMAL_BUFFER_HEADER_T *buf)
if (rc != 0) if (rc != 0)
goto end; goto end;
raspitex_do_capture(state);
eglSwapBuffers(state->display, state->surface); eglSwapBuffers(state->display, state->surface);
update_fps(); update_fps();
} }
else
{
// vcos_log_trace("%s: No preview image", VCOS_FUNCTION);
}
end: end:
return rc; return rc;
@@ -354,13 +447,13 @@ static void preview_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
if (buf->length == 0) if (buf->length == 0)
{ {
vcos_log_info("%s: zero-length buffer => EOS", port->name); vcos_log_trace("%s: zero-length buffer => EOS", port->name);
state->preview_stop = 1; state->preview_stop = 1;
mmal_buffer_header_release(buf); mmal_buffer_header_release(buf);
} }
else if (buf->data == NULL) else if (buf->data == NULL)
{ {
vcos_log_info("%s: zero buffer handle", port->name); vcos_log_trace("%s: zero buffer handle", port->name);
mmal_buffer_header_release(buf); mmal_buffer_header_release(buf);
} }
else else
@@ -450,13 +543,13 @@ end:
return (status == MMAL_SUCCESS ? 0 : -1); return (status == MMAL_SUCCESS ? 0 : -1);
} }
/* Initialises GL preview state and creates the dispmanx native window. /* Initialises GL preview state and creates the dispmanx native window.
* @param state Pointer to the GL preview state. * @param state Pointer to the GL preview state.
* @return Zero if successful. * @return Zero if successful.
*/ */
int raspitex_init(RASPITEX_STATE *state) int raspitex_init(RASPITEX_STATE *state)
{ {
VCOS_STATUS_T status;
int rc; int rc;
vcos_init(); vcos_init();
@@ -465,6 +558,16 @@ int raspitex_init(RASPITEX_STATE *state)
state->verbose ? VCOS_LOG_INFO : VCOS_LOG_WARN); state->verbose ? VCOS_LOG_INFO : VCOS_LOG_WARN);
vcos_log_trace("%s", VCOS_FUNCTION); vcos_log_trace("%s", VCOS_FUNCTION);
status = vcos_semaphore_create(&state->capture.start_sem,
"glcap_start_sem", 1);
if (status != VCOS_SUCCESS)
goto error;
status = vcos_semaphore_create(&state->capture.completed_sem,
"glcap_completed_sem", 0);
if (status != VCOS_SUCCESS)
goto error;
switch (state->scene_id) switch (state->scene_id)
{ {
case RASPITEX_SCENE_SQUARE: case RASPITEX_SCENE_SQUARE:
@@ -476,14 +579,24 @@ int raspitex_init(RASPITEX_STATE *state)
case RASPITEX_SCENE_TEAPOT: case RASPITEX_SCENE_TEAPOT:
rc = teapot_open(state); rc = teapot_open(state);
break; break;
case RASPITEX_SCENE_YUV:
rc = yuv_open(state);
break;
case RASPITEX_SCENE_SOBEL:
rc = sobel_open(state);
break;
default: default:
rc = -1; rc = -1;
break; break;
} }
if (rc != 0) if (rc != 0)
return rc; goto error;
return rc; return 0;
error:
vcos_log_error("%s: failed", VCOS_FUNCTION);
return -1;
} }
/* Destroys the pools of buffers used by the GL renderer. /* Destroys the pools of buffers used by the GL renderer.
@@ -503,8 +616,15 @@ void raspitex_destroy(RASPITEX_STATE *state)
mmal_queue_destroy(state->preview_queue); mmal_queue_destroy(state->preview_queue);
state->preview_queue = NULL; state->preview_queue = NULL;
} }
state->ops.destroy_native_window(state);
state->ops.close(state); if (state->ops.destroy_native_window)
state->ops.destroy_native_window(state);
if (state->ops.close)
state->ops.close(state);
vcos_semaphore_delete(&state->capture.start_sem);
vcos_semaphore_delete(&state->capture.completed_sem);
} }
/* Initialise the GL / window state to sensible defaults. /* Initialise the GL / window state to sensible defaults.
@@ -516,10 +636,15 @@ void raspitex_destroy(RASPITEX_STATE *state)
void raspitex_set_defaults(RASPITEX_STATE *state) void raspitex_set_defaults(RASPITEX_STATE *state)
{ {
memset(state, 0, sizeof(*state)); memset(state, 0, sizeof(*state));
state->version_major = RASPITEX_VERSION_MAJOR;
state->version_minor = RASPITEX_VERSION_MINOR;
state->display = EGL_NO_DISPLAY; state->display = EGL_NO_DISPLAY;
state->surface = EGL_NO_SURFACE; state->surface = EGL_NO_SURFACE;
state->context = EGL_NO_CONTEXT; state->context = EGL_NO_CONTEXT;
state->preview_egl_image = EGL_NO_IMAGE_KHR; state->egl_image = EGL_NO_IMAGE_KHR;
state->y_egl_image = EGL_NO_IMAGE_KHR;
state->u_egl_image = EGL_NO_IMAGE_KHR;
state->v_egl_image = EGL_NO_IMAGE_KHR;
state->opacity = 255; state->opacity = 255;
state->width = DEFAULT_WIDTH; state->width = DEFAULT_WIDTH;
state->height = DEFAULT_HEIGHT; state->height = DEFAULT_HEIGHT;
@@ -527,9 +652,9 @@ void raspitex_set_defaults(RASPITEX_STATE *state)
state->ops.create_native_window = raspitexutil_create_native_window; state->ops.create_native_window = raspitexutil_create_native_window;
state->ops.gl_init = raspitexutil_gl_init_1_0; state->ops.gl_init = raspitexutil_gl_init_1_0;
state->ops.update_texture = raspitexutil_update_texture;
state->ops.update_model = raspitexutil_update_model; state->ops.update_model = raspitexutil_update_model;
state->ops.redraw = raspitexutil_redraw; state->ops.redraw = raspitexutil_redraw;
state->ops.capture = raspitexutil_capture_bgra;
state->ops.gl_term = raspitexutil_gl_term; state->ops.gl_term = raspitexutil_gl_term;
state->ops.destroy_native_window = raspitexutil_destroy_native_window; state->ops.destroy_native_window = raspitexutil_destroy_native_window;
state->ops.close = raspitexutil_close; state->ops.close = raspitexutil_close;
@@ -569,3 +694,55 @@ int raspitex_start(RASPITEX_STATE *state)
return (status == VCOS_SUCCESS ? 0 : -1); return (status == VCOS_SUCCESS ? 0 : -1);
} }
/**
* Writes the next GL frame-buffer to a RAW .ppm formatted file
* using the specified file-handle.
* @param state Pointer to the GL preview state.
* @param outpt_file Output file handle for the ppm image.
* @return Zero on success.
*/
int raspitex_capture(RASPITEX_STATE *state, FILE *output_file)
{
int rc = 0;
uint8_t *buffer = NULL;
size_t size = 0;
vcos_log_trace("%s: state %p file %p", VCOS_FUNCTION,
state, output_file);
if (state && output_file)
{
/* Only request one capture at a time */
vcos_semaphore_wait(&state->capture.start_sem);
state->capture.request = 1;
/* Wait for capture to start */
vcos_semaphore_wait(&state->capture.completed_sem);
/* Take ownership of the captured buffer */
buffer = state->capture.buffer;
size = state->capture.size;
state->capture.request = 0;
state->capture.buffer = 0;
state->capture.size = 0;
/* Allow another capture to be requested */
vcos_semaphore_post(&state->capture.start_sem);
}
if (size == 0 || ! buffer)
{
vcos_log_error("%s: capture failed", VCOS_FUNCTION);
rc = -1;
goto end;
}
raspitexutil_brga_to_rgba(buffer, size);
rc = write_tga(output_file, state->width, state->height, buffer, size);
fflush(output_file);
end:
free(buffer);
return rc;
}

View File

@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef RASPITEX_H_ #ifndef RASPITEX_H_
#define RASPITEX_H_ #define RASPITEX_H_
#include <stdio.h>
#include <EGL/egl.h> #include <EGL/egl.h>
#include <EGL/eglext.h> #include <EGL/eglext.h>
#include <GLES/gl.h> #include <GLES/gl.h>
@@ -36,10 +37,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "interface/khronos/include/EGL/eglext_brcm.h" #include "interface/khronos/include/EGL/eglext_brcm.h"
#include "interface/mmal/mmal.h" #include "interface/mmal/mmal.h"
#define RASPITEX_VERSION_MAJOR 1
#define RASPITEX_VERSION_MINOR 0
typedef enum { typedef enum {
RASPITEX_SCENE_SQUARE = 0, RASPITEX_SCENE_SQUARE = 0,
RASPITEX_SCENE_MIRROR, RASPITEX_SCENE_MIRROR,
RASPITEX_SCENE_TEAPOT RASPITEX_SCENE_TEAPOT,
RASPITEX_SCENE_YUV,
RASPITEX_SCENE_SOBEL,
} RASPITEX_SCENE_T; } RASPITEX_SCENE_T;
@@ -54,15 +60,33 @@ typedef struct RASPITEX_SCENE_OPS
/// Creates EGL surface for native window /// Creates EGL surface for native window
int (*gl_init)(struct RASPITEX_STATE *state); int (*gl_init)(struct RASPITEX_STATE *state);
/// Advance to the next animation step /// Updates the RGBX texture from the next MMAL buffer
/// Set to null if this texture type is not required
int (*update_texture)(struct RASPITEX_STATE *state, EGLClientBuffer mm_buf); int (*update_texture)(struct RASPITEX_STATE *state, EGLClientBuffer mm_buf);
/// Updates the Y' plane texture from the next MMAL buffer
/// Set to null if this texture type is not required
int (*update_y_texture)(struct RASPITEX_STATE *state, EGLClientBuffer mm_buf);
/// Updates the U plane texture from the next MMAL buffer
/// Set to null if this texture type is not required
int (*update_u_texture)(struct RASPITEX_STATE *state, EGLClientBuffer mm_buf);
/// Updates the V plane texture from the next MMAL buffer
/// Set to null if this texture type is not required
int (*update_v_texture)(struct RASPITEX_STATE *state, EGLClientBuffer mm_buf);
/// Advance to the next animation step /// Advance to the next animation step
int (*update_model)(struct RASPITEX_STATE *state); int (*update_model)(struct RASPITEX_STATE *state);
/// Draw the scene - called after update_model /// Draw the scene - called after update_model
int (*redraw)(struct RASPITEX_STATE *state); int (*redraw)(struct RASPITEX_STATE *state);
/// Allocates a buffer and copies the pixels from the current
/// frame-buffer into it.
int (*capture)(struct RASPITEX_STATE *state,
uint8_t **buffer, size_t *buffer_size);
/// Creates EGL surface for native window /// Creates EGL surface for native window
void (*gl_term)(struct RASPITEX_STATE *state); void (*gl_term)(struct RASPITEX_STATE *state);
@@ -73,18 +97,45 @@ typedef struct RASPITEX_SCENE_OPS
void (*close)(struct RASPITEX_STATE *state); void (*close)(struct RASPITEX_STATE *state);
} RASPITEX_SCENE_OPS; } RASPITEX_SCENE_OPS;
typedef struct RASPITEX_CAPTURE
{
/// Wait for previous capture to complete
VCOS_SEMAPHORE_T start_sem;
/// Posted once the capture is complete
VCOS_SEMAPHORE_T completed_sem;
/// The RGB capture buffer
uint8_t *buffer;
/// Size of the captured buffer in bytes
size_t size;
/// Frame-buffer capture has been requested. Could use
/// a queue instead here to allow multiple capture requests.
int request;
} RASPITEX_CAPTURE;
/** /**
* Contains the internal state and configuration for the GL rendered * Contains the internal state and configuration for the GL rendered
* preview window. * preview window.
*/ */
typedef struct RASPITEX_STATE typedef struct RASPITEX_STATE
{ {
int version_major; /// For binary compatibility
int version_minor; /// Incremented for new features
MMAL_PORT_T *preview_port; /// Source port for preview opaque buffers MMAL_PORT_T *preview_port; /// Source port for preview opaque buffers
MMAL_POOL_T *preview_pool; /// Pool for storing opaque buffer handles MMAL_POOL_T *preview_pool; /// Pool for storing opaque buffer handles
MMAL_QUEUE_T *preview_queue; /// Queue preview buffers to display in order MMAL_QUEUE_T *preview_queue; /// Queue preview buffers to display in order
VCOS_THREAD_T preview_thread; /// Preview worker / GL rendering thread VCOS_THREAD_T preview_thread; /// Preview worker / GL rendering thread
uint32_t preview_stop; /// If zero the worker can continue uint32_t preview_stop; /// If zero the worker can continue
/* Copy of preview window params */
int32_t preview_x; /// x-offset of preview window
int32_t preview_y; /// y-offset of preview window
int32_t preview_width; /// preview y-plane width in pixels
int32_t preview_height; /// preview y-plane height in pixels
/* Display rectangle for the native window */ /* Display rectangle for the native window */
int32_t x; /// x-offset in pixels int32_t x; /// x-offset in pixels
int32_t y; /// y-offset in pixels int32_t y; /// y-offset in pixels
@@ -102,16 +153,27 @@ typedef struct RASPITEX_STATE
EGLDisplay display; /// The current EGL display EGLDisplay display; /// The current EGL display
EGLSurface surface; /// The current EGL surface EGLSurface surface; /// The current EGL surface
EGLContext context; /// The current EGL context EGLContext context; /// The current EGL context
const EGLint *egl_config_attribs; /// GL scenes preferred EGL configuration
GLuint texture; /// Texture name for the preview texture GLuint texture; /// Name for the preview texture
EGLImageKHR preview_egl_image; /// The current preview EGL image EGLImageKHR egl_image; /// The current preview EGL image
MMAL_BUFFER_HEADER_T *preview_buf; /// MMAL buffer currently bound to texture
GLuint y_texture; /// The Y plane texture
EGLImageKHR y_egl_image; /// EGL image for Y plane texture
GLuint u_texture; /// The U plane texture
EGLImageKHR u_egl_image; /// EGL image for U plane texture
GLuint v_texture; /// The V plane texture
EGLImageKHR v_egl_image; /// EGL image for V plane texture
MMAL_BUFFER_HEADER_T *preview_buf; /// MMAL buffer currently bound to texture(s)
RASPITEX_SCENE_T scene_id; /// Id of the scene to load RASPITEX_SCENE_T scene_id; /// Id of the scene to load
RASPITEX_SCENE_OPS ops; /// The interface for the current scene RASPITEX_SCENE_OPS ops; /// The interface for the current scene
void *scene_state; /// Pointer to scene specific data void *scene_state; /// Pointer to scene specific data
int verbose; /// Log FPS int verbose; /// Log FPS
RASPITEX_CAPTURE capture; /// Frame-buffer capture state
} RASPITEX_STATE; } RASPITEX_STATE;
int raspitex_init(RASPITEX_STATE *state); int raspitex_init(RASPITEX_STATE *state);
@@ -124,5 +186,6 @@ int raspitex_configure_preview_port(RASPITEX_STATE *state,
void raspitex_display_help(); void raspitex_display_help();
int raspitex_parse_cmdline(RASPITEX_STATE *state, int raspitex_parse_cmdline(RASPITEX_STATE *state,
const char *arg1, const char *arg2); const char *arg1, const char *arg2);
int raspitex_capture(RASPITEX_STATE *state, FILE* output_file);
#endif /* RASPITEX_H_ */ #endif /* RASPITEX_H_ */

View File

@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "RaspiTexUtil.h" #include "RaspiTexUtil.h"
#include "RaspiTex.h" #include "RaspiTex.h"
#include <bcm_host.h> #include <bcm_host.h>
#include <GLES2/gl2.h>
VCOS_LOG_CAT_T raspitex_log_category; VCOS_LOG_CAT_T raspitex_log_category;
@@ -47,10 +48,22 @@ void raspitexutil_gl_term(RASPITEX_STATE *raspitex_state)
{ {
vcos_log_trace("%s", VCOS_FUNCTION); vcos_log_trace("%s", VCOS_FUNCTION);
/* Delete texture name */ /* Delete OES textures */
glDeleteTextures(1, &raspitex_state->texture); glDeleteTextures(1, &raspitex_state->texture);
eglDestroyImageKHR(raspitex_state->display, raspitex_state->preview_egl_image); eglDestroyImageKHR(raspitex_state->display, raspitex_state->egl_image);
raspitex_state->preview_egl_image = EGL_NO_IMAGE_KHR; raspitex_state->egl_image = EGL_NO_IMAGE_KHR;
glDeleteTextures(1, &raspitex_state->y_texture);
eglDestroyImageKHR(raspitex_state->display, raspitex_state->y_egl_image);
raspitex_state->y_egl_image = EGL_NO_IMAGE_KHR;
glDeleteTextures(1, &raspitex_state->u_texture);
eglDestroyImageKHR(raspitex_state->display, raspitex_state->u_egl_image);
raspitex_state->u_egl_image = EGL_NO_IMAGE_KHR;
glDeleteTextures(1, &raspitex_state->v_texture);
eglDestroyImageKHR(raspitex_state->display, raspitex_state->v_egl_image);
raspitex_state->u_egl_image = EGL_NO_IMAGE_KHR;
/* Terminate EGL */ /* Terminate EGL */
eglMakeCurrent(raspitex_state->display, EGL_NO_SURFACE, eglMakeCurrent(raspitex_state->display, EGL_NO_SURFACE,
@@ -80,13 +93,13 @@ int raspitexutil_create_native_window(RASPITEX_STATE *raspitex_state)
dest_rect.width = raspitex_state->width; dest_rect.width = raspitex_state->width;
dest_rect.height = raspitex_state->height; dest_rect.height = raspitex_state->height;
src_rect.width = dest_rect.width << 16;
src_rect.height = dest_rect.height << 16;
vcos_log_trace("%s: %d,%d,%d,%d %d,%d,0x%x,0x%x", VCOS_FUNCTION, vcos_log_trace("%s: %d,%d,%d,%d %d,%d,0x%x,0x%x", VCOS_FUNCTION,
src_rect.x, src_rect.y, src_rect.width, src_rect.height, src_rect.x, src_rect.y, src_rect.width, src_rect.height,
dest_rect.x, dest_rect.y, dest_rect.width, dest_rect.height); dest_rect.x, dest_rect.y, dest_rect.width, dest_rect.height);
src_rect.width = dest_rect.width << 16;
src_rect.height = dest_rect.height << 16;
raspitex_state->disp = vc_dispmanx_display_open(disp_num); raspitex_state->disp = vc_dispmanx_display_open(disp_num);
if (raspitex_state->disp == DISPMANX_NO_HANDLE) if (raspitex_state->disp == DISPMANX_NO_HANDLE)
{ {
@@ -208,6 +221,19 @@ error:
return -1; return -1;
} }
/* Creates the RGBA and luma textures with some default parameters
* @param raspitex_state A pointer to the GL preview state.
* @return Zero if successful.
*/
int raspitexutil_create_textures(RASPITEX_STATE *raspitex_state)
{
GLCHK(glGenTextures(1, &raspitex_state->texture));
GLCHK(glGenTextures(1, &raspitex_state->y_texture));
GLCHK(glGenTextures(1, &raspitex_state->u_texture));
GLCHK(glGenTextures(1, &raspitex_state->v_texture));
return 0;
}
/** /**
* Creates an OpenGL ES 1.X context. * Creates an OpenGL ES 1.X context.
* @param raspitex_state A pointer to the GL preview state. * @param raspitex_state A pointer to the GL preview state.
@@ -216,8 +242,9 @@ error:
int raspitexutil_gl_init_1_0(RASPITEX_STATE *raspitex_state) int raspitexutil_gl_init_1_0(RASPITEX_STATE *raspitex_state)
{ {
int rc; int rc;
const EGLint* attribs = raspitex_state->egl_config_attribs;
const EGLint attribs[] = const EGLint default_attribs[] =
{ {
EGL_RED_SIZE, 8, EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8, EGL_GREEN_SIZE, 8,
@@ -234,13 +261,15 @@ int raspitexutil_gl_init_1_0(RASPITEX_STATE *raspitex_state)
EGL_NONE EGL_NONE
}; };
vcos_log_trace("%s", VCOS_FUNCTION); if (! attribs)
attribs = default_attribs;
rc = raspitexutil_gl_common(raspitex_state, attribs, context_attribs); rc = raspitexutil_gl_common(raspitex_state, attribs, context_attribs);
if (rc != 0) if (rc != 0)
goto end; goto end;
GLCHK(glEnable(GL_TEXTURE_EXTERNAL_OES)); GLCHK(glEnable(GL_TEXTURE_EXTERNAL_OES));
GLCHK(glGenTextures(1, &raspitex_state->texture)); rc = raspitexutil_create_textures(raspitex_state);
end: end:
return rc; return rc;
@@ -254,14 +283,16 @@ end:
int raspitexutil_gl_init_2_0(RASPITEX_STATE *raspitex_state) int raspitexutil_gl_init_2_0(RASPITEX_STATE *raspitex_state)
{ {
int rc; int rc;
const EGLint attribs[] = const EGLint* attribs = raspitex_state->egl_config_attribs;;
const EGLint default_attribs[] =
{ {
EGL_RED_SIZE, 8, EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8, EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8, EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8, EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 16, EGL_DEPTH_SIZE, 16,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE EGL_NONE
}; };
@@ -271,44 +302,102 @@ int raspitexutil_gl_init_2_0(RASPITEX_STATE *raspitex_state)
EGL_NONE EGL_NONE
}; };
if (! attribs)
attribs = default_attribs;
vcos_log_trace("%s", VCOS_FUNCTION); vcos_log_trace("%s", VCOS_FUNCTION);
rc = raspitexutil_gl_common(raspitex_state, attribs, context_attribs); rc = raspitexutil_gl_common(raspitex_state, attribs, context_attribs);
if (rc != 0) if (rc != 0)
goto end; goto end;
GLCHK(glGenTextures(1, &raspitex_state->texture));
rc = raspitexutil_create_textures(raspitex_state);
end: end:
return rc; return rc;
} }
/** /**
* Updates the viewfinder texture whenever a new viewfinder MMAL buffer * Advances the texture and EGL image to the next MMAL buffer.
* is available. *
* @param display The EGL display.
* @param target The EGL image target e.g. EGL_IMAGE_BRCM_MULTIMEDIA
* @param mm_buf The EGL client buffer (mmal opaque buffer) that is used to
* create the EGL Image for the preview texture.
* @param egl_image Pointer to the EGL image to update with mm_buf.
* @param texture Pointer to the texture to update from EGL image.
* @return Zero if successful.
*/
int raspitexutil_do_update_texture(EGLDisplay display, EGLenum target,
EGLClientBuffer mm_buf, GLuint *texture, EGLImageKHR *egl_image)
{
vcos_log_trace("%s: mm_buf %u", VCOS_FUNCTION, (unsigned) mm_buf);
GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, *texture));
if (*egl_image != EGL_NO_IMAGE_KHR)
{
/* Discard the EGL image for the preview frame */
eglDestroyImageKHR(display, *egl_image);
*egl_image = EGL_NO_IMAGE_KHR;
}
*egl_image = eglCreateImageKHR(display, EGL_NO_CONTEXT, target, mm_buf, NULL);
GLCHK(glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, *egl_image));
return 0;
}
/**
* Updates the RGBX texture to the specified MMAL buffer.
* @param raspitex_state A pointer to the GL preview state. * @param raspitex_state A pointer to the GL preview state.
* @param mm_buf The EGL client buffer (mmal opaque buffer) that is * @param mm_buf The MMAL buffer.
* used to create the EGL Image for the preview texture.
* @return Zero if successful. * @return Zero if successful.
*/ */
int raspitexutil_update_texture(RASPITEX_STATE *raspitex_state, int raspitexutil_update_texture(RASPITEX_STATE *raspitex_state,
EGLClientBuffer mm_buf) EGLClientBuffer mm_buf)
{ {
// vcos_log_trace("%s: mm_buf %u", VCOS_FUNCTION, (unsigned) mm_buf); return raspitexutil_do_update_texture(raspitex_state->display,
if (raspitex_state->preview_egl_image != EGL_NO_IMAGE_KHR) EGL_IMAGE_BRCM_MULTIMEDIA, mm_buf,
{ &raspitex_state->texture, &raspitex_state->egl_image);
/* Discard the EGL image for the preview frame */ }
eglDestroyImageKHR(raspitex_state->display,
raspitex_state->preview_egl_image);
raspitex_state->preview_egl_image = EGL_NO_IMAGE_KHR;
}
raspitex_state->preview_egl_image = eglCreateImageKHR(raspitex_state->display, /**
EGL_NO_CONTEXT, EGL_IMAGE_BRCM_MULTIMEDIA, mm_buf, NULL); * Updates the Y plane texture to the specified MMAL buffer.
* @param raspitex_state A pointer to the GL preview state.
* @param mm_buf The MMAL buffer.
* @return Zero if successful.
*/
int raspitexutil_update_y_texture(RASPITEX_STATE *raspitex_state,
EGLClientBuffer mm_buf)
{
return raspitexutil_do_update_texture(raspitex_state->display,
EGL_IMAGE_BRCM_MULTIMEDIA_Y, mm_buf,
&raspitex_state->y_texture, &raspitex_state->y_egl_image);
}
GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->texture)); /**
GLCHK(glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, * Updates the U plane texture to the specified MMAL buffer.
raspitex_state->preview_egl_image)); * @param raspitex_state A pointer to the GL preview state.
* @param mm_buf The MMAL buffer.
* @return Zero if successful.
*/
int raspitexutil_update_u_texture(RASPITEX_STATE *raspitex_state,
EGLClientBuffer mm_buf)
{
return raspitexutil_do_update_texture(raspitex_state->display,
EGL_IMAGE_BRCM_MULTIMEDIA_U, mm_buf,
&raspitex_state->u_texture, &raspitex_state->u_egl_image);
}
return 0; /**
* Updates the V plane texture to the specified MMAL buffer.
* @param raspitex_state A pointer to the GL preview state.
* @param mm_buf The MMAL buffer.
* @return Zero if successful.
*/
int raspitexutil_update_v_texture(RASPITEX_STATE *raspitex_state,
EGLClientBuffer mm_buf)
{
return raspitexutil_do_update_texture(raspitex_state->display,
EGL_IMAGE_BRCM_MULTIMEDIA_V, mm_buf,
&raspitex_state->v_texture, &raspitex_state->v_egl_image);
} }
/** /**
@@ -341,3 +430,168 @@ void raspitexutil_close(RASPITEX_STATE* raspitex_state)
{ {
(void) raspitex_state; (void) raspitex_state;
} }
/**
* Performs an in-place byte swap from BGRA to RGBA.
* @param buffer The buffer to modify.
* @param size Size of the buffer in bytes.
*/
void raspitexutil_brga_to_rgba(uint8_t *buffer, size_t size)
{
uint8_t* out = buffer;
uint8_t* end = buffer + size;
while (out < end)
{
uint8_t tmp = out[0];
out[0] = out[2];
out[2] = tmp;
out += 4;
}
}
/**
* Uses glReadPixels to grab the current frame-buffer contents
* and returns the result in a newly allocate buffer along with
* the its size.
* Data is returned in BGRA format for TGA output. PPM output doesn't
* require the channel order swap but would require a vflip. The TGA
* format also supports alpha. The byte swap is not done in this function
* to avoid blocking the GL rendering thread.
* @param state Pointer to the GL preview state.
* @param buffer Address of pointer to set to pointer to new buffer.
* @param buffer_size The size of the new buffer in bytes (out param)
* @return Zero if successful.
*/
int raspitexutil_capture_bgra(RASPITEX_STATE *state,
uint8_t **buffer, size_t *buffer_size)
{
const int bytes_per_pixel = 4;
vcos_log_trace("%s: %dx%d %d", VCOS_FUNCTION,
state->width, state->height, bytes_per_pixel);
*buffer_size = state->width * state->height * bytes_per_pixel;
*buffer = calloc(*buffer_size, 1);
if (! *buffer)
goto error;
glReadPixels(0, 0, state->width, state->height, GL_RGBA,
GL_UNSIGNED_BYTE, *buffer);
if (glGetError() != GL_NO_ERROR)
goto error;
return 0;
error:
*buffer_size = 0;
if (*buffer)
free(*buffer);
*buffer = NULL;
return -1;
}
/**
* Takes a description of shader program, compiles it and gets the locations
* of uniforms and attributes.
*
* @param p The shader program state.
* @return Zero if successful.
*/
int raspitexutil_build_shader_program(RASPITEXUTIL_SHADER_PROGRAM_T *p)
{
GLint status;
int i = 0;
char log[1024];
int logLen = 0;
vcos_assert(p);
vcos_assert(p->vertex_source);
vcos_assert(p->fragment_source);
if (! (p && p->vertex_source && p->fragment_source))
goto fail;
p->vs = p->fs = 0;
p->vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(p->vs, 1, &p->vertex_source, NULL);
glCompileShader(p->vs);
glGetShaderiv(p->vs, GL_COMPILE_STATUS, &status);
if (! status) {
glGetShaderInfoLog(p->vs, sizeof(log), &logLen, log);
vcos_log_error("Program info log %s", log);
goto fail;
}
p->fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(p->fs, 1, &p->fragment_source, NULL);
glCompileShader(p->fs);
glGetShaderiv(p->fs, GL_COMPILE_STATUS, &status);
if (! status) {
glGetShaderInfoLog(p->fs, sizeof(log), &logLen, log);
vcos_log_error("Program info log %s", log);
goto fail;
}
p->program = glCreateProgram();
glAttachShader(p->program, p->vs);
glAttachShader(p->program, p->fs);
glLinkProgram(p->program);
glGetProgramiv(p->program, GL_LINK_STATUS, &status);
if (! status)
{
vcos_log_error("Failed to link shader program");
glGetProgramInfoLog(p->program, sizeof(log), &logLen, log);
vcos_log_error("Program info log %s", log);
goto fail;
}
for (i = 0; i < SHADER_MAX_ATTRIBUTES; ++i)
{
if (! p->attribute_names[i])
break;
p->attribute_locations[i] = glGetAttribLocation(p->program, p->attribute_names[i]);
if (p->attribute_locations[i] == -1)
{
vcos_log_error("Failed to get location for attribute %s",
p->attribute_names[i]);
goto fail;
}
else {
vcos_log_trace("Attribute for %s is %d",
p->attribute_names[i], p->attribute_locations[i]);
}
}
for (i = 0; i < SHADER_MAX_UNIFORMS; ++i)
{
if (! p->uniform_names[i])
break;
p->uniform_locations[i] = glGetUniformLocation(p->program, p->uniform_names[i]);
if (p->uniform_locations[i] == -1)
{
vcos_log_error("Failed to get location for uniform %s",
p->uniform_names[i]);
goto fail;
}
else {
vcos_log_trace("Uniform for %s is %d",
p->uniform_names[i], p->uniform_locations[i]);
}
}
return 0;
fail:
vcos_log_error("%s: Failed to build shader program", VCOS_FUNCTION);
if (p)
{
glDeleteProgram(p->program);
glDeleteShader(p->fs);
glDeleteShader(p->vs);
}
return -1;
}

View File

@@ -26,8 +26,8 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef RASPITEX_UTIL_H #ifndef RASPITEX_UTIL_H_
#define RASPITEX_UTIL_H #define RASPITEX_UTIL_H_
#define VCOS_LOG_CATEGORY (&raspitex_log_category) #define VCOS_LOG_CATEGORY (&raspitex_log_category)
#include <math.h> #include <math.h>
@@ -41,6 +41,34 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
extern VCOS_LOG_CAT_T raspitex_log_category; extern VCOS_LOG_CAT_T raspitex_log_category;
#define SHADER_MAX_ATTRIBUTES 16
#define SHADER_MAX_UNIFORMS 16
/**
* Container for a simple shader program. The uniform and attribute locations
* are automatically setup by raspitex_build_shader_program.
*/
typedef struct RASPITEXUTIL_SHADER_PROGRAM_T
{
const char *vertex_source; /// Pointer to vertex shader source
const char *fragment_source; /// Pointer to fragment shader source
/// Array of uniform names for raspitex_build_shader_program to process
const char *uniform_names[SHADER_MAX_UNIFORMS];
/// Array of attribute names for raspitex_build_shader_program to process
const char *attribute_names[SHADER_MAX_ATTRIBUTES];
GLint vs; /// Vertex shader handle
GLint fs; /// Fragment shader handle
GLint program; /// Shader program handle
/// The locations for uniforms defined in uniform_names
GLint uniform_locations[SHADER_MAX_UNIFORMS];
/// The locations for attributes defined in attribute_names
GLint attribute_locations[SHADER_MAX_ATTRIBUTES];
} RASPITEXUTIL_SHADER_PROGRAM_T;
/* Uncomment to enable extra GL error checking */ /* Uncomment to enable extra GL error checking */
//#define CHECK_GL_ERRORS //#define CHECK_GL_ERRORS
#if defined(CHECK_GL_ERRORS) #if defined(CHECK_GL_ERRORS)
@@ -50,7 +78,7 @@ do { \
X; \ X; \
while ((err = glGetError())) \ while ((err = glGetError())) \
{ \ { \
vcos_log_trace("GL error 0x%x in " #X "file %s line %d", err, __FILE__,__LINE__); \ vcos_log_error("GL error 0x%x in " #X "file %s line %d", err, __FILE__,__LINE__); \
vcos_assert(err == GL_NO_ERROR); \ vcos_assert(err == GL_NO_ERROR); \
exit(err); \ exit(err); \
} \ } \
@@ -68,8 +96,21 @@ int raspitexutil_update_model(RASPITEX_STATE* raspitex_state);
int raspitexutil_redraw(RASPITEX_STATE* raspitex_state); int raspitexutil_redraw(RASPITEX_STATE* raspitex_state);
void raspitexutil_gl_term(RASPITEX_STATE *raspitex_state); void raspitexutil_gl_term(RASPITEX_STATE *raspitex_state);
void raspitexutil_destroy_native_window(RASPITEX_STATE *raspitex_state); void raspitexutil_destroy_native_window(RASPITEX_STATE *raspitex_state);
int raspitexutil_create_textures(RASPITEX_STATE *raspitex_state);
int raspitexutil_update_texture(RASPITEX_STATE *raspitex_state, int raspitexutil_update_texture(RASPITEX_STATE *raspitex_state,
EGLClientBuffer mm_buf); EGLClientBuffer mm_buf);
int raspitexutil_update_y_texture(RASPITEX_STATE *raspitex_state,
EGLClientBuffer mm_buf);
int raspitexutil_update_u_texture(RASPITEX_STATE *raspitex_state,
EGLClientBuffer mm_buf);
int raspitexutil_update_v_texture(RASPITEX_STATE *raspitex_state,
EGLClientBuffer mm_buf);
int raspitexutil_capture_bgra(struct RASPITEX_STATE *state,
uint8_t **buffer, size_t *buffer_size);
void raspitexutil_close(RASPITEX_STATE* raspitex_state); void raspitexutil_close(RASPITEX_STATE* raspitex_state);
#endif /* RASPITEX_UTIL_H */ /* Utility functions */
int raspitexutil_build_shader_program(RASPITEXUTIL_SHADER_PROGRAM_T *p);
void raspitexutil_brga_to_rgba(uint8_t *buffer, size_t size);
#endif /* RASPITEX_UTIL_H_ */

View File

@@ -0,0 +1,123 @@
/*
Copyright (c) 2013, Broadcom Europe Ltd
Copyright (c) 2013, Tim Gover
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "mirror.h"
#include "RaspiTex.h"
#include "RaspiTexUtil.h"
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
/**
* Draws an external EGL image and applies a sine wave distortion to create
* a hall of mirrors effect.
*/
static RASPITEXUTIL_SHADER_PROGRAM_T mirror_shader = {
.vertex_source =
"attribute vec2 vertex;\n"
"varying vec2 texcoord;"
"void main(void) {\n"
" texcoord = 0.5 * (vertex + 1.0);\n"
" gl_Position = vec4(vertex, 0.0, 1.0);\n"
"}\n",
.fragment_source =
"#extension GL_OES_EGL_image_external : require\n"
"uniform samplerExternalOES tex;\n"
"uniform float offset;\n"
"const float waves = 2.0;\n"
"varying vec2 texcoord;\n"
"void main(void) {\n"
" float x = texcoord.x + 0.05 * sin(offset + (texcoord.y * waves * 2.0 * 3.141592));\n"
" float y = texcoord.y + 0.05 * sin(offset + (texcoord.x * waves * 2.0 * 3.141592));\n"
" if (y < 1.0 && y > 0.0 && x < 1.0 && x > 0.0) {\n"
" vec2 pos = vec2(x, y);\n"
" gl_FragColor = texture2D(tex, pos);\n"
" }\n"
" else {\n"
" gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
" }\n"
"}\n",
.uniform_names = {"tex", "offset"},
.attribute_names = {"vertex"},
};
/**
* Creates the OpenGL ES 2.X context and builds the shaders.
* @param raspitex_state A pointer to the GL preview state.
* @return Zero if successful.
*/
static int mirror_init(RASPITEX_STATE *state)
{
int rc = raspitexutil_gl_init_2_0(state);
if (rc != 0)
goto end;
rc = raspitexutil_build_shader_program(&mirror_shader);
end:
return rc;
}
static int mirror_redraw(RASPITEX_STATE *raspitex_state) {
static float offset = 0.0;
// Start with a clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Bind the OES texture which is used to render the camera preview
glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->texture);
offset += 0.05;
GLCHK(glUseProgram(mirror_shader.program));
GLCHK(glEnableVertexAttribArray(mirror_shader.attribute_locations[0]));
GLfloat varray[] = {
-1.0f, -1.0f,
1.0f, 1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
-1.0f, -1.0f,
};
GLCHK(glVertexAttribPointer(mirror_shader.attribute_locations[0], 2, GL_FLOAT, GL_FALSE, 0, varray));
GLCHK(glUniform1f(mirror_shader.uniform_locations[1], offset));
GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
GLCHK(glDisableVertexAttribArray(mirror_shader.attribute_locations[0]));
GLCHK(glUseProgram(0));
return 0;
}
int mirror_open(RASPITEX_STATE *state)
{
state->ops.gl_init = mirror_init;
state->ops.redraw = mirror_redraw;
state->ops.update_texture = raspitexutil_update_texture;
return 0;
}

View File

@@ -0,0 +1,192 @@
/*
Copyright (c) 2013, Broadcom Europe Ltd
Copyright (c) 2013, Tim Gover
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "sobel.h"
#include "RaspiTex.h"
#include "RaspiTexUtil.h"
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
/* \file sobel.c
* Example code for implementing Sobel filter as GLSL shaders.
* The input image is a greyscale texture from the MMAL buffer Y plane.
*/
#define SOBEL_VSHADER_SOURCE \
"attribute vec2 vertex;\n" \
"varying vec2 texcoord;\n" \
"void main(void) {\n" \
" texcoord = 0.5 * (vertex + 1.0);\n" \
" gl_Position = vec4(vertex, 0.0, 1.0);\n" \
"}\n"
/* Example Sobel edge detct shader. The texture format for
* EGL_IMAGE_BRCM_MULTIMEDIA_Y is a one byte per pixel greyscale GL_LUMINANCE.
* If the output is to be fed into another image processing shader then it may
* be worth changing this code to take 4 input Y pixels and pack the result
* into a 32bpp RGBA pixel.
*/
#define SOBEL_FSHADER_SOURCE \
"#extension GL_OES_EGL_image_external : require\n" \
"uniform samplerExternalOES tex;\n" \
"varying vec2 texcoord;\n" \
"uniform vec2 tex_unit;\n" \
"void main(void) {\n" \
" float x = texcoord.x;\n" \
" float y = texcoord.y;\n" \
" float x1 = x - tex_unit.x;\n" \
" float y1 = y - tex_unit.y;\n" \
" float x2 = x + tex_unit.x;\n" \
" float y2 = y + tex_unit.y;\n" \
" vec4 p0 = texture2D(tex, vec2(x1, y1));\n" \
" vec4 p1 = texture2D(tex, vec2(x, y1));\n" \
" vec4 p2 = texture2D(tex, vec2(x2, y1));\n" \
" vec4 p3 = texture2D(tex, vec2(x1, y));\n" \
" /* vec4 p4 = texture2D(tex, vec2(x, y)); */\n" \
" vec4 p5 = texture2D(tex, vec2(x2, y));\n" \
" vec4 p6 = texture2D(tex, vec2(x1, y2));\n" \
" vec4 p7 = texture2D(tex, vec2(x, y2));\n" \
" vec4 p8 = texture2D(tex, vec2(x2, y2));\n" \
"\n" \
" vec4 v = p0 + (2.0 * p1) + p3 -p6 + (-2.0 * p7) + -p8;\n" \
" vec4 h = p0 + (2.0 * p3) + p7 -p2 + (-2.0 * p5) + -p8;\n" \
" gl_FragColor = sqrt(h*h + v*v);\n" \
" gl_FragColor.a = 1.0;\n" \
"}\n"
static GLfloat quad_varray[] = {
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f,
};
static GLuint quad_vbo;
static RASPITEXUTIL_SHADER_PROGRAM_T sobel_shader =
{
.vertex_source = SOBEL_VSHADER_SOURCE,
.fragment_source = SOBEL_FSHADER_SOURCE,
.uniform_names = {"tex", "tex_unit"},
.attribute_names = {"vertex"},
};
static const EGLint sobel_egl_config_attribs[] =
{
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
/**
* Initialisation of shader uniforms.
*
* @param width Width of the EGL image.
* @param width Height of the EGL image.
*/
static int shader_set_uniforms(RASPITEXUTIL_SHADER_PROGRAM_T *shader,
int width, int height)
{
GLCHK(glUseProgram(shader->program));
GLCHK(glUniform1i(shader->uniform_locations[0], 0)); // Texture unit
/* Dimensions of a single pixel in texture co-ordinates */
GLCHK(glUniform2f(shader->uniform_locations[1],
1.0 / (float) width, 1.0 / (float) height));
/* Enable attrib 0 as vertex array */
GLCHK(glEnableVertexAttribArray(shader->attribute_locations[0]));
return 0;
}
/**
* Creates the OpenGL ES 2.X context and builds the shaders.
* @param raspitex_state A pointer to the GL preview state.
* @return Zero if successful.
*/
static int sobel_init(RASPITEX_STATE *raspitex_state)
{
int rc = 0;
int width = raspitex_state->width;
int height = raspitex_state->height;
vcos_log_trace("%s", VCOS_FUNCTION);
raspitex_state->egl_config_attribs = sobel_egl_config_attribs;
rc = raspitexutil_gl_init_2_0(raspitex_state);
if (rc != 0)
goto end;
rc = raspitexutil_build_shader_program(&sobel_shader);
if (rc != 0)
goto end;
rc = shader_set_uniforms(&sobel_shader, width, height);
if (rc != 0)
goto end;
GLCHK(glGenBuffers(1, &quad_vbo));
GLCHK(glBindBuffer(GL_ARRAY_BUFFER, quad_vbo));
GLCHK(glBufferData(GL_ARRAY_BUFFER, sizeof(quad_varray), quad_varray, GL_STATIC_DRAW));
GLCHK(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
end:
return rc;
}
/* Redraws the scene with the latest luma buffer.
*
* @param raspitex_state A pointer to the GL preview state.
* @return Zero if successful.
*/
static int sobel_redraw(RASPITEX_STATE* state)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLCHK(glUseProgram(sobel_shader.program));
/* Bind the Y plane texture */
GLCHK(glActiveTexture(GL_TEXTURE0));
GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, state->y_texture));
GLCHK(glBindBuffer(GL_ARRAY_BUFFER, quad_vbo));
GLCHK(glEnableVertexAttribArray(sobel_shader.attribute_locations[0]));
GLCHK(glVertexAttribPointer(sobel_shader.attribute_locations[0], 2, GL_FLOAT, GL_FALSE, 0, 0));
GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
return 0;
}
int sobel_open(RASPITEX_STATE *state)
{
state->ops.gl_init = sobel_init;
state->ops.redraw = sobel_redraw;
state->ops.update_y_texture = raspitexutil_update_y_texture;
return 0;
}

View File

@@ -0,0 +1,37 @@
/*
Copyright (c) 2013, Broadcom Europe Ltd
Copyright (c) 2013, Tim Gover
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SOBEL_H
#define SOBEL_H
#include "RaspiTex.h"
int sobel_open(RASPITEX_STATE *state);
#endif /* SOBEL_H */

View File

@@ -116,5 +116,6 @@ int square_open(RASPITEX_STATE *state)
state->ops.gl_init = square_init; state->ops.gl_init = square_init;
state->ops.update_model = square_update_model; state->ops.update_model = square_update_model;
state->ops.redraw = square_redraw; state->ops.redraw = square_redraw;
state->ops.update_texture = raspitexutil_update_texture;
return 0; return 0;
} }

View File

@@ -305,11 +305,19 @@ end:
return rc; return rc;
} }
static void teapot_gl_term(RASPITEX_STATE *state) static void teapot_gl_term(RASPITEX_STATE *raspitex_state)
{ {
raspitexutil_gl_term(state); vcos_log_trace("%s:", VCOS_FUNCTION);
free(state->scene_state);
state->scene_state = NULL; TEAPOT_STATE_T *state = raspitex_state->scene_state;
if (state)
{
if (state->model)
unload_wavefront(state->model);
raspitexutil_gl_term(raspitex_state);
free(raspitex_state->scene_state);
raspitex_state->scene_state = NULL;
}
} }
int teapot_open(RASPITEX_STATE *raspitex_state) int teapot_open(RASPITEX_STATE *raspitex_state)
@@ -318,6 +326,7 @@ int teapot_open(RASPITEX_STATE *raspitex_state)
raspitex_state->ops.update_model = teapot_update_model; raspitex_state->ops.update_model = teapot_update_model;
raspitex_state->ops.redraw = teapot_redraw; raspitex_state->ops.redraw = teapot_redraw;
raspitex_state->ops.gl_term = teapot_gl_term; raspitex_state->ops.gl_term = teapot_gl_term;
raspitex_state->ops.update_texture = raspitexutil_update_texture;
return 0; return 0;
} }

View File

@@ -0,0 +1,145 @@
/*
Copyright (c) 2013, Broadcom Europe Ltd
Copyright (c) 2013, Tim Gover
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "yuv.h"
#include "RaspiTex.h"
#include "RaspiTexUtil.h"
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
/* Draw a scaled quad showing the the entire texture with the
* origin defined as an attribute */
static RASPITEXUTIL_SHADER_PROGRAM_T yuv_shader =
{
.vertex_source =
"attribute vec2 vertex;\n"
"attribute vec2 top_left;\n"
"varying vec2 texcoord;\n"
"void main(void) {\n"
" texcoord = vertex + vec2(0.0, 1.0);\n"
" gl_Position = vec4(top_left + vertex, 0.0, 1.0);\n"
"}\n",
.fragment_source =
"#extension GL_OES_EGL_image_external : require\n"
"uniform samplerExternalOES tex;\n"
"varying vec2 texcoord;\n"
"void main(void) {\n"
" gl_FragColor = texture2D(tex, texcoord);\n"
"}\n",
.uniform_names = {"tex"},
.attribute_names = {"vertex", "top_left"},
};
static GLfloat varray[] =
{
0.0f, 0.0f, 0.0f, -1.0f, 1.0f, -1.0f,
1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
};
static const EGLint yuv_egl_config_attribs[] =
{
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
/**
* Creates the OpenGL ES 2.X context and builds the shaders.
* @param raspitex_state A pointer to the GL preview state.
* @return Zero if successful.
*/
static int yuv_init(RASPITEX_STATE *state)
{
int rc;
state->egl_config_attribs = yuv_egl_config_attribs;
rc = raspitexutil_gl_init_2_0(state);
if (rc != 0)
goto end;
rc = raspitexutil_build_shader_program(&yuv_shader);
GLCHK(glUseProgram(yuv_shader.program));
GLCHK(glUniform1i(yuv_shader.uniform_locations[0], 0)); // tex unit
end:
return rc;
}
/**
* Draws a 2x2 grid with each shell showing the entire MMAL buffer from a
* different EGL image target.
*/
static int yuv_redraw(RASPITEX_STATE *raspitex_state)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLCHK(glUseProgram(yuv_shader.program));
GLCHK(glActiveTexture(GL_TEXTURE0));
GLCHK(glEnableVertexAttribArray(yuv_shader.attribute_locations[0]));
GLCHK(glVertexAttribPointer(yuv_shader.attribute_locations[0],
2, GL_FLOAT, GL_FALSE, 0, varray));
// Y plane
GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->y_texture));
GLCHK(glVertexAttrib2f(yuv_shader.attribute_locations[1], -1.0f, 1.0f));
GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
// U plane
GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->u_texture));
GLCHK(glVertexAttrib2f(yuv_shader.attribute_locations[1], 0.0f, 1.0f));
GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
// V plane
GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->v_texture));
GLCHK(glVertexAttrib2f(yuv_shader.attribute_locations[1], 0.0f, 0.0f));
GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
// RGB plane
GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->texture));
GLCHK(glVertexAttrib2f(yuv_shader.attribute_locations[1], -1.0f, 0.0f));
GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
GLCHK(glDisableVertexAttribArray(yuv_shader.attribute_locations[0]));
GLCHK(glUseProgram(0));
return 0;
}
int yuv_open(RASPITEX_STATE *state)
{
state->ops.gl_init = yuv_init;
state->ops.redraw = yuv_redraw;
state->ops.update_texture = raspitexutil_update_texture;
state->ops.update_y_texture = raspitexutil_update_y_texture;
state->ops.update_u_texture = raspitexutil_update_u_texture;
state->ops.update_v_texture = raspitexutil_update_v_texture;
return 0;
}

View File

@@ -0,0 +1,37 @@
/*
Copyright (c) 2013, Broadcom Europe Ltd
Copyright (c) 2013, Tim Gover
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef YUV_H
#define YUV_H
#include "RaspiTex.h"
int yuv_open(RASPITEX_STATE *state);
#endif /* YUV_H */

View File

@@ -1,251 +0,0 @@
/*
Copyright (c) 2013, Broadcom Europe Ltd
Copyright (c) 2013, Tim Gover
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "RaspiTex.h"
#include "RaspiTexUtil.h"
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#define SHADER_MAX_ATTRIBUTES 16
#define SHADER_MAX_UNIFORMS 16
/**
* Container for a GL texture.
*/
struct TEXTURE_T {
GLuint name;
GLuint width;
GLuint height;
};
/**
* Container for a simple vertex, fragment share with the names and locations.
*/
struct SHADER_PROGRAM_T {
const char *vertex_source;
const char *fragment_source;
const char *uniform_names[SHADER_MAX_UNIFORMS];
const char *attribute_names[SHADER_MAX_ATTRIBUTES];
GLint vs;
GLint fs;
GLint program;
/// The locations for uniforms defined in uniform_names
GLint uniform_locations[SHADER_MAX_UNIFORMS];
/// The locations for attributes defined in attribute_names
GLint attribute_locations[SHADER_MAX_ATTRIBUTES];
/// Optional texture information
struct TEXTURE_T tex;
};
/**
* Draws an external EGL image and applies a sine wave distortion to create
* a hall of mirrors effect.
*/
struct SHADER_PROGRAM_T picture_shader = {
.vertex_source =
"attribute vec2 vertex;\n"
"varying vec2 texcoord;"
"void main(void) {\n"
" texcoord = 0.5 * (vertex + 1.0);\n"
" gl_Position = vec4(vertex, 0.0, 1.0);\n"
"}\n",
.fragment_source =
"#extension GL_OES_EGL_image_external : require\n"
"uniform samplerExternalOES tex;\n"
"uniform float offset;\n"
"const float waves = 2.0;\n"
"varying vec2 texcoord;\n"
"void main(void) {\n"
" float x = texcoord.x + 0.05 * sin(offset + (texcoord.y * waves * 2.0 * 3.141592));\n"
" float y = texcoord.y + 0.05 * sin(offset + (texcoord.x * waves * 2.0 * 3.141592));\n"
" if (y < 1.0 && y > 0.0 && x < 1.0 && x > 0.0) {\n"
" vec2 pos = vec2(x, y);\n"
" gl_FragColor = texture2D(tex, pos);\n"
" }\n"
" else {\n"
" gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
" }\n"
"}\n",
.uniform_names = {"tex", "offset"},
.attribute_names = {"vertex"},
};
/**
* Utility for building shaders and configuring the attribute and locations.
* @return Zero if successful.
*/
static int buildShaderProgram(struct SHADER_PROGRAM_T *p)
{
GLint status;
int i = 0;
char log[1024];
int logLen = 0;
assert(p);
assert(p->vertex_source);
assert(p->fragment_source);
if (! (p && p->vertex_source && p->fragment_source))
goto fail;
p->vs = p->fs = 0;
GLCHK(p->vs = glCreateShader(GL_VERTEX_SHADER));
GLCHK(glShaderSource(p->vs, 1, &p->vertex_source, NULL));
GLCHK(glCompileShader(p->vs));
GLCHK(glGetShaderiv(p->vs, GL_COMPILE_STATUS, &status));
if (! status) {
glGetShaderInfoLog(p->vs, sizeof(log), &logLen, log);
vcos_log_trace("Program info log %s", log);
goto fail;
}
GLCHK(p->fs = glCreateShader(GL_FRAGMENT_SHADER));
GLCHK(glShaderSource(p->fs, 1, &p->fragment_source, NULL));
GLCHK(glCompileShader(p->fs));
GLCHK(glGetShaderiv(p->fs, GL_COMPILE_STATUS, &status));
if (! status) {
glGetShaderInfoLog(p->fs, sizeof(log), &logLen, log);
vcos_log_trace("Program info log %s", log);
goto fail;
}
GLCHK(p->program = glCreateProgram());
GLCHK(glAttachShader(p->program, p->vs));
GLCHK(glAttachShader(p->program, p->fs));
GLCHK(glLinkProgram(p->program));
GLCHK(glGetProgramiv(p->program, GL_LINK_STATUS, &status));
if (! status)
{
vcos_log_trace("Failed to link shader program");
glGetProgramInfoLog(p->program, sizeof(log), &logLen, log);
vcos_log_trace("Program info log %s", log);
goto fail;
}
for (i = 0; i < SHADER_MAX_ATTRIBUTES; ++i)
{
if (! p->attribute_names[i])
break;
GLCHK(p->attribute_locations[i] = glGetAttribLocation(p->program, p->attribute_names[i]));
if (p->attribute_locations[i] == -1)
{
vcos_log_trace("Failed to get location for attribute %s", p->attribute_names[i]);
goto fail;
}
else {
vcos_log_trace("Attribute for %s is %d", p->attribute_names[i], p->attribute_locations[i]);
}
}
for (i = 0; i < SHADER_MAX_UNIFORMS; ++i)
{
if (! p->uniform_names[i])
break;
GLCHK(p->uniform_locations[i] = glGetUniformLocation(p->program, p->uniform_names[i]));
if (p->uniform_locations[i] == -1)
{
vcos_log_trace("Failed to get location for uniform %s", p->uniform_names[i]);
goto fail;
}
else {
vcos_log_trace("Uniform for %s is %d", p->uniform_names[i], p->uniform_locations[i]);
}
}
return 0;
fail:
vcos_log_trace("%s: Failed to build shader program", __func__);
if (p)
{
glDeleteProgram(p->program);
glDeleteShader(p->fs);
glDeleteShader(p->vs);
}
return -1;
}
/**
* Creates the OpenGL ES 2.X context and builds the shaders.
* @param raspitex_state A pointer to the GL preview state.
* @return Zero if successful.
*/
static int mirror_init(RASPITEX_STATE *state)
{
int rc = raspitexutil_gl_init_2_0(state);
if (rc != 0)
goto end;
rc = buildShaderProgram(&picture_shader);
end:
return rc;
}
static int mirror_redraw(RASPITEX_STATE *raspitex_state) {
static float offset = 0.0;
// Start with a clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Bind the OES texture which is used to render the camera preview
glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->texture);
offset += 0.05;
GLCHK(glUseProgram(picture_shader.program));
GLCHK(glEnableVertexAttribArray(picture_shader.attribute_locations[0]));
GLfloat varray[] = {
-1.0f, -1.0f,
1.0f, 1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
-1.0f, -1.0f,
};
GLCHK(glVertexAttribPointer(picture_shader.attribute_locations[0], 2, GL_FLOAT, GL_FALSE, 0, varray));
GLCHK(glUniform1f(picture_shader.uniform_locations[1], offset));
GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
GLCHK(glDisableVertexAttribArray(picture_shader.attribute_locations[0]));
GLCHK(glUseProgram(0));
return 0;
}
int mirror_open(RASPITEX_STATE *state)
{
state->ops.gl_init = mirror_init;
state->ops.redraw = mirror_redraw;
return 0;
}

View File

@@ -0,0 +1,113 @@
/*
Copyright (c) 2013, Broadcom Europe Ltd
Copyright (c) 2013, Tim Gover
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "tga.h"
#include <string.h>
#define TGA_WRITE(FP, F) \
if (fwrite((&F), sizeof(F), 1, (FP)) != 1) goto write_fail
int write_tga(FILE *fp, int width, int height,
uint8_t *buffer, size_t buffer_size)
{
struct tga_header header;
memset(&header, 0, sizeof(header));
header.image_type = tga_type_true_color;
header.image_info.width = width;
header.image_info.y_origin = height;
header.image_info.height = height;
header.image_info.bpp = 32;
TGA_WRITE(fp, header.id_length);
TGA_WRITE(fp, header.color_map_type);
TGA_WRITE(fp, header.image_type);
TGA_WRITE(fp, header.colormap_info.offset);
TGA_WRITE(fp, header.colormap_info.length);
TGA_WRITE(fp, header.colormap_info.bpp);
TGA_WRITE(fp, header.image_info.x_origin);
TGA_WRITE(fp, header.image_info.y_origin);
TGA_WRITE(fp, header.image_info.width);
TGA_WRITE(fp, header.image_info.height);
TGA_WRITE(fp, header.image_info.bpp);
TGA_WRITE(fp, header.image_info.descriptor);
if (fwrite(buffer, 1, buffer_size, fp) != buffer_size)
goto write_fail;
return 0;
write_fail:
return -1;
}
#define TGA_READ(FP, F) if (fread((&F), sizeof(F), 1, (FP)) != 1) goto read_fail
static int read_header(FILE *fp, struct tga_header *header) {
TGA_READ(fp, header->id_length);
TGA_READ(fp, header->color_map_type);
TGA_READ(fp, header->image_type);
TGA_READ(fp, header->colormap_info.offset);
TGA_READ(fp, header->colormap_info.length);
TGA_READ(fp, header->colormap_info.bpp);
TGA_READ(fp, header->image_info.x_origin);
TGA_READ(fp, header->image_info.y_origin);
TGA_READ(fp, header->image_info.width);
TGA_READ(fp, header->image_info.height);
TGA_READ(fp, header->image_info.bpp);
TGA_READ(fp, header->image_info.descriptor);
return 0;
read_fail:
return -1;
}
unsigned char *load_tga(const char *filename, struct tga_header *header) {
unsigned char *image = NULL;
FILE *fp = fopen(filename, "r");
if (fp) {
if(read_header(fp, header) == 0) {
if (header->image_type == tga_type_true_color &&
(header->image_info.bpp == 24 ||
header->image_info.bpp == 32)) {
int buflen = header->image_info.width *
header->image_info.height * (header->image_info.bpp / 8);
image = malloc(buflen);
if (image) {
if (header->id_length)
fseek(fp, SEEK_CUR, header->id_length);
if (fread(image, 1, buflen, fp) != buflen) {
free(image);
image = NULL;
}
}
}
}
fclose(fp);
}
return image;
}

View File

@@ -0,0 +1,73 @@
/*
Copyright (c) 2013, Broadcom Europe Ltd
Copyright (c) 2013, Tim Gover
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TGA_H
#define TGA_H
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
typedef enum {
tga_type_null = 0,
tga_type_color_map = 1,
tga_type_true_color = 2,
tga_type_grayscale = 3,
tga_type_rle_color_map = 9,
tga_type_rle_true_color = 10,
tga_type_rle_grayscale = 11,
} tga_image_type;
struct tga_colormap_info {
unsigned short offset;
unsigned short length;
unsigned char bpp;
};
struct tga_image_info {
unsigned short x_origin;
unsigned short y_origin;
unsigned short width;
unsigned short height;
unsigned char bpp;
unsigned char descriptor;
};
struct tga_header {
unsigned char id_length;
unsigned char color_map_type;
unsigned char image_type;
struct tga_colormap_info colormap_info;
struct tga_image_info image_info;
};
int write_tga(FILE* fp, int width, int height, uint8_t *buffer, size_t buffer_size);
unsigned char *load_tga(const char *filename, struct tga_header *header);
#endif /* TGA_H */

View File

@@ -81,6 +81,9 @@ EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx
|| target == EGL_IMAGE_BRCM_RAW_PIXELS || target == EGL_IMAGE_BRCM_RAW_PIXELS
#endif #endif
|| target == EGL_IMAGE_BRCM_MULTIMEDIA || target == EGL_IMAGE_BRCM_MULTIMEDIA
|| target == EGL_IMAGE_BRCM_MULTIMEDIA_Y
|| target == EGL_IMAGE_BRCM_MULTIMEDIA_U
|| target == EGL_IMAGE_BRCM_MULTIMEDIA_V
|| target == EGL_IMAGE_BRCM_DUPLICATE || target == EGL_IMAGE_BRCM_DUPLICATE
) { ) {
context = NULL; context = NULL;
@@ -241,6 +244,18 @@ EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx
buf[0] = (uint32_t)buffer; buf[0] = (uint32_t)buffer;
vcos_log_trace("%s: converting buffer handle %u to EGL_IMAGE_BRCM_MULTIMEDIA", vcos_log_trace("%s: converting buffer handle %u to EGL_IMAGE_BRCM_MULTIMEDIA",
__FUNCTION__, buf[0]); __FUNCTION__, buf[0]);
} else if (target == EGL_IMAGE_BRCM_MULTIMEDIA_Y) {
buf[0] = (uint32_t)buffer;
vcos_log_trace("%s: converting buffer handle %u to EGL_IMAGE_BRCM_MULTIMEDIA_Y",
__FUNCTION__, buf[0]);
} else if (target == EGL_IMAGE_BRCM_MULTIMEDIA_U) {
buf[0] = (uint32_t)buffer;
vcos_log_trace("%s: converting buffer handle %u to EGL_IMAGE_BRCM_MULTIMEDIA_U",
__FUNCTION__, buf[0]);
} else if (target == EGL_IMAGE_BRCM_MULTIMEDIA_V) {
buf[0] = (uint32_t)buffer;
vcos_log_trace("%s: converting buffer handle %u to EGL_IMAGE_BRCM_MULTIMEDIA_V",
__FUNCTION__, buf[0]);
#endif #endif
} else { } else {
vcos_log_trace("%s:target type %x buffer %p handled on server", __FUNCTION__, target, buffer); vcos_log_trace("%s:target type %x buffer %p handled on server", __FUNCTION__, target, buffer);

View File

@@ -38,6 +38,13 @@ extern "C" {
#define EGL_IMAGE_BRCM_MULTIMEDIA 0x99930B2 #define EGL_IMAGE_BRCM_MULTIMEDIA 0x99930B2
#define EGL_IMAGE_BRCM_DUPLICATE 0x99930B3 /* a new EGL Image pointing at the same underlying object */ #define EGL_IMAGE_BRCM_DUPLICATE 0x99930B3 /* a new EGL Image pointing at the same underlying object */
#define EGL_IMAGE_BRCM_RAW_PIXELS 0x99930B4 /* Raw YUV multimedia pixels */ #define EGL_IMAGE_BRCM_RAW_PIXELS 0x99930B4 /* Raw YUV multimedia pixels */
/* Fastpath for creating greyscale textures from a single plane of a
* MMAL opaque buffers. */
#define EGL_IMAGE_BRCM_MULTIMEDIA_Y 0x99930C0
#define EGL_IMAGE_BRCM_MULTIMEDIA_U 0x99930C1
#define EGL_IMAGE_BRCM_MULTIMEDIA_V 0x99930C2
#ifndef EGL_BRCM_sane_choose_config #ifndef EGL_BRCM_sane_choose_config
#define EGL_BRCM_sane_choose_config 1 #define EGL_BRCM_sane_choose_config 1
#endif #endif

View File

@@ -112,6 +112,9 @@ typedef enum
VC_IMAGE_YUV420SP, /* Y as a plane, then UV byte interleaved in plane with with same pitch, half height */ VC_IMAGE_YUV420SP, /* Y as a plane, then UV byte interleaved in plane with with same pitch, half height */
VC_IMAGE_YUV444PLANAR, /* Y, U, & V planes separately 4:4:4 */ VC_IMAGE_YUV444PLANAR, /* Y, U, & V planes separately 4:4:4 */
VC_IMAGE_TF_U8, /* T-format 8-bit U - same as TF_Y8 buf from U plane */
VC_IMAGE_TF_V8, /* T-format 8-bit U - same as TF_Y8 buf from V plane */
VC_IMAGE_MAX, //bounds for error checking VC_IMAGE_MAX, //bounds for error checking
VC_IMAGE_FORCE_ENUM_16BIT = 0xffff, VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,

View File

@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "interface/khronos/include/EGL/eglext.h" #include "interface/khronos/include/EGL/eglext.h"
#include "middleware/khronos/egl/egl_server.h" #include "middleware/khronos/egl/egl_server.h"
#include "middleware/imageconv/imageconv.h" #include "middleware/imageconv/imageconv.h"
#include "vcinclude/vc_image_types.h"
typedef struct EGL_IMAGE_T { typedef struct EGL_IMAGE_T {
@@ -56,6 +57,8 @@ typedef struct EGL_IMAGE_T {
*/ */
MEM_HANDLE_T src; MEM_HANDLE_T src;
const IMAGE_CONVERT_CLASS_T *convert; const IMAGE_CONVERT_CLASS_T *convert;
KHRN_IMAGE_FORMAT_T conv_khrn_format;
VC_IMAGE_TYPE_T conv_vc_format;
uint32_t src_updated; uint32_t src_updated;
uint32_t src_converted; uint32_t src_converted;
} external; } external;