diff -r ea33365bdc00 src/shoot.c --- a/src/shoot.c Tue Jul 30 21:24:18 2013 +0300 +++ b/src/shoot.c Thu Aug 01 11:38:13 2013 +0300 @@ -165,6 +165,7 @@ #define SILENT_PIC_MODE_BURST_END_TRIGGER 2 #define SILENT_PIC_MODE_BEST_SHOTS 3 #define SILENT_PIC_MODE_SLITSCAN 4 +#define SILENT_PIC_MODE_LONGEXP 5 //~ static CONFIG_INT( "zoom.enable.face", zoom_enable_face, 0); static CONFIG_INT( "zoom.disable.x5", zoom_disable_x5, 0); @@ -702,6 +703,9 @@ case SILENT_PIC_MODE_SLITSCAN: MENU_SET_VALUE("Slit-Scan"); break; + + case SILENT_PIC_MODE_LONGEXP: + MENU_SET_VALUE("Long Expo DR++"); } } @@ -1755,6 +1759,12 @@ } } +static int silent_pic_raw_longexp_frame = 0; +static void silent_pic_raw_longexp_vsync() +{ + silent_pic_raw_longexp_frame++; +} + /* called once per LiveView frame from LV state object */ void silent_pic_raw_vsync() { @@ -1768,6 +1778,12 @@ return; } + if (silent_pic_mode == SILENT_PIC_MODE_LONGEXP) + { + silent_pic_raw_longexp_vsync(); + return; + } + /* are we done? */ if ((sp_num_frames >= sp_min_frames && !HALFSHUTTER_PRESSED) || sp_num_frames >= sp_max_frames) { @@ -1885,6 +1901,119 @@ return count; } +#define PA ((int)(p->a)) +#define PB ((int)(p->b_lo | (p->b_hi << 12))) +#define PC ((int)(p->c_lo | (p->c_hi << 10))) +#define PD ((int)(p->d_lo | (p->d_hi << 8))) +#define PE ((int)(p->e_lo | (p->e_hi << 6))) +#define PF ((int)(p->f_lo | (p->f_hi << 4))) +#define PG ((int)(p->g_lo | (p->g_hi << 2))) +#define PH ((int)(p->h)) + +#define SET_PA(x) { int v = (x); p->a = v; } +#define SET_PB(x) { int v = (x); p->b_lo = v; p->b_hi = v >> 12; } +#define SET_PC(x) { int v = (x); p->c_lo = v; p->c_hi = v >> 10; } +#define SET_PD(x) { int v = (x); p->d_lo = v; p->d_hi = v >> 8; } +#define SET_PE(x) { int v = (x); p->e_lo = v; p->e_hi = v >> 6; } +#define SET_PF(x) { int v = (x); p->f_lo = v; p->f_hi = v >> 4; } +#define SET_PG(x) { int v = (x); p->g_lo = v; p->g_hi = v >> 2; } +#define SET_PH(x) { int v = (x); p->h = v; } + +static int* average_buffer = 0; +static int average_count = 0; + +static int silent_pic_raw_average_start() +{ + int size = raw_info.width * raw_info.height * sizeof(int); + average_buffer = shoot_malloc(size); + if (!average_buffer) return 0; + memset(average_buffer, 0, size); + average_count = 0; + return 1; +} + +static void FAST silent_pic_raw_average_add() +{ + average_count++; + int dr = (int)roundf(log2f(sqrtf(average_count)) * 10); + bmp_printf(FONT_MED, 0, 60, "Averaging frame %d, DR+%d.%d EV...", average_count, dr/10, dr%10); + + int width = raw_info.width; + + struct raw_pixblock * row; + int y; + for (row = raw_info.buffer, y = 0; (void*)row < (void*)raw_info.buffer + raw_info.pitch * raw_info.height; row += raw_info.pitch / sizeof(struct raw_pixblock), y++) + { + struct raw_pixblock * p; + int x; + int yw = y * width; + for (p = row, x = 0; (void*)p < (void*)row + raw_info.pitch; p++, x += 8) + { + average_buffer[yw + x + 0] += PA; + average_buffer[yw + x + 1] += PB; + average_buffer[yw + x + 2] += PC; + average_buffer[yw + x + 3] += PD; + average_buffer[yw + x + 4] += PE; + average_buffer[yw + x + 5] += PF; + average_buffer[yw + x + 6] += PG; + average_buffer[yw + x + 7] += PH; + } + } +} + +static void silent_pic_raw_average_finish() +{ + if (!average_count) return; + + bmp_printf(FONT_MED, 0, 60, "Finishing averaging... "); + + int width = raw_info.width; + int x, y; + for (y = 0; y < raw_info.height; y++) + { + for (x = 0; x < raw_info.width; x++) + { + average_buffer[y * width + x] /= average_count; + } + } + + /* save the averaged image */ + struct raw_pixblock * row; + for (row = raw_info.buffer, y = 0; (void*)row < (void*)raw_info.buffer + raw_info.pitch * raw_info.height; row += raw_info.pitch / sizeof(struct raw_pixblock), y++) + { + struct raw_pixblock * p; + for (p = row, x = 0; (void*)p < (void*)row + raw_info.pitch; p++, x += 8) + { + SET_PA(average_buffer[y * width + x + 0]); + SET_PB(average_buffer[y * width + x + 1]); + SET_PC(average_buffer[y * width + x + 2]); + SET_PD(average_buffer[y * width + x + 3]); + SET_PE(average_buffer[y * width + x + 4]); + SET_PF(average_buffer[y * width + x + 5]); + SET_PG(average_buffer[y * width + x + 6]); + SET_PH(average_buffer[y * width + x + 7]); + } + } + + shoot_free(average_buffer); + average_buffer = 0; +} + +void silent_test() +{ + beep(); + raw_lv_request(); + silent_pic_raw_average_start(); + int t0 = get_ms_clock_value(); + silent_pic_raw_average_add(); + int t1 = get_ms_clock_value(); + + NotifyBox(5000, "%d ", t1 - t0); + + silent_pic_raw_average_finish(); + raw_lv_release(); +} + static void silent_pic_take_raw(int interactive) { @@ -1911,6 +2040,7 @@ /* allocate only one frame in simple and slitscan modes */ case SILENT_PIC_MODE_SIMPLE: case SILENT_PIC_MODE_SLITSCAN: + case SILENT_PIC_MODE_LONGEXP: hSuite = shoot_malloc_suite_contig(raw_info.frame_size * 33/32); break; } @@ -1940,6 +2070,7 @@ { case SILENT_PIC_MODE_SIMPLE: case SILENT_PIC_MODE_SLITSCAN: + case SILENT_PIC_MODE_LONGEXP: sp_max_frames = 1; break; @@ -1959,6 +2090,14 @@ #ifdef CONFIG_DISPLAY_FILTERS silent_pic_raw_init_preview(); #endif + + if (silent_pic_mode == SILENT_PIC_MODE_LONGEXP) + { + beep(); + while (get_halfshutter_pressed()) msleep(10); + silent_pic_raw_longexp_frame = 0; + silent_pic_raw_average_start(); + } /* the actual grabbing the image(s) will happen from silent_pic_raw_vsync */ sp_running = 1; @@ -1973,6 +2112,16 @@ if (silent_pic_mode == SILENT_PIC_MODE_BEST_SHOTS) silent_pic_raw_show_focus(-1); + if (silent_pic_mode == SILENT_PIC_MODE_LONGEXP) + { + static int prev_pic = 0; + while (silent_pic_raw_longexp_frame == prev_pic) + msleep(10); + prev_pic = silent_pic_raw_longexp_frame; + silent_pic_raw_average_add(); + if (get_halfshutter_pressed()) sp_running = 0; + } + if (!lv) { sp_running = 0; @@ -2010,6 +2159,14 @@ } } + if (silent_pic_mode == SILENT_PIC_MODE_LONGEXP) + { + int black = raw_info.black_level; + raw_info.buffer = sp_frames[0]; + silent_pic_raw_average_finish(); + raw_info.black_level = black; + } + /* save the image(s) to card */ if (sp_num_frames > 1 || silent_pic_mode == SILENT_PIC_MODE_SLITSCAN) { @@ -4623,15 +4780,16 @@ { .name = "Silent Mode", .priv = &silent_pic_mode, - .max = 4, + .max = 5, .help = "Choose the silent picture mode:", .help2 = "Take a silent picture when you press the shutter halfway.\n" "Take pictures until memory gets full, then save to card.\n" "Take pictures continuously, save the last few pics to card.\n" "Take pictures continuously, save the best (focused) images.\n" - "Distorted pictures for funky effects.\n", - .choices = CHOICES("Simple", "Burst", "Burst, End Trigger", "Best Shots", "Slit-Scan"), + "Distorted pictures for funky effects.\n" + "Long exposures with very high dynamic range\n", + .choices = CHOICES("Simple", "Burst", "Burst, End Trigger", "Best Shots", "Slit-Scan", "Long Expo DR++"), .icon_type = IT_DICE, }, MENU_EOL,