movtweaks.c 29.9 KB
Newer Older
alex@thinkpad's avatar
alex@thinkpad committed
1

2
3
4
5
6
7
8
9
10
11
12
13
/** \file
 * Tweaks specific to movie mode
 */
#include "dryos.h"
#include "bmp.h"
#include "tasks.h"
#include "debug.h"
#include "menu.h"
#include "property.h"
#include "config.h"
#include "gui.h"
#include "lens.h"
14
#include "math.h"
15
16
17
18
#include "shoot.h"
#include "zebra.h"
#include "fps.h"
#include "beep.h"
Licaon Kter's avatar
Licaon Kter committed
19
#include "lvinfo.h"
20
#include "powersave.h"
21
22


23
24
#ifdef FEATURE_REC_NOTIFY

25
26
27
28
29
30
31
32
#ifdef CONFIG_BLUE_LED
#define RECNOTIFY_LED (rec_notify == 3)
#define RECNOTIFY_BEEP (rec_notify == 4)
#else
#define RECNOTIFY_LED 0
#define RECNOTIFY_BEEP (rec_notify == 3)
#endif

33
34
35
36
37
#ifdef FEATURE_REC_NOTIFY_BEEP
    #ifndef CONFIG_BEEP
    #error This requires CONFIG_BEEP
    #endif
#else
alex@thinkpad's avatar
alex@thinkpad committed
38
    #undef RECNOTIFY_BEEP
39
40
41
    #define RECNOTIFY_BEEP 0
#endif

42
43
44
#endif

#ifdef FEATURE_MOVIE_REC_KEY
45
46
#define ALLOW_MOVIE_START (movie_rec_key_action == 0 || movie_rec_key_action == 1)
#define ALLOW_MOVIE_STOP  (movie_rec_key_action == 0 || movie_rec_key_action == 2)
47
48
#endif

49
void update_lvae_for_autoiso_n_displaygain();
50

51
#ifdef FEATURE_FORCE_HDMI_VGA
a1ex's avatar
a1ex committed
52
CONFIG_INT("hdmi.force.vga", hdmi_force_vga, 0);
53

54
55
56
57
static int hdmi_code_array[8];

PROP_HANDLER(PROP_HDMI_CHANGE_CODE)
{
58
    ASSERT(len == 32);
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    memcpy(hdmi_code_array, buf, 32);
}

static void ChangeHDMIOutputSizeToVGA()
{
    hdmi_code_array[0] = 2;
    prop_request_change(PROP_HDMI_CHANGE_CODE, hdmi_code_array, 32);
}

static void ChangeHDMIOutputSizeToFULLHD()
{
    hdmi_code_array[0] = 5;
    prop_request_change(PROP_HDMI_CHANGE_CODE, hdmi_code_array, 32);
} 
#endif

75
76
// WB workaround (not saved in movie mode)
//**********************************************************************
77
//~ CONFIG_INT( "white.balance.workaround", white_balance_workaround, 1);
78

79
80
81
82
static CONFIG_INT( "wb.kelvin", workaround_wb_kelvin, 6500);
static CONFIG_INT( "wbs.gm", workaround_wbs_gm, 100);
static CONFIG_INT( "wbs.ba", workaround_wbs_ba, 100);
static int kelvin_wb_dirty = 1;
83

84
85
#ifdef CONFIG_WB_WORKAROUND

86
87
void save_kelvin_wb()
{
a1ex's avatar
a1ex committed
88
89
90
91
92
    if (!lens_info.kelvin) return;
    workaround_wb_kelvin = lens_info.kelvin;
    workaround_wbs_gm = lens_info.wbs_gm + 100;
    workaround_wbs_ba = lens_info.wbs_ba + 100;
    //~ NotifyBox(1000, "Saved WB: %dK GM%d BA%d", workaround_wb_kelvin, workaround_wbs_gm, workaround_wbs_ba);
93
94
95
96
}

void restore_kelvin_wb()
{
a1ex's avatar
a1ex committed
97
98
99
100
101
102
    msleep(500); // to make sure mode switch is complete
    // sometimes Kelvin WB and WBShift are not remembered, usually in Movie mode 
    lens_set_kelvin_value_only(workaround_wb_kelvin);
    lens_set_wbs_gm(COERCE(((int)workaround_wbs_gm) - 100, -9, 9));
    lens_set_wbs_ba(COERCE(((int)workaround_wbs_ba) - 100, -9, 9));
    //~ NotifyBox(1000, "Restored WB: %dK GM%d BA%d", workaround_wb_kelvin, workaround_wbs_gm, workaround_wbs_ba); msleep(1000);
103
104
}

105
// called only in movie mode
106
107
void kelvin_wb_workaround_step()
{
a1ex's avatar
a1ex committed
108
109
110
111
112
113
114
115
116
    if (!kelvin_wb_dirty)
    {
        save_kelvin_wb();
    }
    else
    {
        restore_kelvin_wb();
        kelvin_wb_dirty = 0;
    }
117
}
118
#endif
119

120
static int ml_changing_shooting_mode = 0;
121
122
PROP_HANDLER(PROP_SHOOTING_MODE)
{
a1ex's avatar
a1ex committed
123
124
    kelvin_wb_dirty = 1;
    if (!ml_changing_shooting_mode) intervalometer_stop();
125
    #ifdef FEATURE_EXPO_OVERRIDE
a1ex's avatar
a1ex committed
126
    bv_auto_update();
127
    #endif
128
129
}

130
131
void set_shooting_mode(int m)
{
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
    if (shooting_mode == m)
    {
        /* nothing to do */
        return;
    }
    
#ifdef CONFIG_SEPARATE_BULB_MODE
    #define ALLOWED_MODE(x)  (x == SHOOTMODE_M || x == SHOOTMODE_TV || \
         x == SHOOTMODE_AV || x == SHOOTMODE_P || x == SHOOTMODE_BULB )
#else
    #define ALLOWED_MODE(x)  (x == SHOOTMODE_M || x == SHOOTMODE_TV || \
         x == SHOOTMODE_AV || x == SHOOTMODE_P )
#endif
    
    if (!ALLOWED_MODE(m) || !ALLOWED_MODE(shooting_mode))
    {
        /* only allow switching between M, Tv, Av, P and BULB */
        return;
    }
    
    #undef ALLOWED_MODE
153
    
a1ex's avatar
a1ex committed
154
    ml_changing_shooting_mode = 1;
155
156
    prop_request_change_wait(PROP_SHOOTING_MODE, &m, 4, 1000);
    msleep(500);    /* just in case, since mode switching is quite complex */
a1ex's avatar
a1ex committed
157
    ml_changing_shooting_mode = 0;
158
159
}

160
161
162
163
static CONFIG_INT("movie.restart", movie_restart,0);
static CONFIG_INT("movie.rec-key", movie_rec_key, 0);
static CONFIG_INT("movie.rec-key-action", movie_rec_key_action, 0);
static CONFIG_INT("movie.rec-key-long", movie_rec_key_long, 0);
164
165

#ifdef FEATURE_MOVIE_REC_KEY
166

167
static void movie_rec_halfshutter_step()
a1ex's avatar
a1ex committed
168
{
169
170
171
172
    if (!movie_rec_key) return;
    if (!is_movie_mode() || !liveview_display_idle() || gui_menu_shown()) return;

    if (HALFSHUTTER_PRESSED)
a1ex's avatar
a1ex committed
173
    {
174
        if (movie_rec_key_long)
175
176
177
178
179
180
181
182
183
184
185
186
        {
            // need to keep halfshutter pressed for one second
            for (int i = 0; i < 10; i++)
            {
                msleep(100);
                if (!HALFSHUTTER_PRESSED) break;
            }
            if (!HALFSHUTTER_PRESSED) return;
            info_led_on();
            NotifyBox(1000, "OK");
        }
        
187
        while (HALFSHUTTER_PRESSED) msleep(50);
188
        if (NOT_RECORDING && ALLOW_MOVIE_START) schedule_movie_start();
189
        else if(ALLOW_MOVIE_STOP) schedule_movie_end();
a1ex's avatar
a1ex committed
190
    }
a1ex's avatar
a1ex committed
191
}
192
#endif
a1ex's avatar
a1ex committed
193

194
195
196
// start with LV
//**********************************************************************

197
static CONFIG_INT( "enable-liveview",  enable_liveview,
a1ex's avatar
a1ex committed
198
199
200
201
202
203
    #ifdef CONFIG_5D2
    0
    #else
    1
    #endif
);
204

205
206
void force_liveview()
{
207
#ifdef CONFIG_LIVEVIEW
208
209
210
    extern int ml_started;
    while (!ml_started) msleep(50);

211
    msleep(50);
212
213
    if (lv) return;
    info_led_on();
214
215

    /* wait for some preconditions */
216
    while (sensor_cleaning) msleep(100);
217
    while (lens_info.job_state) msleep(100);
218
    while (get_halfshutter_pressed()) msleep(100);
219
220

    /* paused LV? */
a1ex's avatar
a1ex committed
221
222
    ResumeLiveView();
    while (get_halfshutter_pressed()) msleep(100);
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237

    if (CURRENT_GUI_MODE)
    {
        /* we may be in some Canon menu opened from LiveView */
        SetGUIRequestMode(0);
        msleep(1000);
    }

    if (!lv)
    {
        /* we are probably in photo mode */
        fake_simple_button(BGMT_LV);
        msleep(1500);
    }

238
    info_led_off();
239
240

    /* make sure LiveView is up and running */
241
    wait_lv_frames(3);
242
#endif
243
244
}

245
246
247
void close_liveview()
{
    if (lv)
248
249
250
251
252
253
254
#ifdef CONFIG_EOSM
    {
        /* To shut off LiveView switch to the info screen */
        SetGUIRequestMode(21);
        msleep(1000);
    }
#else
255
    {
256
257
258
259
260
261
262
263
264
265
266
267
268
        if (!is_movie_mode()) {
            /* in photo mode, just exit LiveView by "pressing" the LiveView button */
            fake_simple_button(BGMT_LV);
        } else {
            #if defined(CONFIG_5D2) || defined(CONFIG_50D)
            /* on these cameras, pressing the LiveView button won't start recording */
            fake_simple_button(BGMT_LV);
            #else
            /* in movie mode, pressing LiveView would start recording,
             * so go to PLAY mode instead */
            enter_play_mode();
            #endif
        }
269
270
        msleep(1000);
    }
271
#endif
272
273
}

274
static CONFIG_INT("shutter.lock", shutter_lock, 0);
275
static CONFIG_INT("shutter.lock.value", shutter_lock_value, 0);
276
277

#ifdef FEATURE_SHUTTER_LOCK
a1ex's avatar
a1ex committed
278
279
static void
shutter_lock_print(
a1ex's avatar
a1ex committed
280
281
282
283
    void *          priv,
    int         x,
    int         y,
    int         selected
a1ex's avatar
a1ex committed
284
285
)
{
a1ex's avatar
a1ex committed
286
287
288
289
290
291
    bmp_printf(
        selected ? MENU_FONT_SEL : MENU_FONT,
        x, y,
        "Shutter Lock  : %s",
        shutter_lock ? "ON" : "OFF"
    );
a1ex's avatar
a1ex committed
292
293
}

294
static void shutter_lock_step()
a1ex's avatar
a1ex committed
295
{
a1ex's avatar
a1ex committed
296
297
    if (is_movie_mode()) // no effect in photo mode
    {
298
        int shutter = lens_info.raw_shutter;
a1ex's avatar
a1ex committed
299
300
301
302
303
304
305
306
307
308
309
310
311
312
        if (shutter_lock_value == 0) shutter_lock_value = shutter; // make sure it's some valid value
        if (!gui_menu_shown()) // lock shutter
        {
            if (shutter != shutter_lock_value) // i.e. revert it if changed
            {
                //~ lens_set_rawaperture(COERCE(lens_info.raw_aperture + shutter - shutter_lock_value, 16, 96));
                msleep(100);
                lens_set_rawshutter(shutter_lock_value);
                msleep(100);
            }
        }
        else
            shutter_lock_value = shutter; // accept change from ML menu
    }
a1ex's avatar
a1ex committed
313
}
314
315
#endif

alex@thinkpad's avatar
alex@thinkpad committed
316
#ifdef CONFIG_MOVIE_RECORDING_50D_SHUTTER_HACK
a1ex's avatar
a1ex committed
317

318
CONFIG_INT("shutter.btn.rec", shutter_btn_rec, 1);
319

320
void shutter_btn_rec_do(int rec)
321
{
a1ex's avatar
a1ex committed
322
323
    if (shutter_btn_rec == 1)
    {
324
325
        if (rec) gui_uilock(UILOCK_SHUTTER);
        else gui_uilock(UILOCK_NONE);
a1ex's avatar
a1ex committed
326
327
328
329
330
331
    }
    else if (shutter_btn_rec == 2)
    {
        if (rec) SW1(1,0);
        else SW1(0,0);
    }
332
333
334
}
#endif

a1ex's avatar
a1ex committed
335
336
int movie_was_stopped_by_set = 0;

337
338
void
movtweak_task_init()
339
{
340
#ifdef FEATURE_FORCE_LIVEVIEW
a1ex's avatar
a1ex committed
341
    if (!lv && enable_liveview && is_movie_mode()
342
        && (GUIMODE_MOVIE_PRESS_LV_TO_RESUME || GUIMODE_MOVIE_ENSURE_A_LENS_IS_ATTACHED))
a1ex's avatar
a1ex committed
343
344
345
    {
        force_liveview();
    }
346
#endif
a1ex's avatar
a1ex committed
347
348
349

    extern int ml_started;
    while (!ml_started) msleep(100);
350
351

#ifdef FEATURE_EXPO_OVERRIDE
alex@thinkpad's avatar
alex@thinkpad committed
352
    bv_auto_update();
353
#endif
354
}
a1ex's avatar
a1ex committed
355

356
357
358
static int wait_for_lv_err_msg(int wait) // 1 = msg appeared, 0 = did not appear
{
    extern thunk ErrCardForLVApp_handler;
359
    for(int i = 0; i <= wait/20; i++)
360
    {
361
362
363
364
        if((intptr_t)get_current_dialog_handler() == (intptr_t)&ErrCardForLVApp_handler)
        {
            return 1;
        }
365
366
367
368
369
        msleep(20);
    }
    return 0;
}

370
371
void movtweak_step()
{
372
    #ifdef FEATURE_MOVIE_REC_KEY
373
    movie_rec_halfshutter_step();
374
    #endif
375

376
    #ifdef FEATURE_MOVIE_RESTART
a1ex's avatar
a1ex committed
377
        static int recording_prev = 0;
378
        
alex@thinkpad's avatar
alex@thinkpad committed
379
        #if defined(CONFIG_5D2) || defined(CONFIG_50D) || defined(CONFIG_7D)
380
        if(!RECORDING_H264 && recording_prev && !movie_was_stopped_by_set) // see also gui.c
a1ex's avatar
a1ex committed
381
        #else
382
        if(!RECORDING_H264 && recording_prev && wait_for_lv_err_msg(0))
a1ex's avatar
a1ex committed
383
        #endif
a1ex's avatar
a1ex committed
384
385
386
        {
            if (movie_restart)
            {
a1ex's avatar
a1ex committed
387
                msleep(500);
a1ex's avatar
a1ex committed
388
389
390
                movie_start();
            }
        }
391
        recording_prev = RECORDING_H264;
a1ex's avatar
a1ex committed
392

393
394
395
396
        if(!RECORDING_H264)
        {
            movie_was_stopped_by_set = 0;
        }
397
    #endif
a1ex's avatar
a1ex committed
398
399
400
        
        if (is_movie_mode())
        {
401
            #ifdef CONFIG_WB_WORKAROUND
a1ex's avatar
a1ex committed
402
            kelvin_wb_workaround_step();
403
            #endif
404
405
            
            #ifdef FEATURE_SHUTTER_LOCK
a1ex's avatar
a1ex committed
406
            if (shutter_lock) shutter_lock_step();
407
            #endif
a1ex's avatar
a1ex committed
408
409
        }

410
        #ifdef FEATURE_FORCE_LIVEVIEW
411
412
        if ((enable_liveview && GUIMODE_MOVIE_PRESS_LV_TO_RESUME) ||
            (enable_liveview == 2 && GUIMODE_MOVIE_ENSURE_A_LENS_IS_ATTACHED))
a1ex's avatar
a1ex committed
413
        {
414
            msleep(200);
alex@thinkpad's avatar
alex@thinkpad committed
415
            // double-check
416
417
            if ((enable_liveview && GUIMODE_MOVIE_PRESS_LV_TO_RESUME) ||
                (enable_liveview == 2 && GUIMODE_MOVIE_ENSURE_A_LENS_IS_ATTACHED))
418
                force_liveview();
a1ex's avatar
a1ex committed
419
        }
420
        #endif
421

422
        //~ update_lvae_for_autoiso_n_displaygain();
a1ex's avatar
a1ex committed
423
        
424
        #ifdef FEATURE_FORCE_HDMI_VGA
a1ex's avatar
a1ex committed
425
426
        if (hdmi_force_vga && is_movie_mode() && (lv || PLAY_MODE) && !gui_menu_shown())
        {
427
            if (hdmi_code >= 5)
a1ex's avatar
a1ex committed
428
429
            {
                msleep(1000);
430
                gui_uilock(UILOCK_EVERYTHING);
431
432
433
434
435
                BMP_LOCK(
                    ChangeHDMIOutputSizeToVGA();
                    msleep(300);
                )
                msleep(2000);
436
                gui_uilock(UILOCK_NONE);
a1ex's avatar
a1ex committed
437
438
439
                msleep(5000);
            }
        }
440
        #endif
441
442
}

443
444
static CONFIG_INT("screen_layout.lcd", screen_layout_lcd, SCREENLAYOUT_3_2_or_4_3);
static CONFIG_INT("screen_layout.ext", screen_layout_ext, SCREENLAYOUT_16_10);
445
int* get_screen_layout_ptr() { return EXT_MONITOR_CONNECTED ? &screen_layout_ext : &screen_layout_lcd; }
446
447
448
449
450
451
452
453
454
455
456
457
458
int get_screen_layout() 
{
    int s = (int) *get_screen_layout_ptr();
    if (s == SCREENLAYOUT_4_3)
    {
        // the 4:3 layout is not suitable for 640x480, or when histograms are turned off
        // use the bottom 3:2 in those cases
        if (is_movie_mode() && video_mode_resolution > 1) return SCREENLAYOUT_UNDER_3_2;
        if (!histogram_or_small_waveform_enabled()) return SCREENLAYOUT_UNDER_3_2; 
        return s;
    }
    return s;
}
459

460
461
#ifdef FEATURE_SCREEN_LAYOUT

462
463
int screen_layout_menu_index;
MENU_UPDATE_FUNC(screen_layout_update)
464
{
465
    screen_layout_menu_index = *get_screen_layout_ptr();
466
}
a1ex's avatar
a1ex committed
467

468
469
470
471
472
void screen_layout_toggle(void* priv, int delta) 
{ 
    menu_numeric_toggle(get_screen_layout_ptr(), delta, 0, 4);
    screen_layout_menu_index = *get_screen_layout_ptr();
}
473
#endif
474

475
#ifdef FEATURE_MOVIE_RECORDING_50D
476

477
static MENU_UPDATE_FUNC(lv_movie_print)
478
{
479
    MENU_SET_VALUE(
a1ex's avatar
a1ex committed
480
        lv_movie_select != 2 ? "Disabled" :
481
        video_mode_resolution == 0 ? "1920x1080, 30fps" : 
a1ex's avatar
a1ex committed
482
483
        video_mode_resolution == 2 ? "640x480, 30fps" : "Invalid"
    );
484
    MENU_SET_ENABLED(lv_movie_select == 2);
485
486
}

Rob Kramer's avatar
Rob Kramer committed
487
void lv_movie_toggle(void* priv, int delta)
488
{
a1ex's avatar
a1ex committed
489
490
491
    int newvalue = lv_movie_select == 2 ? 1 : 2;
    GUI_SetLvMode(newvalue);
    if (newvalue == 2) GUI_SetMovieSize_b(1);
492
}
a1ex's avatar
a1ex committed
493

Rob Kramer's avatar
Rob Kramer committed
494
void lv_movie_size_toggle(void* priv, int delta)
a1ex's avatar
a1ex committed
495
{
a1ex's avatar
a1ex committed
496
497
    int s = video_mode_resolution ? 0 : 2;
    GUI_SetMovieSize_a(s);
a1ex's avatar
a1ex committed
498
}
Coutts's avatar
Coutts committed
499
#endif
500

501
#ifdef CONFIG_BLUE_LED
502
503
CONFIG_INT("rec.notify", rec_notify, 3);
#else
504
CONFIG_INT("rec.notify", rec_notify, 0);
505
506
#endif

507
#ifdef FEATURE_REC_NOTIFY
a1ex's avatar
a1ex committed
508

509
void rec_notify_continuous(int called_from_menu)
a1ex's avatar
a1ex committed
510
{
a1ex's avatar
a1ex committed
511
    if (!is_movie_mode()) return;
512

513
    if (RECNOTIFY_LED) // this is non-graphical notification, should also run when display is off
514
515
516
517
518
    {
        static int k = 0;
        k++;
        if (k % 10 == 0) // edled may take a while to process, don't try it often
        {
519
            if (RECORDING) info_led_on();
520
521
522
        }
    }

a1ex's avatar
a1ex committed
523
524
    if (!zebra_should_run()) return;
    if (gui_menu_shown() && !called_from_menu) return;
525
526
527

    get_yuv422_vram();

a1ex's avatar
a1ex committed
528
529
530
531
    static int prev = 0;
    
    if (rec_notify == 1)
    {
532
        if (NOT_RECORDING)
533
        {
a1ex's avatar
a1ex committed
534
535
            int xc = os.x0 + os.x_ex/2;
            int yc = os.y0 + os.y_ex/2;
pravdomil's avatar
pravdomil committed
536
537
            int rx = os.y_ex * 6/10;
            int ry = rx * 9/16; 
a1ex's avatar
a1ex committed
538
            bmp_printf(
pravdomil's avatar
pravdomil committed
539
540
541
542
                SHADOW_FONT(FONT(FONT_MED, COLOR_WHITE, COLOR_RED)) | FONT_ALIGN_CENTER | FONT_EXPAND(4), 
                xc, yc - ry - font_med.height,
                "NOT RECORDING"
            );
a1ex's avatar
a1ex committed
543
            bmp_draw_rect(COLOR_RED, xc - rx, yc - ry, rx * 2, ry * 2);
pravdomil's avatar
pravdomil committed
544
            bmp_draw_rect(COLOR_WHITE, xc - rx + 1, yc - ry + 1, rx * 2 - 2, ry * 2 - 2);
a1ex's avatar
a1ex committed
545
            draw_line(xc + rx, yc - ry, xc - rx, yc + ry, COLOR_RED);
pravdomil's avatar
pravdomil committed
546
            draw_line(xc + rx, yc - ry + 1, xc - rx, yc + ry + 1, COLOR_WHITE);
547
        }
a1ex's avatar
a1ex committed
548
549
550
    }
    else if (rec_notify == 2)
    {
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
            int screen_layout_menu_index = *get_screen_layout_ptr();
            int rec_indic_x = os.x_max;
            int rec_indic_y = get_ml_topbar_pos() + 32;
            if (screen_layout_menu_index > 2) rec_indic_y = rec_indic_y - 60; // bottom modes need shifting up
            if (RECORDING)
            {
                bmp_printf(
                FONT(FONT_MED_LARGE, COLOR_WHITE, COLOR_RED),
                rec_indic_x - 5 * font_med.width, // substracted some pixels to hide the red dot in top 3:2 and top 16:9
                rec_indic_y,
                "REC"
                );
            }
            else
                bmp_printf(
                FONT_MED_LARGE,
                rec_indic_x - 6 * font_med.width + 5, // align with ML bars
                rec_indic_y,
                "STBY"
                );       
a1ex's avatar
a1ex committed
571
572
    }
    
573
574
    if (prev != RECORDING_STATE) redraw();
    prev = RECORDING_STATE;
a1ex's avatar
a1ex committed
575
}
a1ex's avatar
a1ex committed
576

a1ex's avatar
a1ex committed
577
578
void rec_notify_trigger(int rec)
{
579
    if (RECNOTIFY_BEEP)
a1ex's avatar
a1ex committed
580
    {
a1ex's avatar
a1ex committed
581
        if (rec != 2) { unsafe_beep(); }
582
        if (!rec) { msleep(200); unsafe_beep(); }
a1ex's avatar
a1ex committed
583
    }
584

585
586
    if (RECNOTIFY_LED)
    {
a1ex's avatar
a1ex committed
587
        if (rec != 2) info_led_on();
588
589
590
        if (!rec) info_led_off();
    }

591
#ifndef CONFIG_50D
592
    if (rec == 1 && sound_recording_mode == 1 && !fps_should_record_wav())
593
594
        NotifyBox(1000, "Sound is disabled.");
#endif
a1ex's avatar
a1ex committed
595
}
596
#endif
a1ex's avatar
a1ex committed
597

598
599

#ifdef FEATURE_EXPO_OVERRIDE
a1ex's avatar
a1ex committed
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
/**
 * Exposure override mode
 * ======================
 * 
 * This mode bypasses exposure settings (ISO, Tv, Av) and uses some overriden values instead.
 * 
 * It's good for bypassing Canon limits:
 * 
 * - Manual video exposure controls in cameras without it (500D, 50D, 1100D)
 * - 1/25s in movie mode (24p/25p) -> 1/3 stops better in low light
 * - ISO 12800 is allowed in movie mode
 * - No restrictions on certain ISO values and shutter speeds (e.g. on 60D)
 * - Does not have the LiveView underexposure bug with manual lenses
 * - Previews DOF all the time in photo mode
 * 
 * Side effects:
 * 
 * - In photo mode, anything slower than 1/25 seconds will be underexposed in LiveView
 * - No exposure simulation; it's wysiwyg, like in movie mode
 * - You can't use display gain (night vision)
 *  
 * In menu:
 * 
 * - OFF: Canon default mode.
 * - ON: only values from Expo are used; Canon graphics may display other values.
 * 
 */
a1ex's avatar
a1ex committed
627

628
static struct semaphore * bv_sem = 0;
629

630
CONFIG_INT("bv.auto", bv_auto, 0);
a1ex's avatar
a1ex committed
631

632
static MENU_UPDATE_FUNC(bv_display)
a1ex's avatar
a1ex committed
633
{
634
635
636
    extern int zoom_auto_exposure;

    if (bv_auto == 1 && !CONTROL_BV) 
637
        MENU_SET_WARNING(MENU_WARN_NOT_WORKING,
638
639
640
            (zoom_auto_exposure && lv_dispsize > 1) ? "Temporarily disabled (auto exposure on zoom)." :
            LVAE_DISP_GAIN ? "Temporarily disabled (display gain active)." :
            "Temporarily disabled."
641
        );
a1ex's avatar
a1ex committed
642
643
}

644
645
646
647
CONFIG_INT("bv.iso", bv_iso, 88);
CONFIG_INT("bv.tv", bv_tv, 111);
CONFIG_INT("bv.av", bv_av, 48);

648
void bv_enable()
a1ex's avatar
a1ex committed
649
{
650
651
    if (CONTROL_BV) return; // already enabled, nothing to do
    
a1ex's avatar
a1ex committed
652
    //~ bmp_printf(FONT_LARGE, 50, 50, "EN     ");
653
654
    take_semaphore(bv_sem, 0);

a1ex's avatar
a1ex committed
655
656
657
    //~ bmp_printf(FONT_LARGE, 50, 50, "ENable ");
    call("lvae_setcontrolbv", 1);

658
659
660
    int auto_movie = (ae_mode_movie == 0) && is_movie_mode();

    if (auto_movie) // auto movie mode
a1ex's avatar
a1ex committed
661
    {
662
663
664
        bv_apply_tv(bv_tv);
        bv_apply_av(bv_av);
        bv_apply_iso(bv_iso);
a1ex's avatar
a1ex committed
665
666
667
    }
    else // manual movie mode or photo mode, try to sync with Canon values
    {
668
669
670
671
672
673
        bv_tv = lens_info.raw_shutter && ABS(lens_info.raw_shutter - bv_tv) > 4 ? lens_info.raw_shutter : bv_tv;
        bv_av = lens_info.raw_aperture ? lens_info.raw_aperture : bv_av;
        bv_iso = lens_info.raw_iso ? lens_info.raw_iso - (get_htp() ? 8 : 0) : bv_iso;
        bv_apply_tv(bv_tv);
        bv_apply_av(bv_av);
        bv_apply_iso(bv_iso);
a1ex's avatar
a1ex committed
674
675
    }
    
676
    CONTROL_BV_ZERO = 0;
a1ex's avatar
a1ex committed
677
    bv_update_lensinfo();
a1ex's avatar
a1ex committed
678

679
680
    give_semaphore(bv_sem);
}
a1ex's avatar
a1ex committed
681

682
void bv_disable()
a1ex's avatar
a1ex committed
683
{
a1ex's avatar
a1ex committed
684
    //~ bmp_printf(FONT_LARGE, 50, 50, "DIS    ");
685
686
687
    take_semaphore(bv_sem, 0);

    if (!CONTROL_BV) goto end;
a1ex's avatar
a1ex committed
688
689
    call("lvae_setcontrolbv", 0);
    CONTROL_BV_TV = CONTROL_BV_AV = CONTROL_BV_ISO = CONTROL_BV_ZERO = 0; // auto
690
    if (!lv) goto end;
691
692
    
    iso_auto_restore_hack();
693
    set_photo_digital_iso_gain_for_bv(1024);
a1ex's avatar
a1ex committed
694

a1ex's avatar
a1ex committed
695
    //~ bmp_printf(FONT_LARGE, 50, 50, "DISable");
696
697
698

end:
    give_semaphore(bv_sem);
a1ex's avatar
a1ex committed
699
700
}

701
void bv_toggle(void* priv, int delta)
a1ex's avatar
a1ex committed
702
{
703
    menu_numeric_toggle(&bv_auto, delta, 0, 1);
704
705
706
707
708
709
710
    if (bv_auto) bv_auto_update();
    else bv_disable();
}

PROP_HANDLER(PROP_LIVE_VIEW_VIEWTYPE)
{
    bv_auto_update();
a1ex's avatar
a1ex committed
711
}
712
#endif
a1ex's avatar
a1ex committed
713

714
715
716
717
//~ CONFIG_INT("lvae.iso.min", lvae_iso_min, 72);
//~ CONFIG_INT("lvae.iso.max", lvae_iso_max, 104);
//~ CONFIG_INT("lvae.iso.spd", lvae_iso_speed, 10);
//~ CONFIG_INT("lvae.disp.gain", lvae_disp_gain, 0);
718

719
CONFIG_INT("iso.smooth", smooth_iso, 0);
720
static CONFIG_INT("iso.smooth.spd", smooth_iso_speed, 2);
721

722
723
724
725
726
727
728
729
730
731
#ifdef FEATURE_GRADUAL_EXPOSURE

#ifndef CONFIG_FRAME_ISO_OVERRIDE
#error This requires CONFIG_FRAME_ISO_OVERRIDE. 
#endif

#ifndef FEATURE_EXPO_ISO_DIGIC
#error This requires FEATURE_EXPO_ISO_DIGIC. 
#endif

732
733
void smooth_iso_step()
{
734
    static int iso_acc = 0;
735
736
    if (!smooth_iso) 
    { 
737
        fps_expo_iso_step();
738
739
        iso_acc = 0; return; 
    }
740
741
742
    if (!is_movie_mode()) { iso_acc = 0; return; }
    if (!lv) { iso_acc = 0; return; }
    if (!lens_info.raw_iso) { iso_acc = 0; return; } // no auto iso
743
    
alex@thinkpad's avatar
alex@thinkpad committed
744
    static int prev_bv = (int)0xdeadbeef;
745
    #ifdef FRAME_BV
746
    int current_bv = FRAME_BV;
747
748
749
    #else
    int current_bv = -(FRAME_ISO & 0xFF);
    #endif
750
    int current_iso = FRAME_ISO & 0xFF;
751
    
752
    //~ static int k = 0; k++;
753
    
754
755
    static int frames_to_skip = 30;
    if (frames_to_skip) { frames_to_skip--; prev_bv = current_bv; return; }
756
    
alex@thinkpad's avatar
alex@thinkpad committed
757
    if (prev_bv != current_bv && prev_bv != (int)0xdeadbeef)
758
    {
759
        iso_acc -= (prev_bv - current_bv) * (1 << smooth_iso_speed);
760
        iso_acc = COERCE(iso_acc, -8 * 8 * (1 << smooth_iso_speed), 8 * 8 * (1 << smooth_iso_speed)); // don't correct more than 8 stops (overflow risk)
761
762
763
    }
    if (iso_acc)
    {
764
        float gf = 1024.0f * powf(2, iso_acc / (8.0f * (1 << smooth_iso_speed)));
765
766
767

        // it's not a good idea to use a digital ISO gain higher than +/- 0.5 EV (noise or pink highlights), 
        // so alter it via FRAME_ISO
768
        int digic_iso_gain_movie = get_digic_iso_gain_movie();
769
        #define G_ADJ ((int)roundf(digic_iso_gain_movie ? gf * digic_iso_gain_movie / 1024 : gf))
770
        int altered_iso = current_iso;
771
        while (G_ADJ > 861*2 && altered_iso < MAX_ANALOG_ISO) 
772
773
        {
            altered_iso += 8;
774
            gf /= 2;
775
        }
776
        while ((G_ADJ < 861 && altered_iso > 80) || (altered_iso > MAX_ANALOG_ISO))
777
        {
778
            altered_iso -= 8;
779
            gf *= 2;
780
        }
781
782
783
784
785
786
        
        #ifdef CONFIG_FRAME_SHUTTER_OVERRIDE
        // if ISO should go under 100, try a faster shutter speed
                
        int current_shutter = FRAME_SHUTTER_TIMER;
        int altered_shutter = current_shutter;
787

788
789
790
791
792
        while (G_ADJ < 861)
        {
            altered_shutter = MAX(2, altered_shutter / 2);
            gf *= 2;
        }
793

794
795
796
797
        if (altered_shutter != current_shutter)
        {
            FRAME_SHUTTER_TIMER = altered_shutter;
        }
798
        
799
        // fix imperfect sync
800
801
        // only do this when shutter speed is overriden by ML, not by user
        static int prev_shutter = 0;
802
        static int prev_altered_shutter = 0;
803
804
805
806
807
        if (prev_shutter && prev_altered_shutter && 
            prev_altered_shutter != altered_shutter && 
            prev_shutter == current_shutter
            )
        {
808
            gf = gf * altered_shutter / prev_altered_shutter;
809
        }
810
        prev_altered_shutter = altered_shutter;
811
812
        prev_shutter = current_shutter;
        
813
        #endif
814

815
        if (altered_iso != current_iso)
816
        {
817
            FRAME_ISO = altered_iso | (altered_iso << 8);
818
        }
819
820
821
822
823

        #if defined(CONFIG_5D2) || defined(CONFIG_550D) || defined(CONFIG_50D)
        // FRAME_ISO not synced perfectly, use digital gain to mask the flicker
        static int prev_altered_iso = 0;
        if (prev_altered_iso && prev_altered_iso != altered_iso)
824
            gf = gf * powf(2, (altered_iso - prev_altered_iso) / 8.0);
825
        prev_altered_iso = altered_iso;
826
        
827
828
        // also less than perfect sync when shutter speed is changed
        #ifdef FRAME_SHUTTER
829
830
831
832
        static int prev_tv = 0;
        int tv = FRAME_SHUTTER;
        if (prev_tv && prev_tv != tv)
        {
833
            gf = gf * powf(2, (prev_tv - tv) / 8.0);
834
835
        }
        prev_tv = tv;
836
        #endif
837
        #endif
838
839
840
841
842


        int g = (int)roundf(COERCE(gf, 1, 1<<20));
        if (g == 1024) g = 1025; // force override 

843
        set_movie_digital_iso_gain_for_gradual_expo(g);
844
        if (iso_acc > 0) iso_acc--; else iso_acc++;
845

846
    }
847
    else set_movie_digital_iso_gain_for_gradual_expo(1024);
848
    
849
    
850
    prev_bv = current_bv;
851
852
853
854
855
856
857
858
859
    
    // display a little progress bar

    int x0 = os.x0 + os.x_ex/2;
    int y0 = os.y_max - 2;
    int w = COERCE(iso_acc * 8 / (1 << smooth_iso_speed), -os.x_ex/2, os.x_ex/2);
    static int prev_w = 0;
    if (w || w != prev_w)
    {
alex@thinkpad's avatar
alex@thinkpad committed
860
861
        draw_line(x0, y0, x0 + w, y0, iso_acc > 0 ? COLOR_RED : COLOR_LIGHT_BLUE);
        draw_line(x0, y0 + 1, x0 + w, y0 + 1, iso_acc > 0 ? COLOR_RED : COLOR_LIGHT_BLUE);
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
        if (prev_w != w)
        {
            draw_line(x0 + w, y0, x0 + prev_w, y0, COLOR_BLACK);
            draw_line(x0 + w, y0 + 1, x0 + prev_w, y0 + 1, COLOR_BLACK);
        }
        for (int i = 64; i < ABS(w); i += 64) // mark full stops
        {
            int is = i * SGN(w);
            draw_line(x0 + is, y0, x0 + is, y0 + 1, COLOR_BLACK);
            draw_line(x0 + is + 1, y0, x0 + is + 1, y0 + 1, COLOR_BLACK);
        }
        
        prev_w = w;
    }

877
}
878
#endif
879

880
static struct menu_entry mov_menus[] = {
881
    #ifdef FEATURE_MOVIE_RECORDING_50D
a1ex's avatar
a1ex committed
882
883
884
885
    {
        .name       = "Movie Record",
        .priv       = &lv_movie_select,
        .select     = lv_movie_toggle,
a1ex's avatar
a1ex committed
886
        .select_Q   = lv_movie_size_toggle,
887
        .update     = lv_movie_print,
a1ex's avatar
a1ex committed
888
        .help       = "Enable movie recording on 50D :) ",
889
        .depends_on = DEP_LIVEVIEW,
a1ex's avatar
a1ex committed
890
    },
891
    #endif
alex@thinkpad's avatar
alex@thinkpad committed
892
    #ifdef CONFIG_MOVIE_RECORDING_50D_SHUTTER_HACK
a1ex's avatar
a1ex committed
893
894
895
    {
        .name = "Shutter Button",
        .priv = &shutter_btn_rec,
896
        .max  = 2,
897
898
899
        .choices = CHOICES("Leave unchanged", "Block during REC", "Hold during REC"),
        .help  = "Block shutter button while recording (avoids ERR99)",
        .help2 = "or hold it pressed halfway (enables image stabilization).",
900
        .depends_on = DEP_MOVIE_MODE,
a1ex's avatar
a1ex committed
901
    },
902
    #endif
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930

    #ifdef FEATURE_MOVIE_REC_KEY
    {
        .name = "REC key",
        .priv = &movie_rec_key, 
        .max = 1,
        .icon_type = IT_BOOL,
        .choices = CHOICES("OFF", "HalfShutter"),
        .help = "Start recording by pressing shutter halfway. Wired remote.",
        .submenu_width = 700,
        .depends_on = DEP_MOVIE_MODE,
        .children =  (struct menu_entry[]) {
            {
                .name = "Require long press",
                .priv = &movie_rec_key_long,
                .max = 1,
                .icon_type = IT_BOOL,
                .choices = CHOICES("OFF", "ON (1s)"),
                .help = "If ON, you have to hold half-shutter pressed for 1 second.",
            },
            {
                .name = "Allowed actions",
                .priv = &movie_rec_key_action,
                .max = 2,
                .icon_type = IT_DICE,
                .choices = CHOICES("Start/Stop", "Start only", "Stop only"),
                .help = "Select actions for half-shutter.",
            },
931
            MENU_EOL,
932
933
934
935
936
        },
    },
    #endif
    #ifdef FEATURE_GRADUAL_EXPOSURE
    {
a1ex's avatar
a1ex committed
937
        .name = "Gradual Exposure",
938
939
940
        .priv = &smooth_iso,
        .max = 1,
        .help   = "Use smooth exposure transitions, by compensating with ISO.",
a1ex's avatar
a1ex committed
941
        .help2  = "=> adjust ISO, shutter speed and aperture without large jumps.",
942
943
944
945
946
947
948
949
950
        .submenu_width = 700,
        .depends_on = DEP_MOVIE_MODE | DEP_MANUAL_ISO,
        .children =  (struct menu_entry[]) {
            {
                .name = "Ramping speed",
                .priv       = &smooth_iso_speed,
                .min = 1,
                .max = 7,
                .icon_type = IT_PERCENT,
a1ex's avatar
a1ex committed
951
                .choices = CHOICES("1 EV / 8 frames", "1 EV / 16 frames", "1 EV / 32 frames", "1 EV / 64 frames", "1 EV / 128 frames", "1 EV / 256 frames", "1 EV / 512 frames"),
952
953
954
955
956
957
958
959
960
                .help = "How fast the exposure transitions should be.",
            },
            MENU_EOL
        },
    },
    #endif
};

static struct menu_entry movie_tweaks_menus[] = {
a1ex's avatar
a1ex committed
961
    {
962
        .name = "Movie Tweaks",
963
964
        .select = menu_open_submenu,
        .help = "Movie Restart, Movie Logging, REC/Standby Notify...",
965
        .depends_on = DEP_MOVIE_MODE,
966
        .submenu_width = 710,
967
968
969
970
971
972
973
974
975
        .children =  (struct menu_entry[]) {
                #ifdef FEATURE_MOVIE_RESTART
                {
                    .name = "Movie Restart",
                    .priv = &movie_restart,
                    .max        = 1,
                    .help = "Auto-restart movie recording, if it happens to stop.",
                    .depends_on = DEP_MOVIE_MODE,
                },
976
                #endif
977
978
979
980
981
982
983
984
985
986
987