Revision e5a9df6c8724cf2da2442a26e26145c58d206c98 authored by alex@thinkpad on 14 September 2017, 15:58:30 UTC, committed by alex@thinkpad on 14 September 2017, 15:58:30 UTC
1 parent b92d89e
lv-img-engio.c
/**
* Experiments on LiveView, engio, registers that alter recorded image...
*
**/
#include "dryos.h"
#include "bmp.h"
#include "property.h"
#include "lens.h"
#include "menu.h"
#include "config.h"
#include "math.h"
#include "fps.h"
#if defined(CONFIG_7D)
#include "ml_rpc.h"
#endif
//~ #define EngDrvOutLV(reg, value) *(int*)(reg) = value
//~ #define LV_PAUSE_REGISTER 0xC0F08000 // writing to this pauses LiveView cleanly => good for silent pics
#define SHAD_GAIN 0xc0f08030 // controls clipping point (digital ISO)
#define SHAD_PRESETUP 0xc0f08034 // controls black point? as in "dcraw -k"
#define ISO_PUSH_REGISTER 0xc0f0e0f8 // like display gain, 0x100 = 1 stop, 0x700 = max of 7 stops
#define SHADOW_LIFT_REGISTER_1 0xc0f0e094 // raises shadows, but after they are crushed by Canon curves; default at 0x80?
#define SHADOW_LIFT_REGISTER_2 0xc0f0e0f0 // raises shadows, seems to bring back some shadow detail
#define SHADOW_LIFT_REGISTER_3 0xc0f0f1c4 // raises shadows; has discontinuity :(
#define SHADOW_LIFT_REGISTER_4 0xc0f0f43c // ugly...
#define SHADOW_LIFT_REGISTER_5 0xc0f0e054 // side effect: weird artifacts in highlight
#define SHADOW_LIFT_REGISTER_6 0xc0f0e084 // side effect: weird artifacts in highlight
#define SHADOW_LIFT_REGISTER_7 0xc0f0f178
#define SHADOW_LIFT_REGISTER_8 0xc0f0ecf8 // more like ISO control (clips whites)
static CONFIG_INT("digic.iso.gain.movie", digic_iso_gain_movie, 0); // units: like with the old display gain
static CONFIG_INT("digic.iso.gain.photo", digic_iso_gain_photo, 0);
#define DIGIC_ISO_GAIN_MOVIE (digic_iso_gain_movie ? digic_iso_gain_movie : 1024)
#define DIGIC_ISO_GAIN_PHOTO (digic_iso_gain_photo ? digic_iso_gain_photo : 1024)
int get_digic_iso_gain_movie() { return DIGIC_ISO_GAIN_MOVIE; }
int get_digic_iso_gain_photo() { return DIGIC_ISO_GAIN_PHOTO; }
static CONFIG_INT("digic.black.level", digic_black_level, 0);
int digic_iso_gain_movie_for_gradual_expo = 1024; // additional gain that won't appear in ML menus, but can be changed from code (to be "added" to digic_iso_gain_movie)
int digic_iso_gain_photo_for_bv = 1024;
int display_gain_menu_index = 0; // for menu
//~ CONFIG_INT("digic.shadow.lift", digic_shadow_lift, 0);
// that is: 1024 = 0 EV = disabled
// 2048 = 1 EV etc
// 1024 = 0 EV
void set_display_gain_equiv(int gain)
{
if (gain == 1024) gain = 0;
if (is_movie_mode()) digic_iso_gain_movie = gain;
else digic_iso_gain_photo = gain;
}
void set_movie_digital_iso_gain(int gain)
{
if (gain == 1024) gain = 0;
digic_iso_gain_movie = gain;
}
void set_movie_digital_iso_gain_for_gradual_expo(int gain)
{
digic_iso_gain_movie_for_gradual_expo = gain;
}
void set_photo_digital_iso_gain_for_bv(int gain)
{
digic_iso_gain_photo_for_bv = gain;
}
int gain_to_ev_scaled(int gain, int scale)
{
if (gain == 0) return 0;
return (int) roundf(log2f(gain) * ((float)scale));
}
MENU_UPDATE_FUNC(digic_iso_print_movie)
{
int G = 0;
G = gain_to_ev_scaled(DIGIC_ISO_GAIN_MOVIE, 8) - 80;
G = G * 10/8;
int GA = ABS(G);
MENU_SET_VALUE(
"%s%d.%d EV",
G > 0 ? "+" : G < 0 ? "-" : "",
GA/10, GA%10
);
MENU_SET_ENABLED(G);
// ugly hack
entry->priv = &digic_iso_gain_movie;
}
MENU_UPDATE_FUNC(display_gain_print)
{
int G = gain_to_ev_scaled(DIGIC_ISO_GAIN_PHOTO, 8) - 80;
G = G * 10/8;
int GA = ABS(G);
display_gain_menu_index = GA/10;
}
/*
MENU_UPDATE_FUNC(digic_iso_print)
{
if (is_movie_mode())
{
MENU_SET_NAME("ML digital ISO");
digic_iso_print_movie(entry, info);
}
else
{
MENU_SET_NAME("LV Display Gain");
display_gain_print(entry, info);
}
}
*/
static MENU_UPDATE_FUNC(digic_black_print)
{
MENU_SET_VALUE(
"%s%d",
digic_black_level > 0 ? "+" : "",
digic_black_level
);
MENU_SET_ENABLED(digic_black_level);
}
static int digic_iso_presets[] = {256, 362, 512, 609, 664, 724, 790, 861, 939, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072};
// for debugging
/*static int digic_iso_presets[] = {256, 362, 512, 609, 664, 724, 790, 861, 939,
1024, 1117, 1218, 1328, 1448, 1579, 1722, 1878,
2048, 2233, 2435, 2656, 2896, 3158, 3444, 3756,
4096, 4467, 4871, 5312, 5793, 6317, 6889, 7512,
8192, 16384, 32768, 65536, 131072};
*/
void digic_iso_or_gain_toggle(int* priv, int delta)
{
int mv = (priv == (int*)&digic_iso_gain_movie);
if (*priv == 0) *priv = 1024;
int i;
for (i = 0; i < COUNT(digic_iso_presets); i++)
if (digic_iso_presets[i] >= *priv) break;
do {
i = MOD(i + delta, COUNT(digic_iso_presets));
} while ((!mv && digic_iso_presets[i] < 1024)
#ifdef CONFIG_DIGIC_V
|| (mv && digic_iso_presets[i] > 2048) // high display gains not working
#endif
|| (!mv && digic_iso_presets[i] > 65536)
);
*priv = digic_iso_presets[i];
if (*priv == 1024) *priv = 0;
}
void digic_iso_toggle(void* priv, int delta)
{
if (is_movie_mode()) priv = &digic_iso_gain_movie;
else priv = &digic_iso_gain_photo;
digic_iso_or_gain_toggle(priv, delta);
}
void display_gain_toggle(void* priv, int delta)
{
priv = &digic_iso_gain_photo;
digic_iso_or_gain_toggle(priv, delta);
}
void digic_iso_toggle_movie(void* priv, int delta)
{
priv = &digic_iso_gain_movie;
digic_iso_or_gain_toggle(priv, delta);
}
//~ static CONFIG_INT("digic.effects", image_effects, 0);
static CONFIG_INT("digic.desaturate", desaturate, 0);
static CONFIG_INT("digic.negative", negative, 0);
static CONFIG_INT("digic.swap-uv", swap_uv, 0);
static CONFIG_INT("digic.cartoon", cartoon, 0);
static CONFIG_INT("digic.sharp", sharp, 0);
static CONFIG_INT("digic.zerosharp", zerosharp, 0);
//~ static CONFIG_INT("digic.fringing", fringing, 0);
static int default_white_level = 4096;
static int shad_gain_last_written = 0;
static void autodetect_default_white_level()
{
if (!lv) return;
int current_shad_gain = (int) MEMX(SHAD_GAIN);
if (current_shad_gain == shad_gain_last_written) return; // in the register there's the value we wrote => not good for computing what Canon uses as default setting
default_white_level = current_shad_gain;
}
// get digic ISO level for movie mode
// use SHAD_GAIN as much as possible (range: 0-8191)
// if out of range, return a number of integer stops for boosting the ISO via ISO_PUSH_REGISTER and use SHAD_GAIN for the remainder
static int get_new_white_level(int movie_gain, int* boost_stops)
{
int result = default_white_level;
*boost_stops = 0;
while (1)
{
result = default_white_level * COERCE(movie_gain, 0, 65536) / 1024;
#ifdef CONFIG_DIGIC_V
break;
#endif
if (result > 8192 && *boost_stops < 7)
{
movie_gain /= 2;
(*boost_stops)++;
}
else break;
}
return COERCE(result, 0, 8191);
}
#ifdef CONFIG_DIGIC_POKE
static CONFIG_INT("digic.poke", digic_poke, 0);
static CONFIG_INT("digic.reg.bas", digic_register_base, 0xC0F0);
static CONFIG_INT("digic.reg.mid", digic_register_mid, 0x80);
static CONFIG_INT("digic.reg.off", digic_register_off, 0x08);
static CONFIG_INT("digic.alter.mode", digic_alter_mode, 1);
int digic_register = 0;
int digic_value = 0;
int get_digic_register_addr()
{
return ((digic_register_base << 16) & 0xFFFF0000) |
((digic_register_mid << 8) & 0x0000FF00) |
((digic_register_off << 0) & 0x000000FC) ;
}
void digic_show()
{
NotifyBox(2000, "%x: %8x \n"
"= %d \n"
"= %d %d \n"
"= %d %d %d %d ",
digic_register, digic_value,
digic_value,
digic_value >> 16, (int16_t)digic_value,
(int8_t)(digic_value >> 24), (int8_t)(digic_value >> 16), (int8_t)(digic_value >> 8), (int8_t)(digic_value >> 0)
);
}
void update_digic_register_addr(int dr, int delta, int skip_zero)
{
while (1)
{
dr += delta;
digic_register_base = (dr & 0xFFFF0000) >> 16;
digic_register_mid = (dr & 0x0000FF00) >> 8;
digic_register_off = (dr & 0x000000FC) >> 0;
digic_register = get_digic_register_addr();
if (!skip_zero) break;
int value = MEMX(digic_register);
if (value != 0)
break; // stop on first non-zero register
}
digic_value = MEMX(digic_register);
if ((digic_value & 0xFFF) == 0x800) beep();
digic_show();
}
void digic_find_lv_buffer(int dr, int delta)
{
for (int i = 0; i < 0x1000; i+=4)
{
dr += delta;
digic_register_base = (dr & 0xFFFF0000) >> 16;
digic_register_mid = (dr & 0x0000FF00) >> 8;
digic_register_off = (dr & 0x000000FC) >> 0;
digic_register = get_digic_register_addr();
if ((MEMX(digic_register) & 0xFFF) == 0x800) break;
}
digic_value = MEMX(digic_register);
}
int handle_digic_poke(struct event * event)
{
if (digic_poke && lv && !gui_menu_shown())
{
if (event->param == BGMT_PRESS_LEFT)
{
update_digic_register_addr(digic_register, -4, 0);
return 0;
}
if (event->param == BGMT_PRESS_RIGHT)
{
update_digic_register_addr(digic_register, 4, 0);
return 0;
}
if (event->param == BGMT_PRESS_DOWN)
{
update_digic_register_addr(digic_register, -4, 1);
return 0;
}
if (event->param == BGMT_PRESS_UP)
{
update_digic_register_addr(digic_register, 4, 1);
return 0;
}
}
return 1;
}
void digic_poke_step()
{
if (digic_poke && DISPLAY_IS_ON && lv)
{
digic_register = get_digic_register_addr();
if (HALFSHUTTER_PRESSED)
{
if (digic_alter_mode == 0) // rand
digic_value = rand();
else if (digic_alter_mode == 1) // increment
digic_value += is_manual_focus() ? 1 : -1;
else if (digic_alter_mode == 2) // increment << 8
digic_value += (is_manual_focus() ? 1 : -1) << 8;
else if (digic_alter_mode == 3) // increment << 16
digic_value += (is_manual_focus() ? 1 : -1) << 16;
else if (digic_alter_mode == 4) // increment << 24
digic_value += (is_manual_focus() ? 1 : -1) << 24;
//~ digic_value--;
digic_show();
_EngDrvOut(digic_register, digic_value);
_EngDrvOut(0xC0F06000, 1); // apply the change
//~ fps_set_main_timer(digic_value);
//~ EngDrvOutLV(0xc0f04a08, 0x6000080);
//~ int lvw = MEMX(0xc0f04308);
//~ int hdw = MEMX(0xc0f04208);
//~ EngDrvOutLV(0xc0f04308, hdw);
//~ EngDrvOutLV(0xc0f04208, lvw);
}
else
{
digic_value = MEMX(digic_register);
}
}
}
void hex_toggle_8bit(void* priv, int delta)
{
MEM(priv) += 4 * delta;
MEM(priv) &= 0xFF;
}
void digic_value_toggle(void* priv, int delta)
{
digic_value += delta;
}
void digic_random_register(void* priv, int delta)
{
digic_register_mid = rand() & 0xFF;
digic_register_off = rand() & 0xFC;
}
static MENU_UPDATE_FUNC(digic_value_print)
{
MENU_SET_NAME("Value[%08x]", digic_register);
MENU_SET_VALUE("%x", digic_value);
}
void digic_dump()
{
msleep(1000);
static char log_filename[100];
int log_number = 0;
for (log_number = 0; log_number < 100; log_number++)
{
snprintf(log_filename, sizeof(log_filename), "digic%02d.LOG", log_number);
uint32_t size;
if( FIO_GetFileSize( log_filename, &size ) != 0 ) break;
if (size == 0) break;
}
FILE* f = FIO_CreateFile(log_filename);
if (f)
{
for (uint32_t reg = 0xc0f00000; reg < 0xC0f40000; reg+=4)
{
int value = (int) shamem_read(reg);
if (value && value != -1)
{
bmp_printf(FONT_LARGE, 50, 50, "%8x: %8x", reg, value);
my_fprintf(f, "%8x: %8x\n", reg, value);
}
}
FIO_CloseFile(f);
}
}
void digic_dump_h264()
{
msleep(1000);
FILE* f = FIO_CreateFile("ML/LOGS/h264.log");
if (f)
{
for (uint32_t reg = 0xc0e10000; reg < 0xC0f00000; reg+=4)
{
int value = MEM(reg);
if (value && value != -1)
{
bmp_printf(FONT_LARGE, 50, 50, "%8x: %8x", reg, value);
my_fprintf(f, "%8x: %8x\n", reg, value);
}
}
FIO_CloseFile(f);
}
}
#endif // CONFIG_DIGIC_POKE
#ifdef CONFIG_FULLFRAME
#define VIGNETTING_MAX_INDEX 155 // 5D2
#else
#define VIGNETTING_MAX_INDEX 145 // 60D
#endif
static uint32_t vignetting_data[0x100];
static uint32_t vignetting_data_prep[0x80];
static int vignetting_correction_initialized = 0;
static CONFIG_INT("digic.vignetting.corr", vignetting_correction_enable, 0);
static CONFIG_INT("digic.vignetting.a", vignetting_correction_a, -10);
static CONFIG_INT("digic.vignetting.b", vignetting_correction_b, 0);
static CONFIG_INT("digic.vignetting.c", vignetting_correction_c, 0);
// index from 0 to 0x100, value from 0 to 1023
// indexes greater than VIGNETTING_MAX_INDEX fall outside the image area
static void vignetting_correction_set(int index, int value)
{
vignetting_data[index & 0xFF] = value;
}
static int vignetting_correction_get(int index)
{
return vignetting_data[index & 0xFF];
}
static void vignetting_correction_set_coeffs(int a, int b, int c)
{
uint32_t index = 0;
int min = 1023;
int max = -1023;
for(index = 0; index < 0x100; index++)
{
int t = COERCE(index * 1024 / VIGNETTING_MAX_INDEX, 0, 1024);
int ts = (1024 - t);
ts = ts * ts / 1024;
ts = 1024 - ts;
int t2 = t * t / 1024;
int t4 = t2 * t2 / 1024;
int v = ts * a / 10 + t * b / 10 + t4 * c / 10;
min = MIN(min, v);
max = MAX(max, v);
vignetting_data[index] = v;
}
// normalize data so it fits into 0...1023
int range = max - min;
for(index = 0; index < 0x100; index++)
{
vignetting_data[index] -= min;
if (range > 1023)
vignetting_data[index] = vignetting_data[index] * 1023 / range;
#ifdef CONFIG_DIGIC_V
// prefer to use 512 (0EV) if no correction is needed
vignetting_data[index] += MIN(512, 1023 - MIN(range, 1023));
#endif
// debug - for finding VIGNETTING_MAX_INDEX
// vignetting_data[index] = (index > VIGNETTING_MAX_INDEX) ? 1023 : 0;
}
/* pre-calculate register values */
for(index = 0; index < 0x80; index++)
{
#ifdef CONFIG_DIGIC_V
// 0 -> pitch black
// 256 -> -1EV (with pink highlights)
// 512 -> 0 EV (no correction)
// 1024 -> +1EV (blows hihglights)
// let's map 0-1024 to -2...+2EV; stick to 0EV if no correction is needed
int ev1 = vignetting_data[2*index] - 512;
int val1 = 512 * powf(2, ev1 / 256.0);
int ev2 = vignetting_data[2*index+1] - 512;
int val2 = 512 * powf(2, ev2 / 256.0);
uint32_t data = (val1 & 0xFFFF) | ((val2 & 0xFFFF) << 16);
#else
uint32_t data = (vignetting_data[2*index] & 0x03FF) | ((vignetting_data[2*index+1] & 0x03FF) << 10);
#endif
vignetting_data_prep[index] = data;
}
#if defined(CONFIG_7D)
/* send vignetting data to master */
ml_rpc_send_vignetting(vignetting_data_prep, vignetting_correction_enable ? sizeof(vignetting_data_prep) : 0);
#endif
}
#if defined(CONFIG_7D)
/* 7D version doesnt rewrite digic registers, but updates canon's register value buffer which is held in LVMgr */
void vignetting_correction_apply_lvmgr(uint32_t *lvmgr)
{
uint32_t index = 0;
if(vignetting_correction_enable && lvmgr && is_movie_mode())
{
uint32_t *vign = &lvmgr[0x83];
for(index = 0; index < 0x80; index++)
{
vign[index] = vignetting_data_prep[index];
}
}
}
#else
/* the other cameras rewrite digic registers */
void vignetting_correction_apply_regs()
{
if (!is_movie_mode()) return;
if (!DISPLAY_IS_ON && NOT_RECORDING) return;
if (!lv) return;
if (lv_paused) return;
if (!vignetting_correction_initialized || !vignetting_correction_enable)
{
return;
}
#ifdef CONFIG_DIGIC_V
for(uint32_t index = 0; index < COUNT(vignetting_data_prep); index++)
{
*(volatile uint32_t*)(0xC0F08D1C) = vignetting_data_prep[index];
*(volatile uint32_t*)(0xC0F08D24) = vignetting_data_prep[index];
}
#else
for(uint32_t index = 0; index < COUNT(vignetting_data_prep); index++)
{
*(volatile uint32_t*)(0xC0F08578) = index * 2;
*(volatile uint32_t*)(0xC0F0857C) = vignetting_data_prep[index];
}
*(volatile uint32_t*)(0xC0F08578) = COUNT(vignetting_data_prep) * 2;
#endif
}
#endif
extern void flip_zoom();
static void vignetting_correction_toggle(void* priv, int delta)
{
uint32_t *state = (uint32_t *)priv;
*state = !*state;
#if defined(CONFIG_7D)
ml_rpc_send_vignetting(vignetting_data_prep, *state ? sizeof(vignetting_data_prep) : 0);
#endif
}
static void vignetting_coeff_toggle(void* priv, int delta)
{
menu_numeric_toggle(priv, delta, -10, 10);
vignetting_correction_set_coeffs(vignetting_correction_a, vignetting_correction_b, vignetting_correction_c);
#if defined(CONFIG_7D)
if (vignetting_correction_enable)
ml_rpc_send_vignetting(vignetting_data_prep, sizeof(vignetting_data_prep));
#endif
}
static int vignetting_luma[0x100];
static uint16_t vignetting_luma_n[0x100];
static uint8_t vignetting_luma_max[0x100];
static uint8_t vignetting_luma_min[0x100];
static void vignetting_measure_luma(int samples)
{
uint8_t* lv = vram_lv.vram;
for (int r = 0; r < 0x100; r++)
{
vignetting_luma[r] = 0;
vignetting_luma_n[r] = 0;
vignetting_luma_max[r] = 0;
vignetting_luma_min[r] = 255;
}
for (int i = 0; i < samples; i++)
{
int xc = os.x0 + os.x_ex/2;
int yc = os.y0 + os.y_ex/2;
int x = os.x0 + (rand() % os.x_ex);
int y = os.y0 + (rand() % os.y_ex);
int ya = y;
#ifdef CONFIG_4_3_SCREEN
ya = ((y - yc) * 9/8) + yc;
#endif
int r = sqrtf((x - xc) * (x - xc) + (ya - yc) * (ya - yc)) / 2;
r = MIN(r, 216);
int luma = lv[BM2LV(x,y)+1];
vignetting_luma[r & 0xFF] += luma;
vignetting_luma_n[r & 0xFF]++;
vignetting_luma_min[r & 0xFF] = MIN(luma, vignetting_luma_min[r & 0xFF]);
vignetting_luma_max[r & 0xFF] = MAX(luma, vignetting_luma_max[r & 0xFF]);
}
for (int r = 0; r < 0x100; r++)
vignetting_luma[r] /= vignetting_luma_n[r];
}
static MENU_UPDATE_FUNC(vignetting_graphs_update)
{
if (entry->selected && info->can_custom_draw)
{
int yb = 400;
int xa = 720-218 - 70;
//~ int yb = menu_active_but_hidden() ? 430 : 455;
bmp_fill(COLOR_BLACK, xa, yb-128, 216, 128);
bmp_draw_rect(COLOR_WHITE, xa-1, yb-129, 218, 130);
vignetting_measure_luma(10000);
for (int r = 0; r < 216; r++)
{
int luma = vignetting_luma[r];
int luma_min = vignetting_luma_min[r];
int luma_max = vignetting_luma_max[r];
int x = xa + r;
int y = yb - luma/2;
draw_line(x, yb - luma_min/2, x, yb - luma_max/2, 45);
bmp_putpixel(x, y, COLOR_WHITE);
}
int xb = 70;
bmp_fill(COLOR_BLACK, xb, yb-128, 216, 128);
bmp_draw_rect(COLOR_WHITE, xb-1, yb-129, 218, 130);
int max = 0;
for (int i = 0; i < VIGNETTING_MAX_INDEX; i++)
{
int x = xb + sqrtf(i) * 216 / sqrtf(VIGNETTING_MAX_INDEX);
int y = yb - vignetting_data[i] / 8;
bmp_putpixel(x, y, COLOR_WHITE);
bmp_putpixel(x+1, y, COLOR_WHITE);
max = MAX(max, vignetting_data[i]);
}
#ifdef CONFIG_DIGIC_V
bmp_printf(FONT(FONT_MED, 60, COLOR_BLACK), xb + 225, yb-128 - font_med.height/2, "+2 EV");
bmp_printf(FONT(FONT_MED, 60, COLOR_BLACK), xb + 225, yb - font_med.height/2, "-2 EV");
#else
bmp_printf(FONT(FONT_MED, 60, COLOR_BLACK), xb + 225, yb-128 - font_med.height/2, "+1 EV");
bmp_printf(FONT(FONT_MED, 60, COLOR_BLACK), xb + 225, yb - font_med.height/2, "0");
#endif
}
}
#ifdef FEATURE_SHUTTER_FINE_TUNING
#ifndef CONFIG_FRAME_SHUTTER_OVERRIDE
#error "This requires CONFIG_FRAME_SHUTTER_OVERRIDE"
#endif
#ifdef CONFIG_DIGIC_V
#define MIN_SHUTTER_TIMER 2
#else
#define MIN_SHUTTER_TIMER 1
#endif
static CONFIG_INT("shutter.finetune", shutter_finetune, 0);
static volatile int orig_shutter_timer = 0;
static volatile int adjusted_shutter_timer = 0;
/* should be called from the LV state object, from the same spot as HDR video */
void shutter_finetune_step()
{
if (is_movie_mode() && shutter_finetune)
{
orig_shutter_timer = FRAME_SHUTTER_TIMER;
adjusted_shutter_timer = COERCE(orig_shutter_timer + shutter_finetune, MIN_SHUTTER_TIMER, 65535);
FRAME_SHUTTER_TIMER = adjusted_shutter_timer;
}
}
int shutter_finetune_get_adjusted_timer()
{
if (shutter_finetune) return adjusted_shutter_timer;
else return FRAME_SHUTTER_TIMER;
}
static MENU_UPDATE_FUNC(shutter_finetune_display)
{
if (!shutter_finetune)
{
MENU_SET_VALUE("OFF");
}
else if (is_movie_mode())
{
int delta = get_shutter_speed_us_from_timer(shutter_finetune)/10;
/* fixme: small race condition */
int bk = adjusted_shutter_timer;
adjusted_shutter_timer = orig_shutter_timer;
int orig_shutter = get_current_shutter_reciprocal_x1000();
adjusted_shutter_timer = bk;
int adjusted_shutter = get_current_shutter_reciprocal_x1000();
MENU_SET_VALUE("%s%d.%02d ms", delta > 0 ? "+" : "-", ABS(delta)/100, ABS(delta)%100);
if (orig_shutter/1000 < 1000)
MENU_SET_WARNING(MENU_WARN_INFO, "Shutter speed: 1/%d.%03d -> 1/%d.%03d (%s%d units)", orig_shutter/1000, orig_shutter%1000, adjusted_shutter/1000, adjusted_shutter%1000, delta > 0 ? "+" : "", shutter_finetune);
else
MENU_SET_WARNING(MENU_WARN_INFO, "Shutter speed: 1/%d -> 1/%d (%s%d units)", orig_shutter/1000, adjusted_shutter/1000, delta > 0 ? "+" : "", shutter_finetune);
}
else
{
int delta = shutter_finetune;
MENU_SET_VALUE("%s%d units", delta > 0 ? "+" : "", delta);
}
}
#endif
void image_effects_step()
{
if (!DISPLAY_IS_ON && NOT_RECORDING) return;
if (!lv) return;
if (lv_paused) return;
#ifdef CONFIG_DIGIC_POKE
digic_poke_step();
#endif
#ifdef FEATURE_IMAGE_EFFECTS
static int prev_swap_uv = 0;
if (!is_movie_mode()) return;
if (desaturate) EngDrvOutLV(0xc0f0f070, 0x01000100);
if (negative) EngDrvOutLV(0xc0f0f000, 0xb1);
if (swap_uv) EngDrvOutLV(0xc0f0de2c, 0x10); else if (prev_swap_uv) EngDrvOutLV(0xc0f0de2c, 0);
if (cartoon)
{
if (cartoon == 1)
{
EngDrvOutLV(0xc0f23164, -1);
}
else if (cartoon == 2)
{
EngDrvOutLV(0xc0f23164, -1);
EngDrvOutLV(0xc0f0f29c, 0xffff); // also c0f2194c?
}
else
{
EngDrvOutLV(0xc0f23164, -1);
for (uint32_t reg = 0xc0f0f100; reg <= 0xc0f0f160; reg += 4)
EngDrvOutLV(reg, 0);
EngDrvOutLV(0xc0f0f11c, 128);
EngDrvOutLV(0xc0f0f128, 128);
EngDrvOutLV(0xc0f0f134, 128);
EngDrvOutLV(0xc0f0f150, 128);
EngDrvOutLV(0xc0f0f160, 128);
}
EngDrvOutLV(0xc0f2116c, 0xffff0000); // boost picturestyle sharpness to max
}
//if (oilpaint) EngDrvOutLV(0xc0f2135c, -1);
if (sharp) EngDrvOutLV(0xc0f0f280, -1);
if (zerosharp) EngDrvOutLV(0xc0f2116c, 0x0); // sharpness trick: at -1, cancel it completely
prev_swap_uv = swap_uv;
#endif
}
void digic_iso_step()
{
#if defined(FEATURE_EXPO_ISO_DIGIC) || defined(FEATURE_LV_DISPLAY_GAIN) || defined(FEATURE_SHUTTER_FINE_TUNING)
if (!DISPLAY_IS_ON && NOT_RECORDING) return;
if (!lv) return;
if (lv_paused) return;
int mv = is_movie_mode();
if (mv && lens_info.iso == 0) return; // no auto ISO, please
#endif
#ifdef FEATURE_EXPO_ISO_DIGIC
if (mv)
{
if (digic_iso_gain_movie_for_gradual_expo == 0) digic_iso_gain_movie_for_gradual_expo = 1024;
int total_movie_gain = DIGIC_ISO_GAIN_MOVIE * digic_iso_gain_movie_for_gradual_expo / 1024;
if (total_movie_gain != 1024)
{
autodetect_default_white_level();
int boost_stops = 0;
int new_gain = get_new_white_level(total_movie_gain, &boost_stops);
EngDrvOutLV(SHAD_GAIN, new_gain);
shad_gain_last_written = new_gain;
#ifndef CONFIG_DIGIC_V
EngDrvOutLV(ISO_PUSH_REGISTER, boost_stops << 8);
#endif
}
if (digic_black_level)
{
int presetup = MEMX(SHAD_PRESETUP);
presetup = ((presetup + 100) & 0xFF00) + ((int)digic_black_level);
EngDrvOutLV(SHAD_PRESETUP, presetup);
}
#ifdef CONFIG_DIGIC_V
if (LVAE_DISP_GAIN) call("lvae_setdispgain", 0); // reset display gain
#endif
}
#endif
#ifdef FEATURE_LV_DISPLAY_GAIN
if (!mv) // photo mode - display gain, for preview only
{
if (digic_iso_gain_photo_for_bv == 0) digic_iso_gain_photo_for_bv = 1024;
int total_photo_gain = DIGIC_ISO_GAIN_PHOTO * digic_iso_gain_photo_for_bv / 1024;
#ifdef FEATURE_RAW_BLINKIES
if (raw_blinkies_enabled())
{
autodetect_default_white_level();
int boost_stops = 0;
int new_gain = get_new_white_level(256, &boost_stops);
EngDrvOutLV(SHAD_GAIN, new_gain);
shad_gain_last_written = new_gain;
}
#endif
if (total_photo_gain == 0) total_photo_gain = 1024;
#ifdef CONFIG_DIGIC_V
int g = total_photo_gain == 1024 ? 0 : COERCE(total_photo_gain, 0, 65534);
if (LVAE_DISP_GAIN != g)
{
call("lvae_setdispgain", g);
}
#else
if (total_photo_gain > 1024 && !LVAE_DISP_GAIN)
{
int boost_stops = COERCE((int)log2f(total_photo_gain / 1024), 0, 7);
EngDrvOutLV(ISO_PUSH_REGISTER, boost_stops << 8);
}
#endif
}
#endif
}
void menu_open_submenu();
static struct menu_entry lv_img_menu[] = {
#ifdef FEATURE_VIGNETTING_CORRECTION
{
.name = "Vignetting",
.max = 1,
.priv = &vignetting_correction_enable,
.select = vignetting_correction_toggle,
.help = "Vignetting correction or effects.",
.depends_on = DEP_MOVIE_MODE,
.submenu_width = 710,
.submenu_height = 250,
.children = (struct menu_entry[]) {
{
.name = "Mid-range correction ",
.priv = &vignetting_correction_a,
.unit = UNIT_x10,
.min = -10,
.max = 10,
.select = vignetting_coeff_toggle,
.update = vignetting_graphs_update,
.help = "Correction applied between central area and corners.",
.help2 = "Tip: set this to -1 for a nice vignette effect.",
},
{
.name = "Corner correction ",
.priv = &vignetting_correction_b,
.min = -10,
.max = 10,
.unit = UNIT_x10,
.select = vignetting_coeff_toggle,
.update = vignetting_graphs_update,
.help = "Correction with a stronger bias towards corners.",
},
{
.name = "Extreme corner correction",
.priv = &vignetting_correction_c,
.min = -10,
.max = 10,
.unit = UNIT_x10,
.select = vignetting_coeff_toggle,
.update = vignetting_graphs_update,
},
MENU_EOL,
},
},
#endif
#if defined(FEATURE_IMAGE_EFFECTS) || defined(FEATURE_EXPO_ISO_DIGIC) || defined(FEATURE_SHUTTER_FINE_TUNING)
{
.name = "Image Fine-tuning",
.select = menu_open_submenu,
.help = "Subtle image enhancements via DIGIC register tweaks.",
.depends_on = DEP_MOVIE_MODE,
.submenu_width = 700,
.children = (struct menu_entry[]) {
#ifdef FEATURE_EXPO_ISO_DIGIC
{
.name = "ML Digital ISO",
.priv = &digic_iso_gain_movie,
.update = digic_iso_print_movie,
.select = digic_iso_toggle_movie,
.help = "ISO tweaks. Negative gain has better highlight roll-off.",
.edit_mode = EM_MANY_VALUES_LV,
.depends_on = DEP_MOVIE_MODE | DEP_MANUAL_ISO,
.icon_type = IT_DICE_OFF,
},
{
.name = "Black Level",
.priv = &digic_black_level,
.min = -100,
.max = 100,
.update = digic_black_print,
.icon_type = IT_PERCENT_LOG_OFF,
.edit_mode = EM_MANY_VALUES_LV,
.depends_on = DEP_LIVEVIEW | DEP_MOVIE_MODE,
.help = "Adjust dark level, as with 'dcraw -k'. Fixes green shadows.",
},
#endif
#ifdef FEATURE_SHUTTER_FINE_TUNING
{
.name = "Shutter fine-tuning",
.priv = &shutter_finetune,
.update = shutter_finetune_display,
.min = -500,
.max = 500,
.icon_type = IT_PERCENT_LOG_OFF,
.edit_mode = EM_MANY_VALUES_LV,
.help = "Fine-tune shutter speed in approx 20-microsecond increments.",
.depends_on = DEP_LIVEVIEW | DEP_MOVIE_MODE,
},
#endif
#ifdef FEATURE_IMAGE_EFFECTS
{
.name = "Absolute Zero Sharpness",
.priv = &zerosharp,
.max = 1,
.help = "Disable sharpening completely (below Canon's zero level).",
.depends_on = DEP_LIVEVIEW | DEP_MOVIE_MODE,
},
#if !(defined(CONFIG_600D) || defined(CONFIG_1100D))
{
.name = "Edge Emphasis",
.priv = &sharp,
.max = 1,
.help = "Darken sharp edges in bright areas.",
.depends_on = DEP_LIVEVIEW | DEP_MOVIE_MODE,
},
#endif
#endif
MENU_EOL,
}
},
#endif
#ifdef FEATURE_IMAGE_EFFECTS
{
.name = "Creative Effects",
.select = menu_open_submenu,
.help = "Experimental image filters found by digging into DIGIC.",
.depends_on = DEP_MOVIE_MODE,
.children = (struct menu_entry[]) {
{
.name = "Desaturate",
.priv = &desaturate,
.min = 0,
.max = 1,
.help = "Grayscale recording. Use WB or pic styles for fine tuning.",
.depends_on = DEP_LIVEVIEW | DEP_MOVIE_MODE,
},
{
.name = "Negative",
.priv = &negative,
.min = 0,
.max = 1,
.help = "Negative image. Inverts all colors :)",
.depends_on = DEP_LIVEVIEW | DEP_MOVIE_MODE,
},
{
.name = "Swap U-V",
.priv = &swap_uv,
.min = 0,
.max = 1,
.help = "Swaps U and V channels (red <--> blue).",
.depends_on = DEP_LIVEVIEW | DEP_MOVIE_MODE,
},
{
.name = "Cartoon Look",
.priv = &cartoon,
.min = 0,
.max = 3,
.choices = (const char *[]) {"OFF", "Mode 1", "Mode 2", "Mode 3"},
.help = "Cartoonish look obtained by emphasizing the edges.",
.icon_type = IT_DICE_OFF,
.depends_on = DEP_LIVEVIEW | DEP_MOVIE_MODE,
},
MENU_EOL
}
}
#endif
};
#ifdef CONFIG_DIGIC_POKE
static struct menu_entry dbg_menu[] = {
{
.name = "DIGIC poke",
.priv = &digic_poke,
.min = 0,
.max = 1,
.help = "Changes a DIGIC register to find out what it does. DANGER!",
.children = (struct menu_entry[]) {
{
.name = "Register family",
.priv = &digic_register_base,
.unit = UNIT_HEX,
.min = 0xC000,
.max = 0xCFFF,
.help = "DIGIC register address, mask=FFFF0000.",
},
{
.name = "Register base ",
.priv = &digic_register_mid,
.unit = UNIT_HEX,
.min = 0x00,
.max = 0xFF,
.help = "DIGIC register address, mask=0000FF00.",
},
{
.name = "Register offset",
.priv = &digic_register_off,
.unit = UNIT_HEX,
.min = 0x00,
.max = 0xFF,
.select = hex_toggle_8bit,
.help = "DIGIC register address, mask=000000FC.",
},
{
.name = "Value ",
.priv = &digic_value,
.update = digic_value_print,
.select = digic_value_toggle,
.help = "Current value of selected register. Change w. HalfShutter.",
},
{
.name = "Altering mode ",
.priv = &digic_alter_mode,
.max = 4,
.choices = (const char *[]) {"rand()", "x++", "x += (1<<8)", "x += (1<<16)", "x += (1<<24)"},
.help = "How to change current value [HalfShutter]. MF(+) / AF(-).",
},
{
.name = "Random register",
.select = digic_random_register,
.help = "Click to select some random register.",
},
MENU_EOL
}
},
{
.name = "Dump DIGIC registers",
.priv = digic_dump,
.select = run_in_separate_task,
.help = "Saves the contents of DIGIC shadow copy to DIGIC.LOG."
}
};
#endif
static void lv_img_init()
{
menu_add( "Movie", lv_img_menu, COUNT(lv_img_menu) );
#ifdef CONFIG_DIGIC_POKE
menu_add( "Debug", dbg_menu, COUNT(dbg_menu) );
#endif
}
static void vignetting_init (void * parm)
{
vignetting_correction_set_coeffs(vignetting_correction_a, vignetting_correction_b, vignetting_correction_c);
vignetting_correction_initialized = 1;
}
INIT_FUNC("lv_img", lv_img_init);
TASK_CREATE( "vignetting_init", vignetting_init, 0, 0x1e, 0x2000 );
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...