Click here to Skip to main content
11,490,282 members (35,236 online)
Click here to Skip to main content

Canon EDSDK Tutorial in C#

, 24 Apr 2015 LGPL3 123.3K 8K 115
Rate this:
Please Sign up or sign in to vote.
A tutorial about the Canon SDK to remotly control DSLR cameras. From taking photos to using the LiveView.

Canon EDSDK Tutorial in C#

Introduction

The Canon EOS Digital SDK is a quite powerful SDK to remote control Canon DSLRs. Unfortunatly it is quite difficult to find some good examples for it on the internet and the provided documentation is not very complete. Since I have found out many things already and want to make it easier for others I thought I could compile some of the most important things together and do a tutorial.

This tutorial includes:

  • Init and terminate the SDK
  • Get connected cameras
  • Open and close a session with a camera
  • Get and set camera settings
  • Get a list of available settings
  • Take photos (normally and in Bulb mode)
  • Record videos
  • Press the shutter button remotely
  • Download data (images, films) from the camera
  • Start and view the live view
  • Control the focus
  • Lock and unlock the camera UI
  • Get an image thumbnail
  • Get folders and files on the camera

Note: I'm not affiliated with or funded by Canon Inc. in any way

I do not guarantee for this software in any way. Use at your own risk!

Full Library

This article and the attached project is made to learn how to use the SDK and is therefore not always most elegant or useful for production use.

If you are only looking for a production ready library to handle the SDK, head over to my homepage and look at the EDSDK API project

It is much more elegant and includes a lot of practical methods and properties as well as a raw image processing class. It runs on both Windows and Mac. Also, it is not dependent on any graphics library but contains well integrated helper for System.Drawing and WPF.

Background

You have to have a copy of the Canon EDSDK to get this working. (I think) I am not allowed to include the dlls within the project so you'll have to apply to get them, here:

Once you have the DLLs, put them beside your executable. Other places will cause problems if the main DLL makes a call to a sub-DLL.

It is also important that you use your camera in fully manual or at least half-automated mode for some methods to work.

Using the code

The solution consists of three projects:

  • EDSDKLib: The main project where all the SDK and camera handling happens
  • WinFormsUI: An example project that consumes the EDSDKLib and uses it in a Windows Forms UI application
  • WPFUI: An example project that consumes the EDSDKLib and uses it in a WPF UI application

I will only concentrate on the EDSDKLib project here since this is what this whole article is about: Using the EDSDK with C#

First let us look at the classes

  • SDKHandler: The most important class as it handles all the SDK calls and events
  • Camera: This is a simple container for a pointer and some camera related info
  • CameraValues: A static class that contains a list of Av, Tv and ISO IDs and their string representation. It is not necessary but very helpful for user interaction.
  • CameraFileEntry: A helper class that stores informations about a file entry in the camera. E.g. the file/folder name, the thumbnail of an image etc.
  • EDSDK: This class comes from the SDK and contains all the native calls to the DLLs, some IDs, enums, some helper methods and struct definitions.

Since all the important stuff is in the SDKHandler class, this is what we will look at now.

First, there are some important global variables declared:

  • Camera MainCamera: The used camera
  • bool CameraSessionOpen: States if a session with the MainCamera is opened
  • bool IsLiveViewOn: States if the live view is on or not
  • bool IsFilming: States if camera is recording or not
  • string ImageSaveDirectory: Directory to where photos will be saved (if SaveTo is set to Host or Both)
  • EDSDK.EdsRect Evf_ZoomRect: The focus and zoom border rectangle for live view (set after first use of live view)
  • EDSDK.EdsPoint Evf_ZoomPosition: The focus and zoom border position of the live view (set after first use of live view)
  • EDSDK.EdsPoint Evf_ImagePosition: The cropping position of the enlarged live view image (set after first use of live view)
  • EDSDK.EdsSize Evf_CoordinateSystem: The live view coordinate system (set after first use of live view)
  • bool IsCoordSystemSet: States if the Evf_CoordinateSystem is already set
  • uint Error: Handles errors that happen with the SDK
  • Queue<Action> LvQueue: To ensure safe camera communication while live view is on, commands get queued.
  • bool DownloadVideo: States if a finished video should be downloaded from the camera
  • uint PrevSaveTo: For video recording, SaveTo has to be set to Camera. This is to store the previous setting until after the filming.
  • Thread LVThread: The thread on which the live view images will get downloaded continuously

Also, there are some events from the SDK:

  • SDKCameraAddedEvent
  • SDKObjectEvent
  • SDKProgressCallbackEvent
  • SDKPropertyEvent
  • SDKStateEvent

And some events declared by me:

  • CameraAdded: Fires if a camera is added
  • ProgressChanged: Fires if any process reports progress
  • LiveViewUpdated: Fires if the live view image has been updated
  • CameraHasShutdown: If the camera is disconnected or shuts down, this event is fired

Now off to the fun part: The methods!

Init and Terminate the SDK

Initializing and terminating are the easiest things to do. When you start your program, create a new instance of the SDKHandler:

public SDKHandler()
{
    //initialize SDK
    Error = EDSDK.EdsInitializeSDK();
    //subscribe to camera added event (the C# event and the SDK event)
    SDKCameraAddedEvent += new EDSDK.EdsCameraAddedHandler(SDKHandler_CameraAddedEvent);
    EDSDK.EdsSetCameraAddedHandler(SDKCameraAddedEvent, IntPtr.Zero);

    //subscribe to the camera events (for the C# events)
    SDKStateEvent += new EDSDK.EdsStateEventHandler(Camera_SDKStateEvent);
    SDKPropertyEvent += new EDSDK.EdsPropertyEventHandler(Camera_SDKPropertyEvent);
    SDKProgressCallbackEvent += new EDSDK.EdsProgressCallback(Camera_SDKProgressCallbackEvent);
    SDKObjectEvent += new EDSDK.EdsObjectEventHandler(Camera_SDKObjectEvent);
}

And when you close your program, call:

public void Dispose()
{
    //close session
    CloseSession();
    //terminate SDK
    Error = EDSDK.EdsTerminateSDK();
}

Getting Connected Cameras

 To open a session, you first have to select a camera. To get a list of all connected cameras, call this:

public List<Camera> GetCameraList()
{
    IntPtr camlist;
    //get list of cameras
    Error = EDSDK.EdsGetCameraList(out camlist);

    //get each camera from camlist
    int c;
    //get amount of connected cameras
    Error = EDSDK.EdsGetChildCount(camlist, out c);
    List<Camera> OutCamList = new List<Camera>();
    for (int i = 0; i < c; i++)
    {
        IntPtr cptr;
        //get pointer to camera at index i
        Error = EDSDK.EdsGetChildAtIndex(camlist, i, out cptr);
        OutCamList.Add(new Camera(cptr));
    }
    return OutCamList;
}

Open and Close a Session with a Camera

 From the previously received camera list, select one and open a session to work with it:

public void OpenSession(Camera newCamera)
{
    if (CameraSessionOpen) CloseSession();
    if (newCamera != null)
    {
        MainCamera = newCamera;
        //open a session
        Error = EDSDK.EdsOpenSession(MainCamera.Ref);
        //subscribe to the camera events (for the SDK)
        EDSDK.EdsSetCameraStateEventHandler(MainCamera.Ref, EDSDK.StateEvent_All, SDKStateEvent, IntPtr.Zero);
        EDSDK.EdsSetObjectEventHandler(MainCamera.Ref, EDSDK.ObjectEvent_All, SDKObjectEvent, IntPtr.Zero);
        EDSDK.EdsSetPropertyEventHandler(MainCamera.Ref, EDSDK.PropertyEvent_All, SDKPropertyEvent, IntPtr.Zero);
        CameraSessionOpen = true;
    }
}

 If you are done working with this camera, close the session this way:

public void CloseSession()
{
    if (CameraSessionOpen)
    {
        //if live view is still on, stop it and wait till the thread has stopped
        if (IsLiveViewOn)
        {
            StopLiveView();
            LVThread.Join(1000);
        }

        //close session and release camera
        Error = EDSDK.EdsCloseSession(MainCamera.Ref);
        Error = EDSDK.EdsRelease(MainCamera.Ref);
        CameraSessionOpen = false;
    }
}

Get Camera Settings

Setting and getting camera settings can be very easy for values with an ID, but more difficult for struct values.

Here is the getting method for normal uint values (like Tv, Av or ISO):

public uint GetSetting(uint PropID)
{
    if (MainCamera.Ref != IntPtr.Zero)
    {
        uint property = 0;
        Error = EDSDK.EdsGetPropertyData(MainCamera.Ref, PropID, 0, out property);
        return property;
    }
    else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
}

Some properties have string values (like the owners name or the body ID):

public string GetStringSetting(uint PropID)
{
    if (MainCamera.Ref != IntPtr.Zero)
    {
        string data = String.Empty;
        EDSDK.EdsGetPropertyData(MainCamera.Ref, PropID, 0, out data);
        return data;
    }
    else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
}

Or some use structs:

public T GetStructSetting<T>(uint PropID) where T : struct
{
    if (MainCamera.Ref != IntPtr.Zero)
    {
        //get type and size of struct
        Type structureType = typeof(T);
        int bufferSize = Marshal.SizeOf(structureType);

        //allocate memory
        IntPtr ptr = Marshal.AllocHGlobal(bufferSize);
        //retrieve value
        Error = EDSDK.EdsGetPropertyData(MainCamera.Ref, PropID, 0, bufferSize, ptr);

        try
        {
            //convert pointer to managed structure
            T data = (T)Marshal.PtrToStructure(ptr, structureType);
            return data;
        }
        finally
        {
            if (ptr != IntPtr.Zero)
            {
                //free the allocated memory
                Marshal.FreeHGlobal(ptr);
                ptr = IntPtr.Zero;
            }
        }
    }
    else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
}

To get struct values, use it like this example:

EDSDK.EdsTime time = GetStructSetting<EDSDK.EdsTime>(EDSDK.PropID_DateTime);

Set Camera Settings

Same as getting settings, here are the methods to set them:

Normal uint values (the Value variable has to be the ID for the value):

public void SetSetting(uint PropID, uint Value)
{
    if (MainCamera.Ref != IntPtr.Zero)
    {
        SendSDKCommand(delegate
        {
            int propsize;
            EDSDK.EdsDataType proptype;
            //get size of property
            Error = EDSDK.EdsGetPropertySize(MainCamera.Ref, PropID, 0, out proptype, out propsize);
            //set given property
            Error = EDSDK.EdsSetPropertyData(MainCamera.Ref, PropID, 0, propsize, Value);
        });
    }
    else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
}

Setting a string value:

public void SetStringSetting(uint PropID, string Value)
{
    if (MainCamera.Ref != IntPtr.Zero)
    {
        if (Value == null) throw new ArgumentNullException("String must not be null");

        //convert string to byte array
        byte[] propertyValueBytes = System.Text.Encoding.ASCII.GetBytes(Value + '\0');
        int propertySize = propertyValueBytes.Length;

        //check size of string
        if (propertySize > 32) throw new ArgumentOutOfRangeException("Value must be smaller than 32 bytes");

        //set value
        SendSDKCommand(delegate { Error = EDSDK.EdsSetPropertyData(MainCamera.Ref, PropID, 0, 32, propertyValueBytes); });
    }
    else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
}

and setting a struct value (like EdsTime):

public void SetStructSetting<T>(uint PropID, T Value) where T : struct
{
    if (MainCamera.Ref != IntPtr.Zero)
    {
        SendSDKCommand(delegate { Error = EDSDK.EdsSetPropertyData(MainCamera.Ref, PropID, 0, Marshal.SizeOf(typeof(T)), Value); });
    }
    else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
}

Get a List of Available Settings

Certain cameras don't support certain settings and lenses only have a certain range of Av values. That's why you need to get a list of all supported settings. This only works with "AEModeSelect", "ISO", "Av", "Tv", "MeteringMode" and "ExposureCompensation". The list that you get as a return value is actually a list of IDs for the given PropertyID. You can find the matching values from Av, Tv and ISO in the CameraValues class, look into the SDK documentation PDF for the other values.

public List<int> GetSettingsList(uint PropID)
{
    if (MainCamera.Ref != IntPtr.Zero)
    {
        //a list of settings can only be retrieved for following properties
        if (PropID == EDSDK.PropID_AEModeSelect || PropID == EDSDK.PropID_ISOSpeed || PropID == EDSDK.PropID_Av
            || PropID == EDSDK.PropID_Tv || PropID == EDSDK.PropID_MeteringMode || PropID == EDSDK.PropID_ExposureCompensation)
        {
            //get the list of possible values
            EDSDK.EdsPropertyDesc des = new EDSDK.EdsPropertyDesc();
            Error = EDSDK.EdsGetPropertyDesc(MainCamera.Ref, PropID, out des);
            return des.PropDesc.Take(des.NumElements).ToList();
        }
        else throw new ArgumentException("Method cannot be used with this Property ID");
    }
    else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
}

Taking a Photo (Normal and Bulb)

An important note to the TakePhoto command: If your camera supports the PressShutterButton command I strongly advise to use that. If the camera is not able to focus it could hang the whole program.

To take a photo with the current settings, call the TakePhoto method:

public void TakePhoto()
{
    //send command to camera
    SendSDKCommand(delegate { Error = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_TakePicture, 0); });
}

To take a photo in bulb mode, call the TakePhoto method with the BulbTime parameter:

public void TakePhoto(uint BulbTime)
{
    //bulbtime has to be at least a second
    if (BulbTime < 1000) { throw new ArgumentException("Bulbtime has to be bigger than 1000ms"); }

    //start thread to not block everything
    new Thread(delegate()
    {
        SendSDKCommand(delegate
        {
            //open the shutter
            Error = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_BulbStart, 0);
            //wait for the specified time
            Thread.Sleep((int)BulbTime);
            //close shutter
            Error = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_BulbEnd, 0);
        });
    }).Start();
}

If you selected the output device to be your PC, look for the next topic to download the image from the camera.

Download a Taken Photo to the Computer

If you want to save taken photos directly onto the computer instead of the camera-memory, set it with calling the SetSetting method:

SetSetting(EDSDK.PropID_SaveTo, (uint)EDSDK.EdsSaveTo.Host); //EdsSaveTo.Both would save the image to the camera AND the computer

Once you have taken a photo, the SDKObjectEvent will fire with the inEvent variable being EDSDK.ObjectEvent_DirItemRequestTransfer:

private uint Camera_SDKObjectEvent(uint inEvent, IntPtr inRef, IntPtr inContext)
{
    if (inEvent == EDSDK.ObjectEvent_DirItemRequestTransfer) DownloadImage(inRef, ImageSaveDirectory);
    return EDSDK.EDS_ERR_OK;
}

And the DownloadImage method being (the DownloadData method will be explained at the end):

public void DownloadImage(IntPtr ObjectPointer, string directory)
{
    SendSDKCommand(delegate
    {
        EDSDK.EdsDirectoryItemInfo dirInfo;
        IntPtr streamRef;
        //get information about object
        Error = EDSDK.EdsGetDirectoryItemInfo(ObjectPointer, out dirInfo);
        string CurrentPhoto = Path.Combine(directory, dirInfo.szFileName);
        //create filestream to data
        Error = EDSDK.EdsCreateFileStream(CurrentPhoto, EDSDK.EdsFileCreateDisposition.CreateAlways, EDSDK.EdsAccess.ReadWrite, out streamRef);
        //download file
        DownloadData(ObjectPointer, streamRef);
        //release stream
        Error = EDSDK.EdsRelease(streamRef);
    });
}

If you don't want to save the image to the harddrive but want to get a Bitmap instead, use the second DownloadImage method:

Note: This method should not be used while the live view is running. The program is likely to hang.

public Bitmap DownloadImage(IntPtr ObjectPointer)
{
    //get information about image
    EDSDK.EdsDirectoryItemInfo dirInfo = new EDSDK.EdsDirectoryItemInfo();
    Error = EDSDK.EdsGetDirectoryItemInfo(ObjectPointer, out dirInfo);

    //check the extension. Raw data cannot be read by the bitmap class
    string ext = Path.GetExtension(dirInfo.szFileName).ToLower();
    if (ext == ".jpg" || ext == ".jpeg")
    {
        IntPtr streamRef, jpgPointer;
        uint length;
        Bitmap bmp = null;
        //create memory stream
        Error = EDSDK.EdsCreateMemoryStream(dirInfo.Size, out streamRef);
        //download data to the stream
        DownloadData(ObjectPointer, streamRef);
        Error = EDSDK.EdsGetPointer(streamRef, out jpgPointer);
        Error = EDSDK.EdsGetLength(streamRef, out length);

        unsafe
        {
            //create a System.IO.Stream from the pointer
            using (UnmanagedMemoryStream ums = new UnmanagedMemoryStream((byte*)jpgPointer.ToPointer(), length, length, FileAccess.Read))
            {
                //create bitmap from stream (it's a normal jpeg image)
                bmp = new Bitmap(ums);
            }
        }

        //release data
        Error = EDSDK.EdsRelease(streamRef);
        Error = EDSDK.EdsRelease(jpgPointer);

        return bmp;
    }
    else
    {
        //if it's a RAW image, cancel the download and release the image
        Error = EDSDK.EdsDownloadCancel(ObjectPointer);
        Error = EDSDK.EdsRelease(ObjectPointer);
        return null;
    }
}

Press Shutterbutton

You can remotely press the shutterbutton in various ways. Half to activate the autofocus or to check exposure values. Or full to take a photo (with or without AF). Note that this feature does not work for older cameras.

public void PressShutterButton(EDSDK.EdsShutterButton state)
{
    //send command to camera
    SendSDKCommand(delegate { Error = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_PressShutterButton, (uint)state); });
}

Start and View the Live View

The live view is one of the more difficult things to do, especially if it should be high-performance. First we start the live view like this:

public void StartLiveView()
{
    if (!IsLiveViewOn)
    {
        SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_PC);
        IsLiveViewOn = true;
    }
}

Once this is done, the SDKPropertyEvent will fire with the inPropertyID variable being EDSDK.PropID_Evf_OutputDevice:

private uint Camera_SDKPropertyEvent(uint inEvent, 
uint inPropertyID, uint inParameter, IntPtr inContext)
{
    if (inPropertyID == EDSDK.PropID_Evf_OutputDevice)
    {
        if (IsLiveViewOn == true) DownloadEvf();
    }
    return EDSDK.EDS_ERR_OK;
}

And the DownloadEvf method being:

private void DownloadEvf()
{
    LVThread = new Thread(delegate()
    {
        IntPtr jpgPointer;
        IntPtr stream = IntPtr.Zero;
        IntPtr EvfImageRef = IntPtr.Zero;
        UnmanagedMemoryStream ums;

        uint err;
        uint length;
        //create stream
        Error = EDSDK.EdsCreateMemoryStream(0, out stream);

        //run live view
        while (IsLiveViewOn)
        {
            //Execute waiting commands
            while (LvQueue.Count > 0) LvQueue.Dequeue()();

            //download current live view image
            err = EDSDK.EdsCreateEvfImageRef(stream, out EvfImageRef);
            if (err == EDSDK.EDS_ERR_OK) err = EDSDK.EdsDownloadEvfImage(MainCamera.Ref, EvfImageRef);
            if (err == EDSDK.EDS_ERR_OBJECT_NOTREADY) continue;
            else Error = err;

            //get pointer
            Error = EDSDK.EdsGetPointer(stream, out jpgPointer);
            Error = EDSDK.EdsGetLength(stream, out length);

            //get some live view image metadata
            if (!IsCoordSystemSet) { Evf_CoordinateSystem = GetEvfCoord(EvfImageRef); IsCoordSystemSet = true; }
            Evf_ZoomRect = GetEvfZoomRect(EvfImageRef);
            Evf_ZoomPosition = GetEvfPoints(EDSDK.PropID_Evf_ZoomPosition, EvfImageRef);
            Evf_ImagePosition = GetEvfPoints(EDSDK.PropID_Evf_ImagePosition, EvfImageRef);

            //release current evf image
            if (EvfImageRef != IntPtr.Zero) { Error = EDSDK.EdsRelease(EvfImageRef); }

            //create stream to image
            unsafe { ums = new UnmanagedMemoryStream((byte*)jpgPointer.ToPointer(), length, length, FileAccess.Read); }

            //fire the LiveViewUpdated event with the live view image stream
            if (LiveViewUpdated != null) LiveViewUpdated(ums);
            ums.Close();
        }

        //release and finish
        if (stream != IntPtr.Zero) { Error = EDSDK.EdsRelease(stream); }
        //stop the live view
        SetSetting(EDSDK.PropID_Evf_OutputDevice, 0);
    });
    LVThread.Start();
}

To stop the live view simply call the StopLiveView method, which essentially just allows the DownloadEvf method to jump out of the while loop:

public void StopLiveView()
{
    IsLiveViewOn = false;
}

Recording Videos

Newer cameras have the possibility to record videos built in. To use this, you have to set your camera to video recording mode first (it will not work otherwise!). Usually there is some button, knob or dial you have to switch. If that is done, you can call the starting method where you either download the finished video:

public void StartFilming(string FilePath)
{
    if (!IsFilming)
    {
        StartFilming();
        this.DownloadVideo = true;
        ImageSaveDirectory = FilePath;
    }
}

 Or let the finished video on the memory card of the camera:

public void StartFilming()
{
    if (!IsFilming)
    {
        //Check if the camera is ready to film
        if (GetSetting(EDSDK.PropID_Record) != 3) throw new InvalidOperationException("Camera is not in film mode");

        IsFilming = true;

        //to restore the current setting after recording
        PrevSaveTo = GetSetting(EDSDK.PropID_SaveTo);
        //when recording videos, it has to be saved on the camera internal memory
        SetSetting(EDSDK.PropID_SaveTo, (uint)EDSDK.EdsSaveTo.Camera);
        this.DownloadVideo = false;
        //start the video recording
        SendSDKCommand(delegate { Error = EDSDK.EdsSetPropertyData(MainCamera.Ref, EDSDK.PropID_Record, 0, 4, 4); });
    }
}

 And if you are finished call the StopFilming method:

if (IsFilming)
{
    SendSDKCommand(delegate
    {
        //Shut off live view (it will hang otherwise)
        StopLiveView(false);
        //stop video recording
        Error = EDSDK.EdsSetPropertyData(MainCamera.Ref, EDSDK.PropID_Record, 0, 4, 0);
    });
    IsFilming = false;
}

If the finished video should be downloaded after the recording has stopped, we need to catch the SDKObjectEvent:

private uint Camera_SDKObjectEvent(uint inEvent, IntPtr inRef, IntPtr inContext)
{
    if(inEvent == EDSDK.ObjectEvent_DirItemCreated && DownloadVideo) { DownloadImage(inRef, ImageSaveDirectory); DownloadVideo = false; }
    return EDSDK.EDS_ERR_OK;
}

Lock/Unlock the camera UI

To keep the user or from changing settings on the physical camera, or allowing to do so, you can lock or unlock the camera UI like this:

public void UILock(bool LockState)
{
    SendSDKCommand(delegate
    {
        if (LockState == true) Error = EDSDK.EdsSendStatusCommand(MainCamera.Ref, EDSDK.CameraState_UILock, 0);
        else Error = EDSDK.EdsSendStatusCommand(MainCamera.Ref, EDSDK.CameraState_UIUnLock, 0);
    });
}

Get the Thumbnail of an Image

Sometimes it is useful to get a thumbnail from an image, regardless if RAW or jpg:

public Bitmap GetFileThumb(string filepath)
{
    IntPtr stream;
    //create a filestream to given file
    Error = EDSDK.EdsCreateFileStream(filepath, EDSDK.EdsFileCreateDisposition.OpenExisting, EDSDK.EdsAccess.Read, out stream);
    return GetImage(stream, EDSDK.EdsImageSource.Thumbnail);
}

Control the Focus of a Lens

A question often asked all over the internet is how to control the focus of the camera. It's actually quite easy if you know how. Most important, the camera has to be in live view and the lens has to be on AF. Then call this piece of code:

public void SetFocus(uint Speed)
{
    if (IsLiveViewOn) SendSDKCommand(delegate { Error = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_DriveLensEvf, Speed); });
}

The variable Speed is simply one of the EDSDK.EvfDriveLens_ values. There are three step sizes in each direction (Far1,2,3 and Near1,2,3)

Get Files and Folders on a Camera

This is a bit a tricky method as it is recursive (or actually the subroutine GetChildren is). Basically it goes through every volume and every folder there is on the camera and extracts names and thumbnails:

Note: This method should not be used while the live view is running. The program is likely to hang.

public CameraFileEntry GetAllEntries()
{
    //create the main entry which contains all subentries
    CameraFileEntry MainEntry = new CameraFileEntry("Camera", true);

    //get the number of volumes currently installed in the camera
    int VolumeCount;
    Error = EDSDK.EdsGetChildCount(MainCamera.Ref, out VolumeCount);
    List<CameraFileEntry> VolumeEntries = new List<CameraFileEntry>();

    //iterate through all of them
    for (int i = 0; i < VolumeCount; i++)
    {
        //get information about volume
        IntPtr ChildPtr;
        Error = EDSDK.EdsGetChildAtIndex(MainCamera.Ref, i, out ChildPtr);
        EDSDK.EdsVolumeInfo vinfo;
        Error = EDSDK.EdsGetVolumeInfo(ChildPtr, out vinfo);

        //ignore the HDD
        if (vinfo.szVolumeLabel != "HDD")
        {
            //add volume to the list
            VolumeEntries.Add(new CameraFileEntry("Volume" + i + "(" + vinfo.szVolumeLabel + ")", true));
            //get all child entries on this volume
            VolumeEntries[i].AddSubEntries(GetChildren(ChildPtr));
        }
        //release the volume
        Error = EDSDK.EdsRelease(ChildPtr);
    }
    //add all volumes to the main entry and return it
    MainEntry.AddSubEntries(VolumeEntries.ToArray());
    return MainEntry;
}

Subroutines Used in Previous Methods

There are a few subroutines to make the above code shorter and more readable.

This sends a command to the camera safely when the live view is running:

private void SendSDKCommand(Action command)
{
    if (IsLiveViewOn) LvQueue.Enqueue(command);
    else command();
}

This is a general method that downloads data from the camera into a stream:

private void DownloadData(IntPtr ObjectPointer, IntPtr stream)
{
    //get information about the object
    EDSDK.EdsDirectoryItemInfo dirInfo;
    Error = EDSDK.EdsGetDirectoryItemInfo(ObjectPointer, out dirInfo);

    try
    {
        //set progress event
        Error = EDSDK.EdsSetProgressCallback(stream, SDKProgressCallbackEvent, EDSDK.EdsProgressOption.Periodically, ObjectPointer);
        //download the data
        Error = EDSDK.EdsDownload(ObjectPointer, dirInfo.Size, stream);
    }
    finally
    {
        //set the download as complete
        Error = EDSDK.EdsDownloadComplete(ObjectPointer);
        //release object
        Error = EDSDK.EdsRelease(ObjectPointer);
    }
}

This method gets a Bitmap from a stream:

private Bitmap GetImage(IntPtr img_stream, EDSDK.EdsImageSource imageSource)
{
    IntPtr stream = IntPtr.Zero;
    IntPtr img_ref = IntPtr.Zero;
    IntPtr streamPointer = IntPtr.Zero;
    EDSDK.EdsImageInfo imageInfo;

    try
    {
        //create reference and get image info
        Error = EDSDK.EdsCreateImageRef(img_stream, out img_ref);
        Error = EDSDK.EdsGetImageInfo(img_ref, imageSource, out imageInfo);

        EDSDK.EdsSize outputSize = new EDSDK.EdsSize();
        outputSize.width = imageInfo.EffectiveRect.width;
        outputSize.height = imageInfo.EffectiveRect.height;
        //calculate amount of data
        int datalength = outputSize.height * outputSize.width * 3;
        //create buffer that stores the image
        byte[] buffer = new byte[datalength];
        //create a stream to the buffer
        Error = EDSDK.EdsCreateMemoryStreamFromPointer(buffer, (uint)datalength, out stream);
        //load image into the buffer
        Error = EDSDK.EdsGetImage(img_ref, imageSource, EDSDK.EdsTargetImageType.RGB, imageInfo.EffectiveRect, outputSize, stream);

        //make BGR from RGB (System.Drawing (i.e. GDI+) uses BGR)
        unsafe
        {
            byte tmp;
            fixed (byte* pix = buffer)
            {
                for (long i = 0; i < datalength; i += 3)
                {
                    tmp = pix[i];        //Save B value
                    pix[i] = pix[i + 2]; //Set B value with R value
                    pix[i + 2] = tmp;    //Set R value with B value
                }
            }
        }

        //Get pointer to stream
        Error = EDSDK.EdsGetPointer(stream, out streamPointer);
        //Create bitmap with the data in the buffer
        return new Bitmap(outputSize.width, outputSize.height, datalength, PixelFormat.Format24bppRgb, streamPointer);
    }
    finally
    {
        //Release all data
        if (img_stream != IntPtr.Zero) Error = EDSDK.EdsRelease(img_stream);
        if (img_ref != IntPtr.Zero) Error = EDSDK.EdsRelease(img_ref);
        if (stream != IntPtr.Zero) Error = EDSDK.EdsRelease(stream);
    }
}

This is a recursive method that goes through all folders and subfolders on the camera:

private CameraFileEntry[] GetChildren(IntPtr ptr)
{
    int ChildCount;
    //get children of first pointer
    Error = EDSDK.EdsGetChildCount(ptr, out ChildCount);
    if (ChildCount > 0)
    {
        //if it has children, create an array of entries
        CameraFileEntry[] MainEntry = new CameraFileEntry[ChildCount];
        for (int i = 0; i < ChildCount; i++)
        {
            IntPtr ChildPtr;
            //get children of children
            Error = EDSDK.EdsGetChildAtIndex(ptr, i, out ChildPtr);
            //get the information about this children
            EDSDK.EdsDirectoryItemInfo ChildInfo;
            Error = EDSDK.EdsGetDirectoryItemInfo(ChildPtr, out ChildInfo);

            //create entry from information
            MainEntry[i] = new CameraFileEntry(ChildInfo.szFileName, GetBool(ChildInfo.isFolder));
            if (!MainEntry[i].IsFolder)
            {
                //if it's not a folder, create thumbnail and safe it to the entry
                IntPtr stream;
                Error = EDSDK.EdsCreateMemoryStream(0, out stream);
                Error = EDSDK.EdsDownloadThumbnail(ChildPtr, stream);
                MainEntry[i].AddThumb(GetImage(stream, EDSDK.EdsImageSource.Thumbnail));
            }
            else
            {
                //if it's a folder, check for children with recursion
                CameraFileEntry[] retval = GetChildren(ChildPtr);
                if (retval != null) MainEntry[i].AddSubEntries(retval);
            }
            //release current children
            Error = EDSDK.EdsRelease(ChildPtr);
        }
        return MainEntry;
    }
    else return null;
}

A Note to the Methods

I did not add every single method that is used in the code here. Just download the source if something is not completely clear. And if you still have a question after that, simply ask me Smile | :)

Using the GUI

This project includes a Winforms UI and a WPF UI. They both work the same way and are here to show you how to use the above code in a real, usable software.

Note: These GUIs are not meant for production use and are merely here as an example to get you started!

Plug in your camera and select in the list. Click on "Open Session" and start to use the camera.

Select the values in the dropdown menus to set them in the camera.

Use the "StartLV" Button to start the live view and the buttons with the arrows on it can be used to control the focus (only works if the lens is in AF mode and live view is running)

  

Points of Interest

This code was tested with:

  • EOS 40D
  • EOS 1100D/Rebel T3
  • EOS 100D/Rebel SL1
  • EOS 5D Mark III
  • EOS 7D

If you tried it with a different model, please let me know so I can add it to this list.

And if you have found a bug, have an improvement or a new snippet, I'm happy to hear from you!

Note to Multithreading

If you ever run into multithreading issues you should check for deadlocks. Any command that communicates with the camera (e.g. set settings, download data. etc.) is executed by the SDK on the main thread.

This means if put the SDK command on a different thread and wait for it on the main thread to finish you have a deadlock and everything hangs. This is the reason for the execution of commands while the the live view is running to be so complicated.

History

  • November 2013 - Initial version
  • November 2013 - Bugfix for viewing LiveView and taking photos at the same time
  • December 2013 - Added GetStringProperty and GetStructProperty and added video recording
  • January 2014 - Added SetStringProperty and SetStructProperty and minor changes in the UI
  • January 2014 - Added several new methods and made the code much more secure
  • June 2014 - Changed a few methods to be more secure and revised the code and UI a bit
  • October 2014 - Fixed a few bugs, revised the Winforms UI and added a WPF UI
  • November 2014 - Fixed deadlock issue when the live view is running and camera commands are called
  • April 2015 - Fixed a bug where the camera would hang before or after filming. Fixed a broken link

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

Share

About the Author

Johannes Bildstein
Software Developer
Austria Austria
No Biography provided

Comments and Discussions

 
BugProblem when maximizing the window and few other things Pin
Member 1152534625-May-15 6:25
memberMember 1152534625-May-15 6:25 
QuestionAnyone have a Rebel T5 working? Pin
Member 1036240117-May-15 16:12
memberMember 1036240117-May-15 16:12 
AnswerRe: Anyone have a Rebel T5 working? Pin
Johannes Bildstein17-May-15 23:20
professionalJohannes Bildstein17-May-15 23:20 
GeneralRe: Anyone have a Rebel T5 working? [modified] Pin
Member 1036240118-May-15 1:16
memberMember 1036240118-May-15 1:16 
GeneralRe: Anyone have a Rebel T5 working? Pin
Johannes Bildstein18-May-15 3:34
professionalJohannes Bildstein18-May-15 3:34 
GeneralRe: Anyone have a Rebel T5 working? Pin
Member 1036240118-May-15 11:40
memberMember 1036240118-May-15 11:40 
GeneralRe: Anyone have a Rebel T5 working? Pin
Johannes Bildstein18-May-15 14:18
professionalJohannes Bildstein18-May-15 14:18 
BugHang when closeSession with LV running Pin
zulurineyyyy16-May-15 10:44
memberzulurineyyyy16-May-15 10:44 
GeneralRe: Hang when closeSession with LV running Pin
Member 1105092916-May-15 14:35
memberMember 1105092916-May-15 14:35 
AnswerRe: Hang when closeSession with LV running Pin
Johannes Bildstein16-May-15 14:41
professionalJohannes Bildstein16-May-15 14:41 
AnswerRe: Hang when closeSession with LV running Pin
Johannes Bildstein16-May-15 14:40
professionalJohannes Bildstein16-May-15 14:40 
GeneralRe: Hang when closeSession with LV running Pin
Member 1105092917-May-15 23:56
memberMember 1105092917-May-15 23:56 
QuestionHow do I set the image name when saving? Pin
Classicsmiley15-May-15 7:52
memberClassicsmiley15-May-15 7:52 
AnswerRe: How do I set the image name when saving? Pin
Johannes Bildstein16-May-15 14:45
professionalJohannes Bildstein16-May-15 14:45 
GeneralRe: How do I set the image name when saving? Pin
Classicsmiley16-May-15 14:50
memberClassicsmiley16-May-15 14:50 
GeneralRe: How do I set the image name when saving? Pin
Johannes Bildstein17-May-15 1:40
professionalJohannes Bildstein17-May-15 1:40 
QuestionSave Live View Image Pin
Member 1142515612-May-15 6:39
memberMember 1142515612-May-15 6:39 
AnswerRe: Save Live View Image Pin
Johannes Bildstein16-May-15 14:51
professionalJohannes Bildstein16-May-15 14:51 
GeneralRe: Save Live View Image Pin
Member 1142515616-May-15 16:47
memberMember 1142515616-May-15 16:47 
GeneralRe: Save Live View Image Pin
Johannes Bildstein17-May-15 3:40
professionalJohannes Bildstein17-May-15 3:40 
GeneralRe: Save Live View Image Pin
Member 1142515617-May-15 5:01
memberMember 1142515617-May-15 5:01 
QuestionDownload from SD card Pin
Member 25427689-May-15 15:42
memberMember 25427689-May-15 15:42 
AnswerRe: Download from SD card Pin
Johannes Bildstein17-May-15 3:37
professionalJohannes Bildstein17-May-15 3:37 
AnswerRe: Download from SD card Pin
Johannes Bildstein17-May-15 4:12
professionalJohannes Bildstein17-May-15 4:12 
QuestionPhotoShoot while Live Viewing Pin
B.V.Papadopoulos27-Apr-15 5:55
professionalB.V.Papadopoulos27-Apr-15 5:55 
AnswerRe: PhotoShoot while Live Viewing Pin
Johannes Bildstein27-Apr-15 10:36
professionalJohannes Bildstein27-Apr-15 10:36 
GeneralRe: PhotoShoot while Live Viewing Pin
B.V.Papadopoulos27-Apr-15 10:49
professionalB.V.Papadopoulos27-Apr-15 10:49 
QuestionHelp Error 10 Pin
eden_zhou20-Apr-15 23:01
membereden_zhou20-Apr-15 23:01 
AnswerRe: Help Error 10 Pin
Johannes Bildstein23-Apr-15 12:27
professionalJohannes Bildstein23-Apr-15 12:27 
QuestionDllNotFoundException was unhandled Pin
Member 1161420616-Apr-15 18:28
memberMember 1161420616-Apr-15 18:28 
AnswerRe: DllNotFoundException was unhandled Pin
Johannes Bildstein23-Apr-15 12:20
professionalJohannes Bildstein23-Apr-15 12:20 
QuestionRotator image in liveview mode. Pin
tuhm13-Apr-15 15:03
membertuhm13-Apr-15 15:03 
AnswerRe: Rotator image in liveview mode. Pin
Johannes Bildstein16-Apr-15 5:52
professionalJohannes Bildstein16-Apr-15 5:52 
GeneralRe: Rotator image in liveview mode. [modified] Pin
tuhm17-Apr-15 4:32
membertuhm17-Apr-15 4:32 
GeneralRe: Rotator image in liveview mode. Pin
Johannes Bildstein23-Apr-15 12:18
professionalJohannes Bildstein23-Apr-15 12:18 
QuestionEDS_ERR_STREAM_OPEN_ERROR when manual click image from camera button. Pin
arunsinghdeveloper10-Apr-15 4:05
memberarunsinghdeveloper10-Apr-15 4:05 
AnswerRe: EDS_ERR_STREAM_OPEN_ERROR when manual click image from camera button. Pin
Johannes Bildstein16-Apr-15 5:39
professionalJohannes Bildstein16-Apr-15 5:39 
QuestionI am facing some issue. Pin
Ravinder Singh Choudhary7-Apr-15 3:54
memberRavinder Singh Choudhary7-Apr-15 3:54 
AnswerRe: I am facing some issue. Pin
Johannes Bildstein8-Apr-15 7:59
professionalJohannes Bildstein8-Apr-15 7:59 
GeneralRe: I am facing some issue. Pin
Ravinder Singh Choudhary8-Apr-15 23:03
memberRavinder Singh Choudhary8-Apr-15 23:03 
GeneralRe: I am facing some issue. Pin
arunsinghdeveloper10-Apr-15 4:11
memberarunsinghdeveloper10-Apr-15 4:11 
QuestionSerial Pin
Rafał Szu7-Apr-15 2:03
memberRafał Szu7-Apr-15 2:03 
AnswerRe: Serial Pin
Johannes Bildstein8-Apr-15 7:56
professionalJohannes Bildstein8-Apr-15 7:56 
GeneralRe: Serial Pin
Rafał Szu8-Apr-15 13:33
memberRafał Szu8-Apr-15 13:33 
GeneralRe: Serial Pin
Johannes Bildstein14-Apr-15 1:00
professionalJohannes Bildstein14-Apr-15 1:00 
QuestionLive View Shooting download capabilities Pin
Member 967401827-Mar-15 6:29
memberMember 967401827-Mar-15 6:29 
AnswerRe: Live View Shooting download capabilities Pin
Johannes Bildstein8-Apr-15 7:54
professionalJohannes Bildstein8-Apr-15 7:54 
QuestionSDK Error 2 after re-open Pin
Member 1153964224-Mar-15 9:40
memberMember 1153964224-Mar-15 9:40 
AnswerRe: SDK Error 2 after re-open Pin
Johannes Bildstein24-Mar-15 11:55
professionalJohannes Bildstein24-Mar-15 11:55 
GeneralRe: SDK Error 2 after re-open Pin
Rudy210524-Mar-15 17:24
memberRudy210524-Mar-15 17:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150520.1 | Last Updated 24 Apr 2015
Article Copyright 2013 by Johannes Bildstein
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid