CHDK Wiki
Register
Advertisement

This wiki page presents a script written to provide manual control of exposure settings during the video recording. It should work with all CHDK enabled Canon P&S cameras. Please check if your model has been tested (below) and if not, please report any testing results.

Forum Thread  : Video Manual Control

Download Link :  videxp3.lua


Operation[]

Videxp2

To use this script, place the camera into video recording mode. When the script is activated, a GUI input box will open on the bottom of the camera LCD screen. Use the camera keyboard keys Directional buttons to control the GUI. The right & left keys change fields. The up & down keys to change the exposure values in each field. Use the DISP/SET button to start and stop video recording. The MENU key or a shutter button full press will end script execution. !!! Note !!! :  using this script requires that Lua Native Calls be enabled in the CHDK Miscellaneous menu.  See the warning below about the use of native calls.

Configuration[]

Configuration Options are :

Videxp3
  • Starting Tv (sec) :  set the default shutter speed to be used when the script starts
  • Starting Av (f-stop) : set the default lens aperture opening to be used when the script starts
  • Starting ISO : set the default ISO sensitivity setting to be use used when the script starts
  • ISO Max : set the maximum value the script will allow for ISO adjustment.  One some cameras, too high a value will cause the script to shut down
  • Show start message : enables a startup help screen
  • Debug mode :  enable the script console - useful if the script does not seem to be working.

Warning[]

Use this script at you own risk.  This script makes native calls to the Canon firmware in order to manipulate exposure settings during video recording.  While it is generally believed safe to do so,  and this code has been tested on many camera models, it is potentially more risky than standard CHDK activities.  

Results may also vary between different camera models so if you test this script and find it works for your camera please report it here.

Tested Cameras[]

(please add any additional cameras tested here - please note any failures too)

  • A Series:
    • A570 (ISO 3200 works)
    • A720
    • A1200
    • A2000 (ISO 3200 works)
    • A2500 (*)
  • G series:
    • G10
    • G11
    • G1X needs a special version of the script [ <-- currently unavailable as it was posted on a personal repository. However, the 3.4 script version available at the download link at the top of this page was reported to work correctly with the G1X in the forum discussion for this script ] to make it work you must disable script autostart and not activate the script before the sensor has time to settle. This script also adds supports for aperture down to f/16 for outdoor video shooting
    • G12 ( Failed with script versions prior to 3.3)
    • G15
  • IXUS series:
    • IXUS 115HS/ELPH 100HS (worked until video record is pressed. Then manual shutter speed fails. Iso works.)
    • IXUS120_SD940
    • Elph 300/Ixus 220 HS (works until video recording is started, or don't waste your time installing this script)
  • S series:
    • S95 (Seems to be working well, but can't figure out how to focus when using this script. However, the camera does focus at the beginning of the take if you hold down the FUNC button as you are starting to record). 
    • S100 
    • S110 
  • SX series:
    • S3 works perfectly only in video mode
    • SX10 works perfectly only in video mode
    • SX100i0
    • SX130is
    • SX150is
    • SX160is
    • SX220HS
    • SX260HS
    • SX410IS works but will crash very frequently. Other than that it sets the Tv/Av/ISO just fine.
    • SX30 works perfectly only in video mode
    • SX40 needs a special version of the script, to make it work you must disable script autostart and not activate the script before the sensor has time to settle
    • SX50HS (Hangs when ISO 3200 selected, works fine otherwise if mode dial set to Video)
    • SX230HS: (Works great! Thanks - stop/start record with func set. Script may cause issues issues with live view in manual mode; turn camera off then back on if that happens, Functioning ISO range is 80-1250. Iso 1600 when used will darken the image quite a lot, thus eliminates the use of an ND filter when coupled with low f stops like f/10 and f/11
    • SX510HS: (Hangs when ISO 3200 is selected, makes camera slighly unestable, even when the script isn't running, I recommend to turn off the camera and turning it back on without chdk after using it, if you restart it with chdk on, it will crash after a few minutes. However, you can follow this pattern to keep your camera stable when running chdk [CRASH / TURN OFF - NO CHDK - TURN OFF - TURN ON W/ PLAY MODE - ACTIVATE CHDK])
    • SX530HS: Works great and ISO goes up to 3200. Great job coders!

(*) There is no video recording mode on the A2500, only a red button to start/stop video recording. But you can use still the script as follows :

  • press shutter in ALT mode to start the script running
  • an error message will says "Camera not in video mode" - ignore it
  • use the arrow keys to show/modify Tv, Av and Sv parameters
  • press the FUNC/SET button to start & stop video recording
  • press the shutter or MENU button to stop the script
  • repeat these steps as desired

WARNING: don't activate Debug mode in the script, it freezes the recording.

Failures :

  • Inability to manually set shutter speed.
  • Inability to manually set the aperture.
  • Inability to manually set the ISO.

Lua Script[]

videxp3.lua : for CHDK v1.3.0 or greater

hint :  you can download the most recent version of the script from the link posted at the top of this page

--[[
@title Video Exp Ctrl v3.1

original script by fudgey 2010/08/23
http://chdk.setepontos.com/index.php?topic=5295.msg68622#msg68622
modified 2013/11/29 by waterwingz & msl

@param     t Starting Tv (sec)
  @default t 3
  @values  t 1/30 1/60 1/100 1/200 1/400 1/640 1/800 1/1000 1/1250 1/1600 1/2000
@param     a Starting Av (f-stop)
  @default a 7
  @values  a 1.8 2.0 2.2 2.6 2.8 3.2 3.5 4.0 4.5 5.0 5.6 6.3 7.1 8.0
@param   p Starting ISO 
  @default p 1
  @values  p 80 100 200 400 800 1250 1600
@param     q ISO Max
  @default q 4
  @values  q 100 200 400 800 1250 1600 3200
@param     s Show Start Message ?
  @default s 1
  @range   s 0 1
@param     d Debug Mode ?
  @default d 0
  @range   d 0 1
--]]

require("drawings")
props=require("propcase")

--  ========================== Functions ================================= 

function restore()
  if ( get_movie_status() == 4 ) then
    if ( vbutton == 1 ) then press("video") sleep(500) release("video")
    else press("shoot_full") sleep(250) release("shoot_full") end
  end
  set_aelock(0)
  set_console_autoredraw(0)
end

tv_ref = {    -- note : tv_ref values set 1/2 way between shutter speed values
     464,  496,  528,  560,  592,  624,  656,
     688,  720,  752,  784,  816,  848,  880,  912,  944,  976,
    1008, 1040, 1072, 1096, 1129, 1169, 1192, 1225, 1265, 1376  }

tv_val = { 
       400,
       471,  511,  542,  567,  607,  638,  669,
       703,  734,  765,  799,  830,  861,  895,  926,  957,  988,
      1022, 1053, 1084, 1118, 1149, 1180, 1214, 1245, 1276 }
    
tv_str = {
      "err",
      "1/30", "1/40", "1/50", "1/60", "1/80", "1/100", "1/125",
     "1/160", "1/200", "1/250","1/320","1/400","1/500","1/640","1/800","1/1000","1/1250",
    "1/1600","1/2000","1/2500","1/3200","1/4000","1/5000","1/6400","1/8000","1/10000","hi"  }

function print_tv(val)
    if ( val == nil ) then return("-") end
    local i = 1
    while (i <= #tv_ref) and (val > tv_ref[i]) do i=i+1 end
    return tv_str[i]
end

av_table = {163, 192, 218, 254, 285, 322, 347, 384, 417, 446, 477, 510, 543, 576, 609, 638, 664, 710, 731, 768}

function print_av(val)
    if ( val == nil ) then return("-") end
    local fstop=av96_to_aperture(val)
    return((fstop/1000).."."..(fstop%1000)/100)
end

sv_table = { 380, 411, 507, 603, 699, 795, 891 } 
function print_sv(val)
    if ( val == nil ) then return("-") end
    return( ((iso_real_to_market(sv96_to_iso(val))+5)/10)*10 )
end

function screen_w()     -- lookup table for 480 px screen
    local cams = "ixus110_sd960|ixus200_sd980|ixus240_elph320hs|ixus300_sd4000|ixus310_elph500hs|ixus1000_sd4500|sx1|sx210is|sx220hs|sx230hs"
    return string.find(cams, get_buildinfo().platform) and 480 or 360
end

function help_screen()
    local x = screen_w()/2 - 132
    local help_msg = { "HELP SCREEN","FUNC/SET : start/stop video","\017 \016 : change field", "\030 \031 : change value",  "MENU : exit", "FULLPRESS : exit", "Press any key to start", " "}
    local i=1
    while (i < #help_msg) do 
        msg = "                          "..(help_msg[i]).."                          "
        inx = string.find(msg,":")
        if (inx ~= nil) then
            draw.add( "string", x, i*16+64, string.sub(msg, inx-12, inx+18), "red","white")
        else
            draw.add( "string", x, i*16+64, string.sub(msg, (#msg/2)-12, (#msg/2)+18),"white", "blue")
        end
        i=i+1
    end
    rec,vid,mode=get_mode()
    if (vid ~= true) then
        msg ="                           ".."**Camera not in video mode**".."                          "    
        draw.add( "string", x, i*16+64, string.sub(msg, (#msg/2)-12, (#msg/2)+18), "yellow","red")
    end
    repeat
        draw.overdraw()
        wait_click(100)
    until not(is_key("no_key"))
    draw.clear()
end

function draw_box()
  local fg, bg = "blue" , "black"
  local w = box_width
  local h = box_height
  --if (gb ~= "trans") then 
  draw.add("rectf",  xpos-1,     ypos-6, xpos+w+1, ypos+h+1, bg, bg)
  --end
  draw.add("string", xpos,       ypos-6, "   Tv     Av    Sv", fg, bg)
  draw.add("line",   xpos,       ypos,   xpos+20,   ypos,   fg)
  draw.add("line",   xpos+45,    ypos,   xpos+70,   ypos,   fg)
  draw.add("line",   xpos+100,   ypos,   xpos+120,  ypos,   fg)
  draw.add("line",   xpos+150,   ypos,   xpos+w,  ypos,   fg)
  draw.add("line",   xpos,       ypos,   xpos,      ypos+h, fg)
  draw.add("line",   xpos+w,     ypos,   xpos+w,    ypos+h, fg)
  draw.add("line",   xpos,       ypos+h, xpos+w,    ypos+h, fg)
end

function init_values()
    local fg, bg = "blue" , "black"
    val1=draw.add("string", xpos+6,   ypos+12, " -",   fg, bg)
    val2=draw.add("string", xpos+76,  ypos+12, " -" ,  fg, bg)
    val3=draw.add("string", xpos+120, ypos+12, " -" ,  fg, bg)
end

function show_values(Tv, Av, Sv)
    local fg, bg = "white" , "black"
    local fg1, fg2, fg3, fg4, bg1, bg2, bg2 , bg3, bg4
    if(gui_index==0) then fg1 = bg bg1=fg else fg1 = fg bg1=bg end
    if(gui_index==1) then fg2 = bg bg2=fg else fg2 = fg bg2=bg end
    if(gui_index==2) then fg3 = bg bg3=fg else fg3 = fg bg3=bg end
    draw.replace(val1, "string",  xpos+6,  ypos+12, string.sub(" "..print_tv(Tv).."      ",0,8), fg1, bg1)
    draw.replace(val2, "string", xpos+76,  ypos+12, string.sub(" "..print_av(Av).."      ",0,5), fg2, bg2)
    draw.replace(val3, "string", xpos+120, ypos+12, string.sub(" "..print_sv(Sv).."      ",0,5), fg3, bg3)
end

function adjust_value(inx, offset)
    local i=1
    if     (inx==0 ) then                                               -- adjust Tv value
        while (i <= #tv_ref) and ( tv96 > tv_ref[i]) do i=i+1 end
        if ( offset > 0 ) then tv96=tv_val[math.min(#tv_val,i+1)]      
        else  tv96=tv_val[math.max(2,i-1)] end
        while (i <= #tv_ref) and ( tv96 > tv_val[i]) do i=i+1 end 
        tv96ret=call_event_proc("SetAE_ShutterSpeed",tv96) 
        if ((tv96ret < tv96-96) or (tv96ret > tv96+96))then             -- clamp values beyond cameras range
            print("clamp", tv96ret)
            tv96=tv96ret 
        end       
        print("new Tv96=",tv96)
    elseif (inx==1) then                                                -- adjust Av value
        av96old = av96
        while (i <= #av_table) and ( av96 > av_table[i]) do i=i+1 end
        if ( offset > 0)  then  
            repeat                                                      -- find next f-stop value the camera will accept
                av96=av_table[math.min(#av_table,i)]
                av96ret=call_event_proc("MoveIrisToAv",av96)
                i=i+1
            until (i > #av_table) or (av96ret>av96old)
            av96=av96ret
        else
            repeat
                i=i-1
                av96=av_table[math.max(1,i)]
                av96ret=call_event_proc("MoveIrisToAv",av96)
            until (i==1) or (av96ret<av96old)
            av96=av96ret
        end
        print("new Av96=",av96)
    elseif (inx==2) then                                                -- adjust Sv value
        while (i <= #sv_table) and ( sv96 > sv_table[i]) do i=i+1 end
        if ( offset > 0)  then  sv96=sv_table[math.min(#sv_table,i+1)]
        else  sv96=sv_table[math.max(1,i-1)] end
        call_event_proc("SetCDSGain",sv96)
        print("new Sv96=",sv96)
    end
end

--  ========================== Main Program ================================= 

    tv_table    = { 471, 567, 640, 736, 832, 896, 928, 960, 992, 1024, 1056, 1180, 1276}
    tv96target  = tv_table[t+1]
    av_table    = { 171, 192, 218, 265, 285, 322, 347, 384, 417, 446, 477, 510, 543, 576 }
    av96target  = av_table[a+1]
    sv_table    = { 381, 411, 507, 603, 699, 761, 795, 891 }
    sv96target  = sv_table[p+1]
    sv96max     = sv_table[p+2]

    xpos =  screen_w()/2 -110               -- msl: 360 or 480 px for default screen position & size (upper left hand corner)
    ypos =  175                             -- msl: above the warning text of the unlimited video recording time
    box_width = 170
    box_height = 32
    set_console_layout(1 ,4, 45, 16 )
    
    bi=get_buildinfo()
    print(string.format("%s %s-%s %s %s %s", bi.version, bi.build_number, bi.build_revision, bi.platform, bi.platsub, bi.build_date))
    version= tonumber(string.sub(string.gsub(get_buildinfo().build_number, "%p", ""), 0, 3))
    if ( tonumber(bi.build_revision) > 0 ) then build = tonumber(bi.build_revision)
    else build = tonumber(string.match(bi.build_number,'-(%d+)$')) end

    if ( version < 130) or ( build < 3250)  then 
        error("CHDK 1.3.0 or higher, build 3250 or higher, required")
    end
    if (type(call_event_proc) ~= "function" ) then                      -- need native calls turned on
        error("Lua native calls not enabled")
    end 
    if (call_event_proc("FA.Create") == -1) then                        -- required for event procedures SetAE_ShutterSpeed, MoveIrisToAv, SetCDSGain
        error("FA CREATE failed")
    end
    if (call_event_proc("InitializeAdjustmentSystem") == -1) then
        error("InitializeAdjustmentSystem failed")
    end

 -- switch to shooting mode & make sure we are in a video mode
    if ( get_mode() == false ) then
       sleep(1000)
       set_record(1)
       while ( get_mode() == false) do sleep(100) end
    end
    sleep(500)

 -- setup splash screen & console 
    set_console_autoredraw(d -1)
    cls()  
    if (s==1) then help_screen() end    
    set_exit_key("no_key")                                              -- use "menu" key to exit so that recording gets stopped if running
    set_draw_title_line(0)
    vbutton = get_video_button()
    
-- startup values 
    set_aelock(1)                                                      -- go to manual exposure mode 
    tv96=call_event_proc("SetAE_ShutterSpeed",tv96target)
    av96=call_event_proc("MoveIrisToAv",av96target)
    call_event_proc("SetCDSGain",sv96target) 
    sv96=sv96target
    
    draw_box()
    init_values()
    gui_index=0
    
    while true do
        show_values(tv96, av96, sv96) 
        repeat
           draw.overdraw()
           wait_click(200)
        until not(is_key("no_key"))
        if     is_pressed("set")   then
            if ( vbutton == 1 ) then press("video") sleep(1000) release("video") sleep(1000)
            else press("shoot_full") sleep(1000) release("shoot_full") sleep(1000) end
        elseif is_pressed("left")  then
            if gui_index > 0 then gui_index = gui_index - 1 end
        elseif is_pressed("right") then
            if gui_index < 2 then gui_index = gui_index + 1 end
        elseif ( is_key("up")) then
           adjust_value(gui_index, 1)
        elseif ( is_key("down")) then
           adjust_value(gui_index, -1)
        elseif ( is_key("zoom_in")) then
            press("zoom_in")
            while(is_pressed("zoom_in")) do sleep(20) end
            release("zoom_in")
        elseif ( is_key("zoom_out")) then
            press("zoom_out")
            while(is_pressed("zoom_out")) do sleep(20) end
            release("zoom_out")
        elseif (is_pressed("menu") or is_pressed("shoot_full"))  then break
        end
    end
    restore()
Advertisement