
Нашей задачей стало создание WPF-приложения Photobooth, которое должно работать с камерами Canon EOS: фотографировать и снимать видео. Для этих целей Canon предоставляет разработчикам EOS Digital SDK (EDSDK). Мы использовали версию 2.11. Ниже приведен полный перечень поддерживаемых камер:
- EOS-1D Mark III
- EOS 40D
- EOS-1Ds Mark III
- EOS DIGITAL REBEL Xsi/450D/ Kiss X2
- EOS DIGITAL REBEL XS/ 1000D/ KISS F
- EOS 50D
- EOS 5D Mark II
- EOS Kiss X3/EOS REBEL T1i /EOS 500D
- EOS 7D
- EOS-1D Mark IV
- EOS Kiss X4/EOS REBEL T2i /EOS 550D
- EOS 60D
- EOS Kiss X5/EOS REBEL T3i /EOS 600D
- EOS Kiss X50/EOS REBEL T3 /EOS 1100D
- EOS 5D Mark III
- EOS 1D X
- EOS Kiss X6i/EOS 650D/EOS REBEL T4i
Canon EDSDK — библиотека, написанная на C/C++. Она предоставляет возможность управлять цифровой камерой, подключенной к ПК, загружать фото и видео с камеры на компьютер.
Так как мы используем C# и WPF, то взяли враппер EDSDK для .NET — https://edsdkwrapper.codeplex.com/. Он использует COM Interop. Мы только добавили поддержку видео. EDSDK содержит несколько нативных DLL-библиотек:

Чтобы использовать EDSDK в вашем .NET-проекте, поместите эти библиотеки и папку «icc» в папку Debug или Release и добавьте ссылку на EDSDKWrapper.Framework.dll. Основной класс этого враппера, FrameworkManager, расположен в пространстве имён EDSDKWrapper.Framework.Managers. Этот класс реализует функцию инициализации/завершения работы EDSDK и даёт доступ к списку камер. Чтобы получить доступ к камере, подключенной к ПК, используйте следующий код:
using EDSDKWrapper.Framework.Managers; using EDSDKWrapper.Framework.Objects; var frameworkManager = new FrameworkManager(); var camera = frameworkManager.GetCameras().FirstOrDefault();
Camera — второй важный класс в EDSDK. Она реализует доступ к таким настройкам камеры, как автоэкспозиция, чувствительность ISO, диафрагма, выдержка, баланс белого и др. Полный список настроек есть в руководстве к EDSDK API. Также этот класс реализует функцию предпросмотра, фото- и видео-съёмки. Все настройки камеры завёрнуты в перечисляемые типы в пространстве имён EDSDKWrapper.Framework.Enums. Чтобы задать настройки и начать запись видео с предпросмотром, используйте следующий код:
using EDSDKWrapper.Framework.Managers; using EDSDKWrapper.Framework.Objects; using EDSDKWrapper.Framework.Enums; var frameworkManager = new FrameworkManager(); var camera = frameworkManager.GetCameras().FirstOrDefault(); camera.LiveViewEnabled = true; camera.LiveViewOutputDevice = LiveViewOutputDevice.Computer; camera.AEModeSelect = AEMode.Movie; camera.SaveTo = SaveTo.Camera; camera.VideoDownloaded += cameraVideoDownloaded; camera.Record = Record.Start; DateTime start = DateTime.Now; while (camera.IsRecording && (DateTime.Now - start).Seconds < someDuration) { var stream = this.Camera.GetLiveViewImage(); // some actions with stream, e.g. displaying live view image in app window } camera.Record = Record.Stop; camera.LiveViewEnabled = false; camera.Dispose(); frameworkManager.Dispose();
Здесь мы включили режим предпросмотра и видеорежим, установили передачу картинки предпросмотра и записанного видео на ПК, а также добавили обработчик для события VideoDownloaded. Затем мы начали записывать в течение некоторого времени, после чего остановили запись и освободили неиспользуемые ресурсы.
Как уже было сказано, данный враппер не поддерживает видеорежим. Как же заставить его работать? Когда мы устанавливаем какой-либо параметр камеры, мы вызываем стандартную функцию EDSDK — EdsSetPropertyData:
EdsError EdsSetPropertyData( EdsBaseRef inRef, EdsPropertyID inPropertyID, EdsInt32 inParam, EdsUInt32 inPropertySize, const EdsVoid* inPropertyData)
Описания параметров:
- inRef — обозначает объект (EdsCameraRef или EdsImageRef), для которого устанавливаются свойства.
- inPropertyID — объявляет идентификатор свойства.
- inParam — объявляет дополнительную информацию о свойстве. Используйте дополнительную информацию о свойствах, если они могут быть установлены или возвращены для нескольких элементов, таких как стили изображения.
- inPropertySize — устанавливает объём данных для свойства в байтах. Для каждого свойства это значение можно узнать при помощи функции EdsGetPropertySize.
- inPropertyData — определяет данные свойства, которое устанавливается.
Параметр inPropertyID определяет, какие операции мы будем производить и какие настройки камеры будем менять. Для видеозаписи он равен 0x00000510. Таким образом, мы добавили следующую строку для перечисляемого типа PropertyId во враппере:
namespace EDSDKWrapper.Framework.Enums { public enum PropertyId : uint { ... Record = 0x00000510, ... } }
Далее мы можем создать новый перечисляемый тип Record с состояниями записи:
namespace EDSDKWrapper.Framework.Enums { public enum Record : uint { Start = 4, Stop = 0 } }
Далее добавляем свойства классу Camera:
public Record Record { get { return (Record) GetUInt32Property(PropertyId.Record); } set { SetUInt32Property(PropertyId.Record, (UInt32) value); } } public bool IsRecording { get { return Record == Record.Start; } }
Далее определяем наш делегат:
public static class UserDelegates { public delegate void DownloadedVideoHandler(Stream videoStream, string filename); }
После чего мы изменили метод objectEventHandler и добавили новый метод DownloadVideo в класс Camera:
if (inEvent == (uint)ObjectEvent.DirItemCreated) { DownloadVideo(inRef); } public event UserDelegates.DownloadedVideoHandler VideoDownloaded; public void DownloadVideo(IntPtr inRef) { IntPtr streamPointer = IntPtr.Zero; DirectoryItemInformation info; uint returnValue = EDSDKInvokes.GetDirectoryItemInformation(inRef, out info); ReturnValueManager.HandleFunctionReturnValue(returnValue); try { //returnValue = EDSDKInvokes.CreateFileStream(info.FileName, // FileCreateDisposition.CreateAlways, // Access.ReadWrite, // out streamPointer); EDSDKInvokes.CreateMemoryStream(info.Size, out streamPointer); ReturnValueManager.HandleFunctionReturnValue(returnValue); IntPtr videoBlob = IntPtr.Zero; try { returnValue = EDSDKInvokes.Download(inRef, info.Size, streamPointer); ReturnValueManager.HandleFunctionReturnValue(returnValue); returnValue = EDSDKInvokes.DownloadComplete(inRef); ReturnValueManager.HandleFunctionReturnValue(returnValue); returnValue = EDSDKInvokes.GetPointer(streamPointer, out videoBlob); ReturnValueManager.HandleFunctionReturnValue(returnValue); uint videoLength; returnValue = EDSDKInvokes.GetLength(streamPointer, out videoLength); ReturnValueManager.HandleFunctionReturnValue(returnValue); var buffer = new byte[videoLength]; Marshal.Copy(videoBlob, buffer, 0, (int)videoLength); var stream = new MemoryStream(buffer); if (VideoDownloaded != null) VideoDownloaded(stream, info.FileName); Global.OnDownloadVideo(stream, info.FileName); } finally { EDSDKInvokes.Release(videoBlob); } } finally { EDSDKInvokes.Release(streamPointer); } }
Этот метод передаёт записанный поток видео обработчику событий VideoDownloaded. Поток можно сохранить в файл следующим образом:
private void CameraVideoDownloaded(Stream videoStream, string filename) { using (var fileStream = File.Create(filename)) { videoStream.CopyTo(fileStream); fileStream.Flush(); fileStream.Close(); } }
Таким образом, через EDSDK можно управлять многими функциями камер Canon EOS. Полный список параметров и команд содержится в руководстве к EDSDK API.