现在的位置: 首页 > 综合 > 正文

佳能 EDSDK 教程 C# 版本

2014年09月29日 ⁄ 综合 ⁄ 共 17860字 ⁄ 字号 评论关闭

介绍

佳能EOS数码SDK是一个 可以用来远程控制其数码单反相机相当强大的SDK。不幸的是,想在互联网上找些很好的例子相当难,而且提供的文档也不是很齐全。因为我已经找到了很多能让其他人更容易掌握它的东西,我就想可以把我认为最重要的东西组织在一起,做成一个教程。 

本教程包括: 

  • 初始化和终止的SDK
  • 打开和关闭摄像头会话
  • 获取连接的像机列表
  • set和get相机设置
  • 获取可用的设置列表
  • 正常拍照和使用闪光灯模式
  • 处理相机事件
  • 将拍摄的照片下载到电脑上
  • 启动和实时查看
  • 记录实时查看
  • 锁定/解锁相机的用户界面

另外:其实我不从属于佳能公司,也不受其自助。 

还有:我不对这个软件做任何方式担保。使用时请您自己注意风险! (你可以在GPL许可证中找到有关此主题的更多信息。) 

背景

你必须有佳能EDSDK副本才能让这个运行起来。 (我认为)我不会被允许包含那些官方的DLL的到项目中,所以你必须自己通过申请去获取,它们在这里:

一旦你得到了那些DLL,就把它们放到项目中的 EDSDK文件夹里面,并确保再调试/发行目录中也要有相同的文件夹。 (或你认为的任何地方,同时据此调整 EDSDK.cs文件中的DLLPath变量(在右上部)。 

使用代码

我使用了三个简单的类,SDKHandler,Camera和CameraValues,还有来自 佳能SDK的EDSDK。 

在SDKHandler中有几个变量:

/// <summary>
/// The used camera
/// </summary>
public Camera MainCamera { get; private set; }

/// <summary>
/// States if a session with the MainCamera is opened
/// </summary>
public bool CameraSessionOpen { get; private set; }

/// <summary>
/// States if the LiveView is on or not
/// </summary>
public bool IsLiveViewOn { get; private set; }

/// <summary>
/// States if LiveView is recorded or not
/// </summary>
public bool IsEvfFilming { get; private set; }

/// <summary>
/// Directory to where photos will be saved
/// </summary>
public string ImageSaveDirectory { get; set; }

/// <summary>
/// Handles errors that happen with the SDK
/// </summary>
public uint Error
{
    get { return EDSDK.EDS_ERR_OK; }
    set { if (value != EDSDK.EDS_ERR_OK) throw new Exception("SDK Error: " + value); }
}

/// <summary>
/// Frame buffer for LiveView recording
/// </summary>
private Queue<byte[]> FrameBuffer = new Queue<byte[]>(1000);

还有一些来自SDK的以及我自己添加的一些事件:

#region SDK Events

public event EDSDK.EdsCameraAddedHandler SDKCameraAddedEvent;
public event EDSDK.EdsObjectEventHandler SDKObjectEvent;
public event EDSDK.EdsProgressCallback SDKProgressCallbackEvent;
public event EDSDK.EdsPropertyEventHandler SDKPropertyEvent;
public event EDSDK.EdsStateEventHandler SDKStateEvent;

#endregion

#region Custom Events

public delegate void CameraAddedHandler();
public delegate void ProgressHandler(int Progress);
public delegate void ImageUpdate(Image img);
public delegate void FloatUpdate(float Value);

/// <summary>
/// Fires if a camera is added
/// </summary>
public event CameraAddedHandler CameraAdded;

/// <summary>
/// Fires if any process reports progress
/// </summary>
public event ProgressHandler ProgressChanged;

/// <summary>
/// Fires if the LiveView image is updated
/// </summary>
public event ImageUpdate LiveViewUpdated;

/// <summary>
/// Fires if a new framerate is calculated
/// </summary>
public event FloatUpdate FrameRateUpdated;

#endregion  

这个类的方法将在稍后讨论。


Camera类相当简单,工作起来就像一个相机指针和有关相机的一些信息的容器:

public class Camera
{
    internal IntPtr Ref;
    public EDSDK.EdsDeviceInfo Info { get; private set; }
    public uint Error
    {
        get { return EDSDK.EDS_ERR_OK; }
        set { if (value != EDSDK.EDS_ERR_OK) throw new Exception("SDK Error: " + value); }
    }

    public Camera(IntPtr Reference)
    {
        this.Ref = Reference;        
        EDSDK.EdsDeviceInfo dinfo;
        Error = EDSDK.EdsGetDeviceInfo(Reference, out dinfo);
        this.Info = dinfo;
    }
} 
CameraValues是一个拥有所有单元ID值以及存储从Av、Tv到ISO字符串值的静态类。

初始化和终止SDK

初始化和终止是最容易做的事情。当您一启动程序,就创建了一个SDKHandler的新实例。

/// <summary>
/// Initialises the SDK and adds events
/// </summary>
public SDKHandler()
{
    //this is the important part of initialisation
    Error = EDSDK.EdsInitializeSDK(); 

    //here we subscribe to the CameraAddedEvent and tell the SDK we did so
    CameraAddedEvent += new EDSDK.EdsCameraAddedHandler(SDKHandler_CameraAddedEvent);
    EDSDK.EdsSetCameraAddedHandler(CameraAddedEvent, IntPtr.Zero);
    
    //here we subscribe to the rest of the camera 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);
}

而当你关闭程序时,就会调用:

/// <summary>
/// Closes open session and terminates the SDK
/// </summary>
public void Dispose()
{
    if (CameraSessionOpen) Error = EDSDK.EdsCloseSession(MainCamera.Ref);
    Error = EDSDK.EdsTerminateSDK();
}

获取连接的像机列表

要打开一个会话,你必须选择一个相机。如果要获得所有连接的像机的列表,那就调用这个:

/// <summary>
/// Get a list of all connected cameras
/// </summary>
/// <returns>The camera list</returns>
public List<Camera> GetCameraList()
{
    IntPtr camlist;
    //Get cameralist
    Error = EDSDK.EdsGetCameraList(out camlist);
    //Get each camera from camlist
    int c;
    Error = EDSDK.EdsGetChildCount(camlist, out c);
    List<Camera> OutCamList = new List<Camera>();
    for (int i = 0; i < c; i++)
    {
        IntPtr cptr;
        Error = EDSDK.EdsGetChildAtIndex(camlist, i, out cptr);
        OutCamList.Add(new Camera(cptr));
    {
    return OutCamList;
}

打开和关闭相机会话

从以前收到的像机列表中选择一个,打开一个使用它的会话:

/// <summary>
/// Opens a session with given camera
/// </summary>
/// <param name="NewCamera">The camera which will be used</param>
public void OpenSession(Camera NewCamera)
{
    //make sure the previous camera session is closed
    if (CameraSessionOpen) Error = EDSDK.EdsCloseSession(MainCamera.Ref);
    if (NewCamera != null)
    {
        MainCamera = NewCamera;
        //open a session
        Error = EDSDK.EdsOpenSession(MainCamera.Ref);
        //subscribe to the camera events (this time, in-Camera)
        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;
    }
}

如果你完成了对相机的使用,就使用这个方法关闭会话:

/// <summary>
/// Closes the session with the current camera
/// </summary>
public void CloseSession()
{
    if (CameraSessionOpen)
    {
        Error = EDSDK.EdsCloseSession(MainCamera.Ref);
        CameraSessionOpen = false;
    }
}

Set 和 Get 相机设置

通过ID去设置和获取相机的设置是非常简单的,但是一些有难度的结构值(这里还没有介绍).下面这个例子你可以在这个方法中获取到Tv,Av和ISO的设置。

/// <summary>
/// Gets the current setting of given property ID
/// </summary>
/// <param name="PropID">The property ID</param>
/// <returns>The current setting of the camera</returns>
public uint GetSetting(uint PropID)
{
    if (MainCamera.Ref != IntPtr.Zero)
    {
        unsafe
        {
            uint property = 0;
            EDSDK.EdsDataType dataType;
            int dataSize;
            IntPtr ptr = new IntPtr(&property);
            //get the size of this property
            Error = EDSDK.EdsGetPropertySize(MainCamera.Ref, PropID, 0, out dataType, out dataSize);
            //get the data for this property
            Error = EDSDK.EdsGetPropertyData(MainCamera.Ref, PropID, 0, dataSize, ptr);
            return property;
        }
    }
    else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
}

Setting方法(这里的参数一般是ID,从Camera类中获取这个string值):

/// <summary>
/// Sets a value for the given property ID
/// </summary>
/// <param name="PropID">The property ID</param>
/// <param name="Value">The value which will be set</param>
public void SetSetting(uint PropID, uint Value)
{
    if (MainCamera.Ref != IntPtr.Zero)
    {
        int propsize;
        EDSDK.EdsDataType proptype;
        //get the size of this property
        Error = EDSDK.EdsGetPropertySize(MainCamera.Ref, PropID, 0, out proptype, out propsize);
        //set the property
        Error = EDSDK.EdsSetPropertyData(MainCamera.Ref, PropID, 0, propsize, Value);
    }
    else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
}

可获取的设置值清单:


特定的相机没有特定的支持设置。这就是为什么你需要去获取所有可支持的设置值清单。这些只支持"AEModeSelect", "ISO", "Av", "Tv", "MeteringMode" 和"ExposureCompensation"。传给特定的ID你可以获取到对应的返回值。在Camera类中可以找到和Av,Tv和ISO的对应值。查看PDF格式的SDK文档可以获取其他的值。

/// <summary>
/// Gets the list of possible values for the current camera to set.
/// Only the PropertyIDs "AEModeSelect", "ISO", "Av", "Tv", "MeteringMode" 
/// and "ExposureCompensation" are allowed.
/// </summary>
/// <param name="PropID">The property ID</param>
/// <returns>A list of available values for the given property ID</returns>
public List<int> GetSettingsList(uint PropID)
{
    if (MainCamera.Ref != IntPtr.Zero)
    {
        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)
        {
            EDSDK.EdsPropertyDesc des;
            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"); }
}

在bulb mode(灯泡模式)下正常拍照

用当前设置拍照,调用TakePhoto方法。有三点需要特别注意:

1、新线程启动了所以主线程没有被挂起。 

2、之所有这里用while 循环,是因为由相机有时不会立即就绪,需要稍后再试 

3、如果你将pc作为外设,那么请到下一个章节学习如何获取图片。

/// <summary>
/// Takes a photo with the current camera settings
/// </summary>
public void TakePhoto()
{
    new Thread(delegate()
    {
        int BusyCount = 0;
        uint err = EDSDK.EDS_ERR_OK;
        while (BusyCount < 20)
        {
            //try to take a photo
            err = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_TakePicture, 0);
            //if the camer is currently busy, wait and try again. 
            //If successful or an error happened, break the loop
            if (err == EDSDK.EDS_ERR_DEVICE_BUSY) { BusyCount++; Thread.Sleep(50); }
            else { break; }
        }
        Error = err;
    }).Start();
}

在bulb 模式下拍照,调用带有时间参数的takePhoto方法

/// <summary>
/// Takes a photo in bulb mode with the current camera settings
/// </summary>
/// <param name="BulbTime">The time in milliseconds for how long the shutter will be open</param>
public void TakePhoto(uint BulbTime)
{
    new Thread(delegate()
    {
        if (BulbTime < 1000) 
        { throw new ArgumentException("Bulbtime has to be bigger than 1000ms"); }
        int BusyCount = 0;
        uint err = EDSDK.EDS_ERR_OK;
        while (BusyCount < 20)
        {
            //open the shutter
            err = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_BulbStart, 0);
            if (err == EDSDK.EDS_ERR_DEVICE_BUSY) { BusyCount++; Thread.Sleep(50); }
            else { break; }
        }

        Error = err;
        //Wait for the specified time
        Thread.Sleep((int)BulbTime);
        //close the shutter
        Error = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_BulbEnd, 0);
    }).Start();
}

将拍摄的图片上传到电脑中

想要把拍摄的照片直接传到电脑上,代替相机存储,请调用SetSetting方法进行设置:

SetSetting(EDSDK.PropID_SaveTo, (uint)EDSDK.EdsSaveTo.Host);

每拍摄一张照片,EDSDK.ObjectEvent_DirItemRequestTransfer 类型的SDKObjectEvent都会被触发

/// <summary>
/// An Objectevent fired
/// </summary>
/// <param name="inEvent">The ObjectEvent id</param>
/// <param name="inRef">Pointer to the object</param>
/// <param name="inContext"></param>
/// <returns>An EDSDK errorcode</returns>
private uint Camera_SDKObjectEvent(uint inEvent, IntPtr inRef, IntPtr inContext)
{
    if(inEvent == EDSDK.ObjectEvent_DirItemRequestTransfer) 
    	DownloadImage(inRef, @"Images\");
    return EDSDK.EDS_ERR_OK;
}

DownloadImage方法如下:

/// <summary>
/// Downloads an image to given directory
/// </summary>
/// <param name="Info">Pointer to the object. 
/// Get it from the SDKObjectEvent.</param>
/// <param name="directory"></param>
public void DownloadImage(IntPtr ObjectPointer, string directory)
{
    EDSDK.EdsDirectoryItemInfo dirInfo;
    IntPtr streamRef;
    //get information about the image
    Error = EDSDK.EdsGetDirectoryItemInfo(ObjectPointer, out dirInfo);
    string CurrentPhoto = Path.Combine(directory, dirInfo.szFileName);
    //create a filestream for the image
    Error = EDSDK.EdsCreateFileStream(CurrentPhoto, 
    EDSDK.EdsFileCreateDisposition.CreateAlways, EDSDK.EdsAccess.ReadWrite, out streamRef);
    uint blockSize = 1024 * 1024;
    uint remainingBytes = dirInfo.Size;
    //download the image data in blocks
    do
    {
        if (remainingBytes < blockSize) { blockSize = (uint)(remainingBytes / 512) * 512; }
        remainingBytes -= blockSize;
        Error = EDSDK.EdsDownload(ObjectPointer, blockSize, streamRef);
    } while (remainingBytes > 512);
    //download the last bit of the image
    Error = EDSDK.EdsDownload(ObjectPointer, remainingBytes, streamRef);
    //tell the camera that the download is done
    Error = EDSDK.EdsDownloadComplete(ObjectPointer);
    //release image and stream
    Error = EDSDK.EdsRelease(ObjectPointer);
    Error = EDSDK.EdsRelease(streamRef);
}

打开并查看视频

视频是最难处理的事情之一,尤其是要求高性能的情况下。 首先我们这样打开视频:

/// <summary>
/// Starts the LiveView
/// </summary>
public void StartLiveView()
{
    //make sure it's not already on
    if (!IsLiveViewOn)
    {
        //set the LiveView output to be the PC
        SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_PC);
        IsLiveViewOn = true;
    }
}

完成之后, SDKPropertyEvent这个事件的 inPropertyID参数就被设置成了 EDSDK.PropID_Evf_OutputDevice:

/// <summary>
/// A property changed
/// </summary>
/// <param name="inEvent">The PropetyEvent ID</param>
/// <param name="inPropertyID">The Property ID</param>
/// <param name="inParameter">Event Parameter</param>
/// <param name="inContext">...</param>
/// <returns>An EDSDK errorcode</returns>
private uint Camera_SDKPropertyEvent
(uint inEvent, uint inPropertyID, uint inParameter, IntPtr inContext)
{
    if (inPropertyID == EDSDK.PropID_Evf_OutputDevice)
    {
        if (IsEvfFilming == true) DownloadEvfFilm();
        else if (IsLiveViewOn == true) DownloadEvf();
    }
    return EDSDK.EDS_ERR_OK;
}

DownloadEvf方法如下:

/// <summary>
/// Downloads the LiveView image
/// </summary>
private void DownloadEvf()
{
    new Thread(delegate()
    {
        //To give the camera time to switch the mirror
        Thread.Sleep(1500);

        IntPtr jpgPointer;
        IntPtr stream = IntPtr.Zero;
        IntPtr EvfImageRef = IntPtr.Zero;
        UnmanagedMemoryStream ums;
        uint err;
        uint length;
        //create streams
        err = EDSDK.EdsCreateMemoryStream(0, out stream);
        err = EDSDK.EdsCreateEvfImageRef(stream, out EvfImageRef);

        Stopwatch watch = new Stopwatch();    //stopwatch for FPS calculation
        float lastfr = 24; //last actual FPS

        //Run LiveView
        while (IsLiveViewOn)
        {
            watch.Restart();
            //download current LiveView image
            err = EDSDK.EdsDownloadEvfImage(MainCamera.Ref, EvfImageRef);

            unsafe
            {
                //get pointer and create stream
                Error = EDSDK.EdsGetPointer(stream, out jpgPointer);
                Error = EDSDK.EdsGetLength(stream, out length);
                ums = new UnmanagedMemoryStream
                ((byte*)jpgPointer.ToPointer(), length, length, FileAccess.Read);
                //fire the LiveViewUpdated event with 
                //the LiveView image created from the stream
                if (LiveViewUpdated != null) LiveViewUpdated(Image.FromStream(ums));
                ums.Close();
            }
            //calculate the framerate and fire the FrameRateUpdated event
            lastfr = lastfr * 0.9f + (100f / watch.ElapsedMilliseconds);
            if (FrameRateUpdated != null) FrameRateUpdated(lastfr);
        }

        //Release and finish
        if (stream != IntPtr.Zero) { Error = EDSDK.EdsRelease(stream); }
        if (EvfImageRef != IntPtr.Zero) { Error = EDSDK.EdsRelease(EvfImageRef); }
        //stop the LiveView
        SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_TFT);
    }).Start();
}

虽然这样下载视频图像不是最简单的,但可以说是最快的。

调用StopLiveView方法就能停止实物取景,实质上它的目的是让DownloadEvf方法跳出while循环:

/// <summary>
/// Stops the LiveView
/// </summary>
public void StopLiveView()
{
    IsLiveViewOn = false;
}

记录播放窗口

记录视频的工作跟播放视频的方式很像。

开始方法如下:

/// <summary>
/// Starts LiveView and records it
/// </summary>
public void StartEvfFilming()
{
    if (!IsLiveViewOn)
    {
        SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_PC);
        IsLiveViewOn = true;
        IsEvfFilming = true;
    }
}

捕获SDKPropertyEvent事件:

/// <summary>
/// A property changed
/// </summary>
/// <param name="inEvent">The PropetyEvent ID</param>
/// <param name="inPropertyID">The Property ID</param>
/// <param name="inParameter">Event Parameter</param>
/// <param name="inContext">...</param>
/// <returns>An EDSDK errorcode</returns>
private uint Camera_SDKPropertyEvent
(uint inEvent, uint inPropertyID, uint inParameter, IntPtr inContext)
{
    if (inPropertyID == EDSDK.PropID_Evf_OutputDevice)
    {
        if (IsEvfFilming == true) DownloadEvfFilm();
        else if (IsLiveViewOn == true) DownloadEvf();
    }
    return EDSDK.EDS_ERR_OK;
}

DownloadEvfFilmmethod和DownloadEvfmethod比较相似,但有以下不同:

  • 在开始while循环之前,已经下载了一个边框,并启动了 StartEvfVideoWriter方法。
  • 为了更好的性能,LiveViewUpdatedevent只在每次第四个边框中调用(让实时取景稍显缓慢,但视频很流畅)
  • 实时取景图像作为byte array放入队列中,供StartEvfVideoWriter方法处理
/// <summary>
/// Records the LiveView image
/// </summary>
private void DownloadEvfFilm()
{
    new Thread(delegate()
    {
        //To give the camera time to switch the mirror
        Thread.Sleep(1500);

        IntPtr jpgPointer;
        IntPtr stream = IntPtr.Zero;
        IntPtr EvfImageRef = IntPtr.Zero;
        UnmanagedMemoryStream ums;
        uint err;
        uint length;

        err = EDSDK.EdsCreateMemoryStream(0, out stream);
        err = EDSDK.EdsCreateEvfImageRef(stream, out EvfImageRef);

        //Download one frame to init the video size
        err = EDSDK.EdsDownloadEvfImage(MainCamera.Ref, EvfImageRef);
        unsafe
        {
            Error = EDSDK.EdsGetPointer(stream, out jpgPointer);
            Error = EDSDK.EdsGetLength(stream, out length);
            ums = new UnmanagedMemoryStream((byte*)jpgPointer.ToPointer(), 
            		length, length, FileAccess.Read);
            Bitmap bmp = new Bitmap(ums);
            StartEvfVideoWriter(bmp.Width, bmp.Height);
            bmp.Dispose();
            ums.Close();
        }

        Stopwatch watch = new Stopwatch();
        byte[] barr; //bitmap byte array
        const long ft = 41; //Frametime at 24FPS 
        			//(actually 41.66, but there is a bit of calculation overhead)
        float lastfr = 24; //last actual FPS
        int LVUpdateBreak1 = 0;

        //Run LiveView
        while (IsEvfFilming)
        {
            watch.Restart();
            err = EDSDK.EdsDownloadEvfImage(MainCamera.Ref, EvfImageRef);

            unsafe
            {
                Error = EDSDK.EdsGetPointer(stream, out jpgPointer);
                Error = EDSDK.EdsGetLength(stream, out length);
                ums = new UnmanagedMemoryStream((byte*)jpgPointer.ToPointer(), 
                		length, length, FileAccess.Read);
                barr = new byte[length];
                ums.Read(barr, 0, (int)length);

                //For better performance the LiveView is only updated with every 4th frame
                if (LVUpdateBreak1 == 0 && LiveViewUpdated != null) 
                	{ LiveViewUpdated(Image.FromStream(ums)); LVUpdateBreak1 = 4; }
                LVUpdateBreak1--;
                FrameBuffer.Enqueue(barr);
                ums.Close();
            }

            //To get a steady framerate:
            while (true) if (watch.ElapsedMilliseconds >= ft) break;
            lastfr = lastfr * 0.9f + (100f / watch.ElapsedMilliseconds);
            if (FrameRateUpdated != null) FrameRateUpdated(lastfr);
        }

        //Release and finish
        if (stream != IntPtr.Zero) { Error = EDSDK.EdsRelease(stream); }
        if (EvfImageRef != IntPtr.Zero) { Error = EDSDK.EdsRelease(EvfImageRef); }
        SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_TFT);
    }).Start();
}

由于写硬件驱动转换图片对象很慢,并且这也不需要实时处理,所以有了下面的StartEvfVideoWriter 方法 。这个方法将边框从队列中取出来保存,直到队列为空并且电影处理已关闭。我这里没有包含实际的视频保存功能,你可以用你偏好的类库去完成。

/// <summary>
/// Writes video frames from the buffer to a file
/// </summary>
/// <param name="Width">Width of the video</param>
/// <param name="Height">Height of the video</param>
private void StartEvfVideoWriter(int Width, int Height)
{
    new Thread(delegate()
    {
        byte[] byteArray;
        ImageConverter ic = new ImageConverter();
        Image img;
        while (IsEvfFilming)
        {
            while (FrameBuffer.Count > 0)
            {
                //get byte array from queue
                byteArray = FrameBuffer.Dequeue();
                //convert it to an image object
                img = (Image)ic.ConvertFrom(byteArray);
                //Save video frame here. e.g. with the VideoFileWriter from the AForge library.
            }
            //if saving is faster than the LiveView, wait a bit for new frames and start over
            if (IsEvfFilming) Thread.Sleep(10);
        }
    }).Start();
}

下面是如何利用 AForgelibrary的一个例子
(请注意correct DLLs,它们没被包含在这个项目中)

private void StartVideoWriter(int Width, int Height)
{
    new Thread(delegate()
    {
        VideoFileWriter writer = new VideoFileWriter();
        writer.Open("LiveViewVideo.avi", Width, Height, 24, VideoCodec.MPEG4);
        byte[] byteArray;
        ImageConverter ic = new ImageConverter();
        Image img;
        while (IsEvfFilming)
        {
            while (FrameBuffer.Count > 0)
            {
                byteArray = FrameBuffer.Dequeue();
                img = (Image)ic.ConvertFrom(byteArray);
                writer.WriteVideoFrame(new Bitmap(img));
            }
            if (IsEvfFilming) Thread.Sleep(10);
        }
        writer.Close();
    }).Start();
}

关闭电影功能跟关闭实时取景方法一样:

/// <summary>
/// Stops LiveView and filming
/// </summary>
public void StopEvfFilming()
{
    IsLiveViewOn = false;
    IsEvfFilming = false;
} 

关闭/打开相机的接口

为了避免或允许用户在相机上改变设置,你可以这样关闭或者打开相机的接口:

/// <summary>
/// Locks or unlocks the cameras UI
/// </summary>
/// <param name="LockState">True for locked, false to unlock</param>
public void UILock(bool LockState)
{
    if (LockState == true) Error = 
    EDSDK.EdsSendStatusCommand(MainCamera.Ref, EDSDK.CameraState_UILock, 0);
    else Error = EDSDK.EdsSendStatusCommand
    	(MainCamera.Ref, EDSDK.CameraState_UIUnLock, 0);
}

利用图形化界面

在图像化界面向导代码中,你可以看到如何将以上所有的代码运用到一个真实可用的软件中。你也可以设置 Av,Tv,ISO和白平衡,实时取景和拍照等模式.

插入相机,打开图形化界面就可以开始你的设置啦。

题外话

我用EOS 40D测试了以上代码:

如果你尝试了不同的方法,请告诉我,我会把它添加到这篇文章中。

如果你发现一些bug,对方法有改进或者有一些新的想法,非常希望你能告诉我。

源码下载:

抱歉!评论已关闭.