http://blog.csdn.net/zajin/article/details/17021339 

介绍

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

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

另外:其实我不从属于佳能公司,也不受其自助。 
还有:我不对这个软件做任何方式担保。使用时请您自己注意风险! (你可以在GPL许可证中找到有关此主题的更多信息。)

背景

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

  • 欧洲、非洲及中东
  • 北美、中美和南美洲
  • 澳大利亚和新西兰
  • 印度、印度尼西亚、马来西亚、巴基斯坦、菲律宾和泰国

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

使用代码

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

在SDKHandler中有几个变量:

[csharp]  view plain copy
  1. /// <summary>
  2. /// The used camera
  3. /// </summary>
  4. public Camera MainCamera { get; private set; }
  5. /// <summary>
  6. /// States if a session with the MainCamera is opened
  7. /// </summary>
  8. public bool CameraSessionOpen { get; private set; }
  9. /// <summary>
  10. /// States if the LiveView is on or not
  11. /// </summary>
  12. public bool IsLiveViewOn { get; private set; }
  13. /// <summary>
  14. /// States if LiveView is recorded or not
  15. /// </summary>
  16. public bool IsEvfFilming { get; private set; }
  17. /// <summary>
  18. /// Directory to where photos will be saved
  19. /// </summary>
  20. public string ImageSaveDirectory { get; set; }
  21. /// <summary>
  22. /// Handles errors that happen with the SDK
  23. /// </summary>
  24. public uint Error
  25. {
  26. get { return EDSDK.EDS_ERR_OK; }
  27. set { if (value != EDSDK.EDS_ERR_OK) throw new Exception("SDK Error: " + value); }
  28. }
  29. /// <summary>
  30. /// Frame buffer for LiveView recording
  31. /// </summary>
  32. private Queue<byte[]> FrameBuffer = new Queue<byte[]>(1000);

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

[csharp]  view plain copy
  1. #region SDK Events
  2. public event EDSDK.EdsCameraAddedHandler SDKCameraAddedEvent;
  3. public event EDSDK.EdsObjectEventHandler SDKObjectEvent;
  4. public event EDSDK.EdsProgressCallback SDKProgressCallbackEvent;
  5. public event EDSDK.EdsPropertyEventHandler SDKPropertyEvent;
  6. public event EDSDK.EdsStateEventHandler SDKStateEvent;
  7. #endregion
  8. #region Custom Events
  9. public delegate void CameraAddedHandler();
  10. public delegate void ProgressHandler(int Progress);
  11. public delegate void ImageUpdate(Image img);
  12. public delegate void FloatUpdate(float Value);
  13. /// <summary>
  14. /// Fires if a camera is added
  15. /// </summary>
  16. public event CameraAddedHandler CameraAdded;
  17. /// <summary>
  18. /// Fires if any process reports progress
  19. /// </summary>
  20. public event ProgressHandler ProgressChanged;
  21. /// <summary>
  22. /// Fires if the LiveView image is updated
  23. /// </summary>
  24. public event ImageUpdate LiveViewUpdated;
  25. /// <summary>
  26. /// Fires if a new framerate is calculated
  27. /// </summary>
  28. public event FloatUpdate FrameRateUpdated;
  29. #endregion

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

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

[csharp]  view plain copy
  1. public class Camera
  2. {
  3. internal IntPtr Ref;
  4. public EDSDK.EdsDeviceInfo Info { get; private set; }
  5. public uint Error
  6. {
  7. get { return EDSDK.EDS_ERR_OK; }
  8. set { if (value != EDSDK.EDS_ERR_OK) throw new Exception("SDK Error: " + value); }
  9. }
  10. public Camera(IntPtr Reference)
  11. {
  12. this.Ref = Reference;
  13. EDSDK.EdsDeviceInfo dinfo;
  14. Error = EDSDK.EdsGetDeviceInfo(Reference, out dinfo);
  15. this.Info = dinfo;
  16. }
  17. }
CameraValues是一个拥有所有单元ID值以及存储从Av、Tv到ISO字符串值的静态类。

初始化和终止SDK

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Initialises the SDK and adds events
  3. /// </summary>
  4. public SDKHandler()
  5. {
  6. //this is the important part of initialisation
  7. Error = EDSDK.EdsInitializeSDK();
  8. //here we subscribe to the CameraAddedEvent and tell the SDK we did so
  9. CameraAddedEvent += new EDSDK.EdsCameraAddedHandler(SDKHandler_CameraAddedEvent);
  10. EDSDK.EdsSetCameraAddedHandler(CameraAddedEvent, IntPtr.Zero);
  11. //here we subscribe to the rest of the camera events
  12. SDKStateEvent += new EDSDK.EdsStateEventHandler(Camera_SDKStateEvent);
  13. SDKPropertyEvent += new EDSDK.EdsPropertyEventHandler(Camera_SDKPropertyEvent);
  14. SDKProgressCallbackEvent += new EDSDK.EdsProgressCallback(Camera_SDKProgressCallbackEvent);
  15. SDKObjectEvent += new EDSDK.EdsObjectEventHandler(Camera_SDKObjectEvent);
  16. }

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Closes open session and terminates the SDK
  3. /// </summary>
  4. public void Dispose()
  5. {
  6. if (CameraSessionOpen) Error = EDSDK.EdsCloseSession(MainCamera.Ref);
  7. Error = EDSDK.EdsTerminateSDK();
  8. }

获取连接的像机列表

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Get a list of all connected cameras
  3. /// </summary>
  4. /// <returns>The camera list</returns>
  5. public List<Camera> GetCameraList()
  6. {
  7. IntPtr camlist;
  8. //Get cameralist
  9. Error = EDSDK.EdsGetCameraList(out camlist);
  10. //Get each camera from camlist
  11. int c;
  12. Error = EDSDK.EdsGetChildCount(camlist, out c);
  13. List<Camera> OutCamList = new List<Camera>();
  14. for (int i = 0; i < c; i++)
  15. {
  16. IntPtr cptr;
  17. Error = EDSDK.EdsGetChildAtIndex(camlist, i, out cptr);
  18. OutCamList.Add(new Camera(cptr));
  19. {
  20. return OutCamList;
  21. }

打开和关闭相机会话

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Opens a session with given camera
  3. /// </summary>
  4. /// <param name="NewCamera">The camera which will be used</param>
  5. public void OpenSession(Camera NewCamera)
  6. {
  7. //make sure the previous camera session is closed
  8. if (CameraSessionOpen) Error = EDSDK.EdsCloseSession(MainCamera.Ref);
  9. if (NewCamera != null)
  10. {
  11. MainCamera = NewCamera;
  12. //open a session
  13. Error = EDSDK.EdsOpenSession(MainCamera.Ref);
  14. //subscribe to the camera events (this time, in-Camera)
  15. EDSDK.EdsSetCameraStateEventHandler(MainCamera.Ref,
  16. EDSDK.StateEvent_All, SDKStateEvent, IntPtr.Zero);
  17. EDSDK.EdsSetObjectEventHandler(MainCamera.Ref,
  18. EDSDK.ObjectEvent_All, SDKObjectEvent, IntPtr.Zero);
  19. EDSDK.EdsSetPropertyEventHandler(MainCamera.Ref,
  20. EDSDK.PropertyEvent_All, SDKPropertyEvent, IntPtr.Zero);
  21. CameraSessionOpen = true;
  22. }
  23. }

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Closes the session with the current camera
  3. /// </summary>
  4. public void CloseSession()
  5. {
  6. if (CameraSessionOpen)
  7. {
  8. Error = EDSDK.EdsCloseSession(MainCamera.Ref);
  9. CameraSessionOpen = false;
  10. }
  11. }

Set 和 Get 相机设置

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Gets the current setting of given property ID
  3. /// </summary>
  4. /// <param name="PropID">The property ID</param>
  5. /// <returns>The current setting of the camera</returns>
  6. public uint GetSetting(uint PropID)
  7. {
  8. if (MainCamera.Ref != IntPtr.Zero)
  9. {
  10. unsafe
  11. {
  12. uint property = 0;
  13. EDSDK.EdsDataType dataType;
  14. int dataSize;
  15. IntPtr ptr = new IntPtr(&property);
  16. //get the size of this property
  17. Error = EDSDK.EdsGetPropertySize(MainCamera.Ref, PropID, 0, out dataType, out dataSize);
  18. //get the data for this property
  19. Error = EDSDK.EdsGetPropertyData(MainCamera.Ref, PropID, 0, dataSize, ptr);
  20. return property;
  21. }
  22. }
  23. else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
  24. }

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Sets a value for the given property ID
  3. /// </summary>
  4. /// <param name="PropID">The property ID</param>
  5. /// <param name="Value">The value which will be set</param>
  6. public void SetSetting(uint PropID, uint Value)
  7. {
  8. if (MainCamera.Ref != IntPtr.Zero)
  9. {
  10. int propsize;
  11. EDSDK.EdsDataType proptype;
  12. //get the size of this property
  13. Error = EDSDK.EdsGetPropertySize(MainCamera.Ref, PropID, 0, out proptype, out propsize);
  14. //set the property
  15. Error = EDSDK.EdsSetPropertyData(MainCamera.Ref, PropID, 0, propsize, Value);
  16. }
  17. else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
  18. }

可获取的设置值清单:

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Gets the list of possible values for the current camera to set.
  3. /// Only the PropertyIDs "AEModeSelect", "ISO", "Av", "Tv", "MeteringMode"
  4. /// and "ExposureCompensation" are allowed.
  5. /// </summary>
  6. /// <param name="PropID">The property ID</param>
  7. /// <returns>A list of available values for the given property ID</returns>
  8. public List<int> GetSettingsList(uint PropID)
  9. {
  10. if (MainCamera.Ref != IntPtr.Zero)
  11. {
  12. if (PropID == EDSDK.PropID_AEModeSelect || PropID == EDSDK.PropID_ISOSpeed ||
  13. PropID == EDSDK.PropID_Av
  14. || PropID == EDSDK.PropID_Tv || PropID == EDSDK.PropID_MeteringMode ||
  15. PropID == EDSDK.PropID_ExposureCompensation)
  16. {
  17. EDSDK.EdsPropertyDesc des;
  18. Error = EDSDK.EdsGetPropertyDesc(MainCamera.Ref, PropID, out des);
  19. return des.PropDesc.Take(des.NumElements).ToList();
  20. }
  21. else throw new ArgumentException("Method cannot be used with this Property ID");
  22. }
  23. else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
  24. }

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

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

1、新线程启动了所以主线程没有被挂起。 
2、之所有这里用while 循环,是因为由相机有时不会立即就绪,需要稍后再试 
3、如果你将pc作为外设,那么请到下一个章节学习如何获取图片。

[csharp]  view plain copy
  1. /// <summary>
  2. /// Takes a photo with the current camera settings
  3. /// </summary>
  4. public void TakePhoto()
  5. {
  6. new Thread(delegate()
  7. {
  8. int BusyCount = 0;
  9. uint err = EDSDK.EDS_ERR_OK;
  10. while (BusyCount < 20)
  11. {
  12. //try to take a photo
  13. err = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_TakePicture, 0);
  14. //if the camer is currently busy, wait and try again.
  15. //If successful or an error happened, break the loop
  16. if (err == EDSDK.EDS_ERR_DEVICE_BUSY) { BusyCount++; Thread.Sleep(50); }
  17. else { break; }
  18. }
  19. Error = err;
  20. }).Start();
  21. }

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Takes a photo in bulb mode with the current camera settings
  3. /// </summary>
  4. /// <param name="BulbTime">The time in milliseconds for how long the shutter will be open</param>
  5. public void TakePhoto(uint BulbTime)
  6. {
  7. new Thread(delegate()
  8. {
  9. if (BulbTime < 1000)
  10. { throw new ArgumentException("Bulbtime has to be bigger than 1000ms"); }
  11. int BusyCount = 0;
  12. uint err = EDSDK.EDS_ERR_OK;
  13. while (BusyCount < 20)
  14. {
  15. //open the shutter
  16. err = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_BulbStart, 0);
  17. if (err == EDSDK.EDS_ERR_DEVICE_BUSY) { BusyCount++; Thread.Sleep(50); }
  18. else { break; }
  19. }
  20. Error = err;
  21. //Wait for the specified time
  22. Thread.Sleep((int)BulbTime);
  23. //close the shutter
  24. Error = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_BulbEnd, 0);
  25. }).Start();
  26. }

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

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

[csharp]  view plain copy
  1. SetSetting(EDSDK.PropID_SaveTo, (uint)EDSDK.EdsSaveTo.Host);

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// An Objectevent fired
  3. /// </summary>
  4. /// <param name="inEvent">The ObjectEvent id</param>
  5. /// <param name="inRef">Pointer to the object</param>
  6. /// <param name="inContext"></param>
  7. /// <returns>An EDSDK errorcode</returns>
  8. private uint Camera_SDKObjectEvent(uint inEvent, IntPtr inRef, IntPtr inContext)
  9. {
  10. if(inEvent == EDSDK.ObjectEvent_DirItemRequestTransfer)
  11. DownloadImage(inRef, @"Images\");
  12. return EDSDK.EDS_ERR_OK;
  13. }

DownloadImage方法如下:

[csharp]  view plain copy
  1. /// <summary>
  2. /// Downloads an image to given directory
  3. /// </summary>
  4. /// <param name="Info">Pointer to the object.
  5. /// Get it from the SDKObjectEvent.</param>
  6. /// <param name="directory"></param>
  7. public void DownloadImage(IntPtr ObjectPointer, string directory)
  8. {
  9. EDSDK.EdsDirectoryItemInfo dirInfo;
  10. IntPtr streamRef;
  11. //get information about the image
  12. Error = EDSDK.EdsGetDirectoryItemInfo(ObjectPointer, out dirInfo);
  13. string CurrentPhoto = Path.Combine(directory, dirInfo.szFileName);
  14. //create a filestream for the image
  15. Error = EDSDK.EdsCreateFileStream(CurrentPhoto,
  16. EDSDK.EdsFileCreateDisposition.CreateAlways, EDSDK.EdsAccess.ReadWrite, out streamRef);
  17. uint blockSize = 1024 * 1024;
  18. uint remainingBytes = dirInfo.Size;
  19. //download the image data in blocks
  20. do
  21. {
  22. if (remainingBytes < blockSize) { blockSize = (uint)(remainingBytes / 512) * 512; }
  23. remainingBytes -= blockSize;
  24. Error = EDSDK.EdsDownload(ObjectPointer, blockSize, streamRef);
  25. } while (remainingBytes > 512);
  26. //download the last bit of the image
  27. Error = EDSDK.EdsDownload(ObjectPointer, remainingBytes, streamRef);
  28. //tell the camera that the download is done
  29. Error = EDSDK.EdsDownloadComplete(ObjectPointer);
  30. //release image and stream
  31. Error = EDSDK.EdsRelease(ObjectPointer);
  32. Error = EDSDK.EdsRelease(streamRef);
  33. }

打开并查看视频

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Starts the LiveView
  3. /// </summary>
  4. public void StartLiveView()
  5. {
  6. //make sure it's not already on
  7. if (!IsLiveViewOn)
  8. {
  9. //set the LiveView output to be the PC
  10. SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_PC);
  11. IsLiveViewOn = true;
  12. }
  13. }

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// A property changed
  3. /// </summary>
  4. /// <param name="inEvent">The PropetyEvent ID</param>
  5. /// <param name="inPropertyID">The Property ID</param>
  6. /// <param name="inParameter">Event Parameter</param>
  7. /// <param name="inContext">...</param>
  8. /// <returns>An EDSDK errorcode</returns>
  9. private uint Camera_SDKPropertyEvent
  10. (uint inEvent, uint inPropertyID, uint inParameter, IntPtr inContext)
  11. {
  12. if (inPropertyID == EDSDK.PropID_Evf_OutputDevice)
  13. {
  14. if (IsEvfFilming == true) DownloadEvfFilm();
  15. else if (IsLiveViewOn == true) DownloadEvf();
  16. }
  17. return EDSDK.EDS_ERR_OK;
  18. }

DownloadEvf方法如下:

[csharp]  view plain copy
  1. /// <summary>
  2. /// Downloads the LiveView image
  3. /// </summary>
  4. private void DownloadEvf()
  5. {
  6. new Thread(delegate()
  7. {
  8. //To give the camera time to switch the mirror
  9. Thread.Sleep(1500);
  10. IntPtr jpgPointer;
  11. IntPtr stream = IntPtr.Zero;
  12. IntPtr EvfImageRef = IntPtr.Zero;
  13. UnmanagedMemoryStream ums;
  14. uint err;
  15. uint length;
  16. //create streams
  17. err = EDSDK.EdsCreateMemoryStream(0, out stream);
  18. err = EDSDK.EdsCreateEvfImageRef(stream, out EvfImageRef);
  19. Stopwatch watch = new Stopwatch();    //stopwatch for FPS calculation
  20. float lastfr = 24; //last actual FPS
  21. //Run LiveView
  22. while (IsLiveViewOn)
  23. {
  24. watch.Restart();
  25. //download current LiveView image
  26. err = EDSDK.EdsDownloadEvfImage(MainCamera.Ref, EvfImageRef);
  27. unsafe
  28. {
  29. //get pointer and create stream
  30. Error = EDSDK.EdsGetPointer(stream, out jpgPointer);
  31. Error = EDSDK.EdsGetLength(stream, out length);
  32. ums = new UnmanagedMemoryStream
  33. ((byte*)jpgPointer.ToPointer(), length, length, FileAccess.Read);
  34. //fire the LiveViewUpdated event with
  35. //the LiveView image created from the stream
  36. if (LiveViewUpdated != null) LiveViewUpdated(Image.FromStream(ums));
  37. ums.Close();
  38. }
  39. //calculate the framerate and fire the FrameRateUpdated event
  40. lastfr = lastfr * 0.9f + (100f / watch.ElapsedMilliseconds);
  41. if (FrameRateUpdated != null) FrameRateUpdated(lastfr);
  42. }
  43. //Release and finish
  44. if (stream != IntPtr.Zero) { Error = EDSDK.EdsRelease(stream); }
  45. if (EvfImageRef != IntPtr.Zero) { Error = EDSDK.EdsRelease(EvfImageRef); }
  46. //stop the LiveView
  47. SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_TFT);
  48. }).Start();
  49. }

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

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Stops the LiveView
  3. /// </summary>
  4. public void StopLiveView()
  5. {
  6. IsLiveViewOn = false;
  7. }

记录播放窗口

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

开始方法如下:

[csharp]  view plain copy
  1. /// <summary>
  2. /// Starts LiveView and records it
  3. /// </summary>
  4. public void StartEvfFilming()
  5. {
  6. if (!IsLiveViewOn)
  7. {
  8. SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_PC);
  9. IsLiveViewOn = true;
  10. IsEvfFilming = true;
  11. }
  12. }

捕获SDKPropertyEvent事件:

[csharp]  view plain copy
  1. /// <summary>
  2. /// A property changed
  3. /// </summary>
  4. /// <param name="inEvent">The PropetyEvent ID</param>
  5. /// <param name="inPropertyID">The Property ID</param>
  6. /// <param name="inParameter">Event Parameter</param>
  7. /// <param name="inContext">...</param>
  8. /// <returns>An EDSDK errorcode</returns>
  9. private uint Camera_SDKPropertyEvent
  10. (uint inEvent, uint inPropertyID, uint inParameter, IntPtr inContext)
  11. {
  12. if (inPropertyID == EDSDK.PropID_Evf_OutputDevice)
  13. {
  14. if (IsEvfFilming == true) DownloadEvfFilm();
  15. else if (IsLiveViewOn == true) DownloadEvf();
  16. }
  17. return EDSDK.EDS_ERR_OK;
  18. }

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

  • 在开始while循环之前,已经下载了一个边框,并启动了 StartEvfVideoWriter方法。
  • 为了更好的性能,LiveViewUpdatedevent只在每次第四个边框中调用(让实时取景稍显缓慢,但视频很流畅)
  • 实时取景图像作为byte array放入队列中,供StartEvfVideoWriter方法处理
[csharp]  view plain copy
  1. /// <summary>
  2. /// Records the LiveView image
  3. /// </summary>
  4. private void DownloadEvfFilm()
  5. {
  6. new Thread(delegate()
  7. {
  8. //To give the camera time to switch the mirror
  9. Thread.Sleep(1500);
  10. IntPtr jpgPointer;
  11. IntPtr stream = IntPtr.Zero;
  12. IntPtr EvfImageRef = IntPtr.Zero;
  13. UnmanagedMemoryStream ums;
  14. uint err;
  15. uint length;
  16. err = EDSDK.EdsCreateMemoryStream(0, out stream);
  17. err = EDSDK.EdsCreateEvfImageRef(stream, out EvfImageRef);
  18. //Download one frame to init the video size
  19. err = EDSDK.EdsDownloadEvfImage(MainCamera.Ref, EvfImageRef);
  20. unsafe
  21. {
  22. Error = EDSDK.EdsGetPointer(stream, out jpgPointer);
  23. Error = EDSDK.EdsGetLength(stream, out length);
  24. ums = new UnmanagedMemoryStream((byte*)jpgPointer.ToPointer(),
  25. length, length, FileAccess.Read);
  26. Bitmap bmp = new Bitmap(ums);
  27. StartEvfVideoWriter(bmp.Width, bmp.Height);
  28. bmp.Dispose();
  29. ums.Close();
  30. }
  31. Stopwatch watch = new Stopwatch();
  32. byte[] barr; //bitmap byte array
  33. const long ft = 41; //Frametime at 24FPS
  34. //(actually 41.66, but there is a bit of calculation overhead)
  35. float lastfr = 24; //last actual FPS
  36. int LVUpdateBreak1 = 0;
  37. //Run LiveView
  38. while (IsEvfFilming)
  39. {
  40. watch.Restart();
  41. err = EDSDK.EdsDownloadEvfImage(MainCamera.Ref, EvfImageRef);
  42. unsafe
  43. {
  44. Error = EDSDK.EdsGetPointer(stream, out jpgPointer);
  45. Error = EDSDK.EdsGetLength(stream, out length);
  46. ums = new UnmanagedMemoryStream((byte*)jpgPointer.ToPointer(),
  47. length, length, FileAccess.Read);
  48. barr = new byte[length];
  49. ums.Read(barr, 0, (int)length);
  50. //For better performance the LiveView is only updated with every 4th frame
  51. if (LVUpdateBreak1 == 0 && LiveViewUpdated != null)
  52. { LiveViewUpdated(Image.FromStream(ums)); LVUpdateBreak1 = 4; }
  53. LVUpdateBreak1--;
  54. FrameBuffer.Enqueue(barr);
  55. ums.Close();
  56. }
  57. //To get a steady framerate:
  58. while (true) if (watch.ElapsedMilliseconds >= ft) break;
  59. lastfr = lastfr * 0.9f + (100f / watch.ElapsedMilliseconds);
  60. if (FrameRateUpdated != null) FrameRateUpdated(lastfr);
  61. }
  62. //Release and finish
  63. if (stream != IntPtr.Zero) { Error = EDSDK.EdsRelease(stream); }
  64. if (EvfImageRef != IntPtr.Zero) { Error = EDSDK.EdsRelease(EvfImageRef); }
  65. SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_TFT);
  66. }).Start();
  67. }

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Writes video frames from the buffer to a file
  3. /// </summary>
  4. /// <param name="Width">Width of the video</param>
  5. /// <param name="Height">Height of the video</param>
  6. private void StartEvfVideoWriter(int Width, int Height)
  7. {
  8. new Thread(delegate()
  9. {
  10. byte[] byteArray;
  11. ImageConverter ic = new ImageConverter();
  12. Image img;
  13. while (IsEvfFilming)
  14. {
  15. while (FrameBuffer.Count > 0)
  16. {
  17. //get byte array from queue
  18. byteArray = FrameBuffer.Dequeue();
  19. //convert it to an image object
  20. img = (Image)ic.ConvertFrom(byteArray);
  21. //Save video frame here. e.g. with the VideoFileWriter from the AForge library.
  22. }
  23. //if saving is faster than the LiveView, wait a bit for new frames and start over
  24. if (IsEvfFilming) Thread.Sleep(10);
  25. }
  26. }).Start();
  27. }

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

[csharp]  view plain copy
  1. private void StartVideoWriter(int Width, int Height)
  2. {
  3. new Thread(delegate()
  4. {
  5. VideoFileWriter writer = new VideoFileWriter();
  6. writer.Open("LiveViewVideo.avi", Width, Height, 24, VideoCodec.MPEG4);
  7. byte[] byteArray;
  8. ImageConverter ic = new ImageConverter();
  9. Image img;
  10. while (IsEvfFilming)
  11. {
  12. while (FrameBuffer.Count > 0)
  13. {
  14. byteArray = FrameBuffer.Dequeue();
  15. img = (Image)ic.ConvertFrom(byteArray);
  16. writer.WriteVideoFrame(new Bitmap(img));
  17. }
  18. if (IsEvfFilming) Thread.Sleep(10);
  19. }
  20. writer.Close();
  21. }).Start();
  22. }

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Stops LiveView and filming
  3. /// </summary>
  4. public void StopEvfFilming()
  5. {
  6. IsLiveViewOn = false;
  7. IsEvfFilming = false;
  8. }

关闭/打开相机的接口

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

[csharp]  view plain copy
  1. /// <summary>
  2. /// Locks or unlocks the cameras UI
  3. /// </summary>
  4. /// <param name="LockState">True for locked, false to unlock</param>
  5. public void UILock(bool LockState)
  6. {
  7. if (LockState == true) Error =
  8. EDSDK.EdsSendStatusCommand(MainCamera.Ref, EDSDK.CameraState_UILock, 0);
  9. else Error = EDSDK.EdsSendStatusCommand
  10. (MainCamera.Ref, EDSDK.CameraState_UIUnLock, 0);
  11. }

利用图形化界面

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

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

题外话

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

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

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

源码下载:

  • Download tutorial - 72.4 KB
  • Download tutorial (no EXE) - 45.3 KB

转载于:https://www.cnblogs.com/carl2380/p/4730571.html

佳能相机操作 EDSDK 教程 C# 版本相关推荐

  1. 四全集学python选哪种电脑_“Python教程哪个版本最适合学习?“python教程全集

    python教程,求一套比较好的python教程 好不好主要先看你自己,理解能力样,有没有接触过编程,有没础,这很重要: 看教程,能不能先给你建立起知识体系框架,许多教程一上来就直接给你灌输知识很让人 ...

  2. idea 2019激活置2099年教程 diea版本为2018.3版

    idea 2019激活置2099年教程 diea版本为2018.3版 1.下载完成之后双击安装包进行安装 官网下载链接 2.下载破解补丁 百度云下载地址 提取码:4m1b 找到idea安装目录的bin ...

  3. EasyRecovery 15 mac中文免费密钥数据恢复 安装软件的方法教程及版本对比

    为了方便果粉们的使用,EasyRecovery 15 For Mac已经率先上线,那么在使用之前需要在Mac电脑上安装,小编在此说明EasyRecovery 详细介绍安装软件的方法教程及版本对比. 准 ...

  4. 江苏海信ip906h盒子,强刷固件及教程(70T1版本)

    江苏海信ip906h盒子强刷安当贝桌面固件及教程(70T1版本) 固件介绍: 1.调出原厂固件屏蔽的wifi,开放原厂固件屏蔽的市场安装和u盘安装apk: 2.无开机广告,无系统更新,不在被强制升级: ...

  5. 5d4的白平衡模式_佳能5D4使用教程|视频教程|设置技巧(共29课时)

    (注意:佳能5D4系列教程为超级VIP专享,请开通超级VIP权限) 佳能5D4使用教程|视频教程|拍摄技巧 想快速掌握佳能5D4的各项功能,告别卡片机式的玩法?想从零基础入门,彻底玩转佳能5D4,从而 ...

  6. Axure for mac安装教程(版本8.1.0.3382)

    Axure for mac安装教程(版本8.1.0.3382) 第一步--下载安装包 官网下载安装包:https://www.axure.com/download 第二步--安装 如图双击刚下下来的A ...

  7. 重装系统教程(版本二)

    版本一的方法是传统方法,比较正规.但是比较麻烦,想要快速解决问题的朋友可以参考现在的这篇文章. 一:下载小马PEV2015-02-15-Beta.exe(下载链接:http://pan.baidu.c ...

  8. agentzh 的 Nginx 教程(版本 2015.03.19) 第一篇

    转载:http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html#02-NginxDirectiveExecOrder10 目录 缘 ...

  9. python官网下载安装教程-各种版本的Python下载安装教程

    python从17年开始大火,自然想学python的同学就多了,小编整理了这篇文章,从python的功能介绍.各系统最新版本python下载.python全部版本下载.python下载后安装教程以及p ...

最新文章

  1. [Oracle] 中的Temporary tablespace的作用
  2. 先装VS2008再装SQL2005的问题
  3. 【Xmind】,让你的大脑解放出来
  4. Linux文件的三种时间属性
  5. MongoDB-数据库-mongoose-图形化操作
  6. Snabbdom(虚拟dom-h函数)
  7. 微信小程序引入npm
  8. offset函数的高级用法_数据验证(数据有效性)结合Offset函数 的综合用法
  9. Thinkpad T470 内置电池问题
  10. C#+ItextSharp 查看pdf文件页面尺寸
  11. request_threaded_irq
  12. 欧拉角细节/旋转顺序/内旋外旋
  13. 同济子豪兄-机器学习基础
  14. Flyte简介:云原生机器学习和数据处理平台
  15. 102-gold入门
  16. 艰难时世的赚钱之道:淘金iPhone App (一)
  17. 煎蛋网妹子图爬虫(requests库实现)
  18. BI到底是什么,是否所有企业都适合上BI?
  19. .php可以转换为.jpg么,php pdf转换为jpg的方法
  20. 让自己对bff层有个了解--服务于前端的后端

热门文章

  1. linux查看已安装软件版本号
  2. 添加游戏对象到 Windows 7 游戏管理器中。
  3. 7-7 jmu-分段函数l (20 分)(PTA Python版本)
  4. ps 入门 传智播客_如果您喜欢写博客,则应尝试播客。 这是入门方法。
  5. 生活对我们每个人而言意味着什么?
  6. jar命令的一次实际使用
  7. 基于卷积神经网络对男女性眼睛进行识别
  8. Vue----路由器
  9. 知乎万赞,值得反复刷的Android面试题,金九银十正确打开方式
  10. 申请信息服务业务(短信息)经营许可证递交材料