diff --git a/README.md b/README.md index daf7c6a..3bda179 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ when previewing. * `width=640` and `height=480` the resolution to use for the sensor * `rate=15` the refresh rate in fps to use for the sensor -* `fmt=BGGR8` sets the pixel and bus formats used when capturing from the sensor, only BGGR8 is fully supported +* `fmt=BGGR8` sets the pixel and bus formats used when capturing from the sensor. # Post processing diff --git a/data/debayer.frag b/data/debayer.frag index e7583eb..bf3d042 100644 --- a/data/debayer.frag +++ b/data/debayer.frag @@ -44,9 +44,15 @@ main() texture2D(texture, bottom_right_uv).r); #endif - // Assume BGGR for now. Currently this just takes 3 of the four samples - // for each pixel, there's room here to do some better debayering. +#if defined(CFA_BGGR) vec3 color = vec3(samples.w, (samples.y + samples.z) / 2.0, samples.x); +#elif defined(CFA_GBRG) + vec3 color = vec3(samples.z, (samples.x + samples.w) / 2.0, samples.y); +#elif defined(CFA_GRBG) + vec3 color = vec3(samples.y, (samples.x + samples.w) / 2.0, samples.z); +#else + vec3 color = vec3(samples.x, (samples.y + samples.z) / 2.0, samples.w); +#endif // Some crude blacklevel correction to make the preview a bit nicer, this // should be an uniform diff --git a/src/camera.c b/src/camera.c index 7800304..0c3e7f0 100644 --- a/src/camera.c +++ b/src/camera.c @@ -144,6 +144,38 @@ mp_pixel_format_pixel_depth(MPPixelFormat pixel_format) } } +const char * +mp_pixel_format_cfa(MPPixelFormat pixel_format) +{ + g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0); + switch (pixel_format) { + case MP_PIXEL_FMT_BGGR8: + case MP_PIXEL_FMT_BGGR10P: + return "BGGR"; + break; + case MP_PIXEL_FMT_GBRG8: + case MP_PIXEL_FMT_GBRG10P: + return "GBRG"; + break; + case MP_PIXEL_FMT_GRBG8: + case MP_PIXEL_FMT_GRBG10P: + return "GRBG"; + break; + case MP_PIXEL_FMT_RGGB8: + case MP_PIXEL_FMT_RGGB10P: + return "RGGB"; + break; + case MP_PIXEL_FMT_UYVY: + return "UYUV"; + break; + case MP_PIXEL_FMT_YUYV: + return "YUYV"; + break; + default: + return "unsupported"; + } +} + uint32_t mp_pixel_format_width_to_bytes(MPPixelFormat pixel_format, uint32_t width) { diff --git a/src/camera.h b/src/camera.h index 5b8dc12..60fb70f 100644 --- a/src/camera.h +++ b/src/camera.h @@ -31,6 +31,7 @@ uint32_t mp_pixel_format_to_v4l_bus_code(MPPixelFormat pixel_format); uint32_t mp_pixel_format_bits_per_pixel(MPPixelFormat pixel_format); uint32_t mp_pixel_format_pixel_depth(MPPixelFormat pixel_format); +const char *mp_pixel_format_cfa(MPPixelFormat pixel_format); uint32_t mp_pixel_format_width_to_bytes(MPPixelFormat pixel_format, uint32_t width); uint32_t mp_pixel_format_width_to_colors(MPPixelFormat pixel_format, uint32_t width); uint32_t mp_pixel_format_height_to_colors(MPPixelFormat pixel_format, diff --git a/src/gles2_debayer.c b/src/gles2_debayer.c index f7400c2..f266d7f 100644 --- a/src/gles2_debayer.c +++ b/src/gles2_debayer.c @@ -24,7 +24,10 @@ struct _GLES2Debayer { GLES2Debayer * gles2_debayer_new(MPPixelFormat format) { - if (format != MP_PIXEL_FMT_BGGR8 && format != MP_PIXEL_FMT_BGGR10P) { + if (format != MP_PIXEL_FMT_BGGR8 && format != MP_PIXEL_FMT_GBRG8 && + format != MP_PIXEL_FMT_GRBG8 && format != MP_PIXEL_FMT_RGGB8 && + format != MP_PIXEL_FMT_BGGR10P && format != MP_PIXEL_FMT_GBRG10P && + format != MP_PIXEL_FMT_GRBG10P && format != MP_PIXEL_FMT_RGGB10P) { return NULL; } @@ -32,10 +35,11 @@ gles2_debayer_new(MPPixelFormat format) glGenFramebuffers(1, &frame_buffer); check_gl(); - char format_def[32]; + char format_def[64]; snprintf(format_def, - 32, - "#define BITS_%d\n", + 64, + "#define CFA_%s\n#define BITS_%d\n", + mp_pixel_format_cfa(format), mp_pixel_format_bits_per_pixel(format)); const GLchar *def[1] = { format_def }; diff --git a/src/process_pipeline.c b/src/process_pipeline.c index 53d70b2..6edadbd 100644 --- a/src/process_pipeline.c +++ b/src/process_pipeline.c @@ -224,14 +224,9 @@ init_gl(MPPipeline *pipeline, GdkSurface **surface) check_gl(); } - gles2_debayer = gles2_debayer_new(MP_PIXEL_FMT_BGGR8); - check_gl(); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); check_gl(); - gles2_debayer_use(gles2_debayer); - for (size_t i = 0; i < NUM_BUFFERS; ++i) { glGenTextures(1, &output_buffers[i].texture_id); glBindTexture(GL_TEXTURE_2D, output_buffers[i].texture_id); @@ -718,7 +713,7 @@ mp_process_pipeline_capture() } static void -on_output_changed() +on_output_changed(bool format_changed) { output_buffer_width = mode.width / 2; output_buffer_height = mode.height / 2; @@ -744,6 +739,17 @@ on_output_changed() glBindTexture(GL_TEXTURE_2D, 0); + // Create new gles2_debayer on format change + if (format_changed) { + if (gles2_debayer) + gles2_debayer_free(gles2_debayer); + + gles2_debayer = gles2_debayer_new(mode.pixel_format); + check_gl(); + + gles2_debayer_use(gles2_debayer); + } + gles2_debayer_configure( gles2_debayer, output_buffer_width, @@ -772,6 +778,8 @@ update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state preview_height != state->preview_height || device_rotation != state->device_rotation; + const bool format_changed = mode.pixel_format != state->mode.pixel_format; + camera = state->camera; mode = state->mode; @@ -793,7 +801,7 @@ update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state if (output_changed) { camera_rotation = mod(camera->rotate - device_rotation, 360); - on_output_changed(); + on_output_changed(format_changed); } struct mp_main_state main_state = {