mirror of
https://github.com/raspberrypi/userland.git
synced 2025-12-06 04:49:12 +00:00
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:
@@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 2.8)
|
||||
project(vmcs_host_apps)
|
||||
|
||||
set(BUILD_MMAL TRUE)
|
||||
set(BUILD_MMAL_COMPONENTS FALSE)
|
||||
if (ALL_APPS)
|
||||
set(BUILD_MMAL_APPS TRUE)
|
||||
else()
|
||||
@@ -70,6 +69,11 @@ if(BUILD_MMAL_APPS)
|
||||
add_subdirectory(containers)
|
||||
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)
|
||||
|
||||
# 3d demo code
|
||||
|
||||
@@ -246,6 +246,8 @@ extern "C" {
|
||||
case VC_IMAGE_TF_PAL4: \
|
||||
case VC_IMAGE_TF_ETC1: \
|
||||
case VC_IMAGE_TF_Y8: \
|
||||
case VC_IMAGE_TF_U8: \
|
||||
case VC_IMAGE_TF_V8: \
|
||||
case VC_IMAGE_TF_A8: \
|
||||
case VC_IMAGE_TF_SHORT: \
|
||||
case VC_IMAGE_TF_1BPP
|
||||
|
||||
@@ -4,13 +4,29 @@
|
||||
SET(COMPILE_DEFINITIONS -Werror)
|
||||
|
||||
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)
|
||||
add_executable(raspiyuv RaspiCamControl.c RaspiCLI.c RaspiPreview.c RaspiStillYUV.c)
|
||||
add_executable(raspivid RaspiCamControl.c RaspiCLI.c RaspiPreview.c RaspiVid.c)
|
||||
set (GL_SCENE_SOURCES
|
||||
gl_scenes/models.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)
|
||||
target_link_libraries(raspiyuv mmal_core mmal_util mmal_vc_client vcos bcm_host)
|
||||
target_link_libraries(raspivid mmal_core mmal_util mmal_vc_client vcos bcm_host)
|
||||
set (COMMON_SOURCES
|
||||
RaspiCamControl.c
|
||||
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)
|
||||
|
||||
@@ -134,6 +134,7 @@ typedef struct
|
||||
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 useGL; /// Render preview using OpenGL
|
||||
int glCapture; /// Save the GL frame-buffer instead of camera output
|
||||
|
||||
RASPIPREVIEW_PARAMETERS preview_parameters; /// Preview 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 CommandSignal 16
|
||||
#define CommandGL 17
|
||||
#define CommandGLCapture 18
|
||||
|
||||
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},
|
||||
{ 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},
|
||||
{ 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]);
|
||||
@@ -276,6 +279,7 @@ static void default_status(RASPISTILL_STATE *state)
|
||||
state->fullResPreview = 0;
|
||||
state->frameNextMethod = FRAME_NEXT_SINGLE;
|
||||
state->useGL = 0;
|
||||
state->glCapture = 0;
|
||||
|
||||
// Setup preview window defaults
|
||||
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;
|
||||
break;
|
||||
|
||||
case CommandGLCapture:
|
||||
state->glCapture = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
// 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.height = state->preview_parameters.previewWindow.height;
|
||||
}
|
||||
state->raspitex_state.opacity = state->preview_parameters.opacity;
|
||||
state->raspitex_state.verbose = state->verbose;
|
||||
/* Also pass the preview information through so GL renderer can determine
|
||||
* 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)
|
||||
{
|
||||
@@ -1449,7 +1463,37 @@ static int wait_for_next_frame(RASPISTILL_STATE *state, int *frame)
|
||||
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
|
||||
@@ -1649,7 +1693,15 @@ int main(int argc, const char **argv)
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -1725,32 +1777,8 @@ int main(int argc, const char **argv)
|
||||
|
||||
if (output_file != stdout)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
rename_file(&state, output_file, final_filename, use_filename, frame);
|
||||
}
|
||||
// Disable encoder output port
|
||||
status = mmal_port_disable(encoder_output_port);
|
||||
}
|
||||
|
||||
@@ -42,10 +42,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "interface/mmal/mmal_buffer.h"
|
||||
#include "interface/mmal/util/mmal_util.h"
|
||||
#include "interface/mmal/util/mmal_util_params.h"
|
||||
#include "tga.h"
|
||||
|
||||
#include "mirror.h"
|
||||
#include "square.h"
|
||||
#include "teapot.h"
|
||||
#include "gl_scenes/mirror.h"
|
||||
#include "gl_scenes/sobel.h"
|
||||
#include "gl_scenes/square.h"
|
||||
#include "gl_scenes/teapot.h"
|
||||
#include "gl_scenes/yuv.h"
|
||||
|
||||
/**
|
||||
* \file RaspiTex.c
|
||||
@@ -94,7 +97,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
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 },
|
||||
};
|
||||
|
||||
@@ -152,6 +155,12 @@ int raspitex_parse_cmdline(RASPITEX_STATE *state,
|
||||
state->scene_id = RASPITEX_SCENE_TEAPOT;
|
||||
else if (strcmp(arg2, "mirror") == 0)
|
||||
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;
|
||||
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
|
||||
* preview texture is updated first.
|
||||
@@ -217,15 +271,48 @@ static int raspitex_draw(RASPITEX_STATE *state, MMAL_BUFFER_HEADER_T *buf)
|
||||
if (buf)
|
||||
{
|
||||
/* Update the texture to the new viewfinder image which should */
|
||||
rc = state->ops.update_texture(state, (EGLClientBuffer) buf->data);
|
||||
if (rc != 0)
|
||||
if (state->ops.update_texture)
|
||||
{
|
||||
vcos_log_error("%s: Failed to update texture", VCOS_FUNCTION);
|
||||
goto end;
|
||||
rc = state->ops.update_texture(state, (EGLClientBuffer) buf->data);
|
||||
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)
|
||||
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 */
|
||||
if (state->preview_egl_image != EGL_NO_IMAGE_KHR)
|
||||
if (check_egl_image(state) == 0)
|
||||
{
|
||||
rc = state->ops.update_model(state);
|
||||
if (rc != 0)
|
||||
@@ -243,9 +330,15 @@ static int raspitex_draw(RASPITEX_STATE *state, MMAL_BUFFER_HEADER_T *buf)
|
||||
if (rc != 0)
|
||||
goto end;
|
||||
|
||||
raspitex_do_capture(state);
|
||||
|
||||
eglSwapBuffers(state->display, state->surface);
|
||||
update_fps();
|
||||
}
|
||||
else
|
||||
{
|
||||
// vcos_log_trace("%s: No preview image", VCOS_FUNCTION);
|
||||
}
|
||||
|
||||
end:
|
||||
return rc;
|
||||
@@ -354,13 +447,13 @@ static void preview_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
|
||||
|
||||
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;
|
||||
mmal_buffer_header_release(buf);
|
||||
}
|
||||
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);
|
||||
}
|
||||
else
|
||||
@@ -450,13 +543,13 @@ end:
|
||||
return (status == MMAL_SUCCESS ? 0 : -1);
|
||||
}
|
||||
|
||||
|
||||
/* Initialises GL preview state and creates the dispmanx native window.
|
||||
* @param state Pointer to the GL preview state.
|
||||
* @return Zero if successful.
|
||||
*/
|
||||
int raspitex_init(RASPITEX_STATE *state)
|
||||
{
|
||||
VCOS_STATUS_T status;
|
||||
int rc;
|
||||
vcos_init();
|
||||
|
||||
@@ -465,6 +558,16 @@ int raspitex_init(RASPITEX_STATE *state)
|
||||
state->verbose ? VCOS_LOG_INFO : VCOS_LOG_WARN);
|
||||
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)
|
||||
{
|
||||
case RASPITEX_SCENE_SQUARE:
|
||||
@@ -476,14 +579,24 @@ int raspitex_init(RASPITEX_STATE *state)
|
||||
case RASPITEX_SCENE_TEAPOT:
|
||||
rc = teapot_open(state);
|
||||
break;
|
||||
case RASPITEX_SCENE_YUV:
|
||||
rc = yuv_open(state);
|
||||
break;
|
||||
case RASPITEX_SCENE_SOBEL:
|
||||
rc = sobel_open(state);
|
||||
break;
|
||||
default:
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
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.
|
||||
@@ -503,8 +616,15 @@ void raspitex_destroy(RASPITEX_STATE *state)
|
||||
mmal_queue_destroy(state->preview_queue);
|
||||
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.
|
||||
@@ -516,10 +636,15 @@ void raspitex_destroy(RASPITEX_STATE *state)
|
||||
void raspitex_set_defaults(RASPITEX_STATE *state)
|
||||
{
|
||||
memset(state, 0, sizeof(*state));
|
||||
state->version_major = RASPITEX_VERSION_MAJOR;
|
||||
state->version_minor = RASPITEX_VERSION_MINOR;
|
||||
state->display = EGL_NO_DISPLAY;
|
||||
state->surface = EGL_NO_SURFACE;
|
||||
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->width = DEFAULT_WIDTH;
|
||||
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.gl_init = raspitexutil_gl_init_1_0;
|
||||
state->ops.update_texture = raspitexutil_update_texture;
|
||||
state->ops.update_model = raspitexutil_update_model;
|
||||
state->ops.redraw = raspitexutil_redraw;
|
||||
state->ops.capture = raspitexutil_capture_bgra;
|
||||
state->ops.gl_term = raspitexutil_gl_term;
|
||||
state->ops.destroy_native_window = raspitexutil_destroy_native_window;
|
||||
state->ops.close = raspitexutil_close;
|
||||
@@ -569,3 +694,55 @@ int raspitex_start(RASPITEX_STATE *state)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#ifndef RASPITEX_H_
|
||||
#define RASPITEX_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.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/mmal/mmal.h"
|
||||
|
||||
#define RASPITEX_VERSION_MAJOR 1
|
||||
#define RASPITEX_VERSION_MINOR 0
|
||||
|
||||
typedef enum {
|
||||
RASPITEX_SCENE_SQUARE = 0,
|
||||
RASPITEX_SCENE_MIRROR,
|
||||
RASPITEX_SCENE_TEAPOT
|
||||
RASPITEX_SCENE_TEAPOT,
|
||||
RASPITEX_SCENE_YUV,
|
||||
RASPITEX_SCENE_SOBEL,
|
||||
|
||||
} RASPITEX_SCENE_T;
|
||||
|
||||
@@ -54,15 +60,33 @@ typedef struct RASPITEX_SCENE_OPS
|
||||
/// Creates EGL surface for native window
|
||||
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);
|
||||
|
||||
/// 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
|
||||
int (*update_model)(struct RASPITEX_STATE *state);
|
||||
|
||||
/// Draw the scene - called after update_model
|
||||
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
|
||||
void (*gl_term)(struct RASPITEX_STATE *state);
|
||||
|
||||
@@ -73,18 +97,45 @@ typedef struct RASPITEX_SCENE_OPS
|
||||
void (*close)(struct RASPITEX_STATE *state);
|
||||
} 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
|
||||
* preview window.
|
||||
*/
|
||||
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_POOL_T *preview_pool; /// Pool for storing opaque buffer handles
|
||||
MMAL_QUEUE_T *preview_queue; /// Queue preview buffers to display in order
|
||||
VCOS_THREAD_T preview_thread; /// Preview worker / GL rendering thread
|
||||
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 */
|
||||
int32_t x; /// x-offset in pixels
|
||||
int32_t y; /// y-offset in pixels
|
||||
@@ -102,16 +153,27 @@ typedef struct RASPITEX_STATE
|
||||
EGLDisplay display; /// The current EGL display
|
||||
EGLSurface surface; /// The current EGL surface
|
||||
EGLContext context; /// The current EGL context
|
||||
const EGLint *egl_config_attribs; /// GL scenes preferred EGL configuration
|
||||
|
||||
GLuint texture; /// Texture name for the preview texture
|
||||
EGLImageKHR preview_egl_image; /// The current preview EGL image
|
||||
MMAL_BUFFER_HEADER_T *preview_buf; /// MMAL buffer currently bound to texture
|
||||
GLuint texture; /// Name for the preview texture
|
||||
EGLImageKHR egl_image; /// The current preview EGL image
|
||||
|
||||
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_OPS ops; /// The interface for the current scene
|
||||
void *scene_state; /// Pointer to scene specific data
|
||||
int verbose; /// Log FPS
|
||||
|
||||
RASPITEX_CAPTURE capture; /// Frame-buffer capture state
|
||||
|
||||
} RASPITEX_STATE;
|
||||
|
||||
int raspitex_init(RASPITEX_STATE *state);
|
||||
@@ -124,5 +186,6 @@ int raspitex_configure_preview_port(RASPITEX_STATE *state,
|
||||
void raspitex_display_help();
|
||||
int raspitex_parse_cmdline(RASPITEX_STATE *state,
|
||||
const char *arg1, const char *arg2);
|
||||
int raspitex_capture(RASPITEX_STATE *state, FILE* output_file);
|
||||
|
||||
#endif /* RASPITEX_H_ */
|
||||
|
||||
@@ -29,6 +29,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "RaspiTexUtil.h"
|
||||
#include "RaspiTex.h"
|
||||
#include <bcm_host.h>
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
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);
|
||||
|
||||
/* Delete texture name */
|
||||
/* Delete OES textures */
|
||||
glDeleteTextures(1, &raspitex_state->texture);
|
||||
eglDestroyImageKHR(raspitex_state->display, raspitex_state->preview_egl_image);
|
||||
raspitex_state->preview_egl_image = EGL_NO_IMAGE_KHR;
|
||||
eglDestroyImageKHR(raspitex_state->display, raspitex_state->egl_image);
|
||||
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 */
|
||||
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.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,
|
||||
src_rect.x, src_rect.y, src_rect.width, src_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);
|
||||
if (raspitex_state->disp == DISPMANX_NO_HANDLE)
|
||||
{
|
||||
@@ -208,6 +221,19 @@ error:
|
||||
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.
|
||||
* @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 rc;
|
||||
const EGLint* attribs = raspitex_state->egl_config_attribs;
|
||||
|
||||
const EGLint attribs[] =
|
||||
const EGLint default_attribs[] =
|
||||
{
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
@@ -234,13 +261,15 @@ int raspitexutil_gl_init_1_0(RASPITEX_STATE *raspitex_state)
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
vcos_log_trace("%s", VCOS_FUNCTION);
|
||||
if (! attribs)
|
||||
attribs = default_attribs;
|
||||
|
||||
rc = raspitexutil_gl_common(raspitex_state, attribs, context_attribs);
|
||||
if (rc != 0)
|
||||
goto end;
|
||||
|
||||
GLCHK(glEnable(GL_TEXTURE_EXTERNAL_OES));
|
||||
GLCHK(glGenTextures(1, &raspitex_state->texture));
|
||||
rc = raspitexutil_create_textures(raspitex_state);
|
||||
|
||||
end:
|
||||
return rc;
|
||||
@@ -254,14 +283,16 @@ end:
|
||||
int raspitexutil_gl_init_2_0(RASPITEX_STATE *raspitex_state)
|
||||
{
|
||||
int rc;
|
||||
const EGLint attribs[] =
|
||||
const EGLint* attribs = raspitex_state->egl_config_attribs;;
|
||||
|
||||
const EGLint default_attribs[] =
|
||||
{
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_ALPHA_SIZE, 8,
|
||||
EGL_DEPTH_SIZE, 16,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
@@ -271,44 +302,102 @@ int raspitexutil_gl_init_2_0(RASPITEX_STATE *raspitex_state)
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
if (! attribs)
|
||||
attribs = default_attribs;
|
||||
|
||||
vcos_log_trace("%s", VCOS_FUNCTION);
|
||||
rc = raspitexutil_gl_common(raspitex_state, attribs, context_attribs);
|
||||
if (rc != 0)
|
||||
goto end;
|
||||
GLCHK(glGenTextures(1, &raspitex_state->texture));
|
||||
|
||||
rc = raspitexutil_create_textures(raspitex_state);
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the viewfinder texture whenever a new viewfinder MMAL buffer
|
||||
* is available.
|
||||
* Advances the texture and EGL image to the next MMAL buffer.
|
||||
*
|
||||
* @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 mm_buf The EGL client buffer (mmal opaque buffer) that is
|
||||
* used to create the EGL Image for the preview texture.
|
||||
* @param mm_buf The MMAL buffer.
|
||||
* @return Zero if successful.
|
||||
*/
|
||||
int raspitexutil_update_texture(RASPITEX_STATE *raspitex_state,
|
||||
EGLClientBuffer mm_buf)
|
||||
{
|
||||
// vcos_log_trace("%s: mm_buf %u", VCOS_FUNCTION, (unsigned) mm_buf);
|
||||
if (raspitex_state->preview_egl_image != EGL_NO_IMAGE_KHR)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
return raspitexutil_do_update_texture(raspitex_state->display,
|
||||
EGL_IMAGE_BRCM_MULTIMEDIA, mm_buf,
|
||||
&raspitex_state->texture, &raspitex_state->egl_image);
|
||||
}
|
||||
|
||||
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,
|
||||
raspitex_state->preview_egl_image));
|
||||
/**
|
||||
* Updates the U 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_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#ifndef RASPITEX_UTIL_H
|
||||
#define RASPITEX_UTIL_H
|
||||
#ifndef RASPITEX_UTIL_H_
|
||||
#define RASPITEX_UTIL_H_
|
||||
|
||||
#define VCOS_LOG_CATEGORY (&raspitex_log_category)
|
||||
#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;
|
||||
|
||||
#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 */
|
||||
//#define CHECK_GL_ERRORS
|
||||
#if defined(CHECK_GL_ERRORS)
|
||||
@@ -50,7 +78,7 @@ do { \
|
||||
X; \
|
||||
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); \
|
||||
exit(err); \
|
||||
} \
|
||||
@@ -68,8 +96,21 @@ int raspitexutil_update_model(RASPITEX_STATE* raspitex_state);
|
||||
int raspitexutil_redraw(RASPITEX_STATE* raspitex_state);
|
||||
void raspitexutil_gl_term(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,
|
||||
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);
|
||||
|
||||
#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_ */
|
||||
|
||||
123
host_applications/linux/apps/raspicam/gl_scenes/mirror.c
Normal file
123
host_applications/linux/apps/raspicam/gl_scenes/mirror.c
Normal 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;
|
||||
}
|
||||
192
host_applications/linux/apps/raspicam/gl_scenes/sobel.c
Normal file
192
host_applications/linux/apps/raspicam/gl_scenes/sobel.c
Normal 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;
|
||||
}
|
||||
37
host_applications/linux/apps/raspicam/gl_scenes/sobel.h
Normal file
37
host_applications/linux/apps/raspicam/gl_scenes/sobel.h
Normal 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 */
|
||||
@@ -116,5 +116,6 @@ int square_open(RASPITEX_STATE *state)
|
||||
state->ops.gl_init = square_init;
|
||||
state->ops.update_model = square_update_model;
|
||||
state->ops.redraw = square_redraw;
|
||||
state->ops.update_texture = raspitexutil_update_texture;
|
||||
return 0;
|
||||
}
|
||||
@@ -305,11 +305,19 @@ end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void teapot_gl_term(RASPITEX_STATE *state)
|
||||
static void teapot_gl_term(RASPITEX_STATE *raspitex_state)
|
||||
{
|
||||
raspitexutil_gl_term(state);
|
||||
free(state->scene_state);
|
||||
state->scene_state = NULL;
|
||||
vcos_log_trace("%s:", VCOS_FUNCTION);
|
||||
|
||||
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)
|
||||
@@ -318,6 +326,7 @@ int teapot_open(RASPITEX_STATE *raspitex_state)
|
||||
raspitex_state->ops.update_model = teapot_update_model;
|
||||
raspitex_state->ops.redraw = teapot_redraw;
|
||||
raspitex_state->ops.gl_term = teapot_gl_term;
|
||||
raspitex_state->ops.update_texture = raspitexutil_update_texture;
|
||||
return 0;
|
||||
}
|
||||
|
||||
145
host_applications/linux/apps/raspicam/gl_scenes/yuv.c
Normal file
145
host_applications/linux/apps/raspicam/gl_scenes/yuv.c
Normal 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;
|
||||
}
|
||||
37
host_applications/linux/apps/raspicam/gl_scenes/yuv.h
Normal file
37
host_applications/linux/apps/raspicam/gl_scenes/yuv.h
Normal 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 */
|
||||
@@ -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;
|
||||
}
|
||||
113
host_applications/linux/apps/raspicam/tga.c
Normal file
113
host_applications/linux/apps/raspicam/tga.c
Normal 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;
|
||||
}
|
||||
73
host_applications/linux/apps/raspicam/tga.h
Normal file
73
host_applications/linux/apps/raspicam/tga.h
Normal 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 */
|
||||
@@ -81,6 +81,9 @@ EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx
|
||||
|| target == EGL_IMAGE_BRCM_RAW_PIXELS
|
||||
#endif
|
||||
|| 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
|
||||
) {
|
||||
context = NULL;
|
||||
@@ -241,6 +244,18 @@ EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx
|
||||
buf[0] = (uint32_t)buffer;
|
||||
vcos_log_trace("%s: converting buffer handle %u to EGL_IMAGE_BRCM_MULTIMEDIA",
|
||||
__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
|
||||
} else {
|
||||
vcos_log_trace("%s:target type %x buffer %p handled on server", __FUNCTION__, target, buffer);
|
||||
|
||||
@@ -38,6 +38,13 @@ extern "C" {
|
||||
#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_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
|
||||
#define EGL_BRCM_sane_choose_config 1
|
||||
#endif
|
||||
|
||||
@@ -113,6 +113,9 @@ typedef enum
|
||||
|
||||
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_FORCE_ENUM_16BIT = 0xffff,
|
||||
} VC_IMAGE_TYPE_T;
|
||||
|
||||
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "interface/khronos/include/EGL/eglext.h"
|
||||
#include "middleware/khronos/egl/egl_server.h"
|
||||
#include "middleware/imageconv/imageconv.h"
|
||||
#include "vcinclude/vc_image_types.h"
|
||||
|
||||
|
||||
typedef struct EGL_IMAGE_T {
|
||||
@@ -56,6 +57,8 @@ typedef struct EGL_IMAGE_T {
|
||||
*/
|
||||
MEM_HANDLE_T src;
|
||||
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_converted;
|
||||
} external;
|
||||
|
||||
Reference in New Issue
Block a user