Базовая фото, видео и аудиозапись с помощью MediaCapture

В этой статье показан самый простой способ захвата фотографий и видео с помощью класса MediaCapture. Класс MediaCapture предоставляет надежный набор API, обеспечивающий низкоуровневый контроль над конвейером захвата и включение сценариев расширенного захвата, но эта статья предназначена для быстрого и простого добавления базового захвата мультимедиа в приложение. Дополнительные сведения о функциях, предоставляемых MediaCapture, см. в Камера.

Если вы просто хотите записать фотографию или видео и не планируете добавлять дополнительные функции захвата мультимедиа, или если вы не хотите создавать собственный пользовательский интерфейс камеры, вы можете использовать класс Камера CaptureUI, который позволяет просто запустить встроенное приложение камеры Windows и получить фото или видеофайл, который был записан. Дополнительные сведения см. в разделе "Запись фотографий и видео с помощью встроенного пользовательского интерфейса камеры Windows"

Код в этой статье был адаптирован из примера начального набора Камера. Вы можете скачать пример, чтобы увидеть код, используемый в контексте, или использовать этот пример в качестве отправной точки для собственного приложения.

Добавление объявлений возможностей в манифест приложения

Чтобы приложение получите доступ к камере устройства, необходимо объявить, что ваше приложение использует возможности веб-камеры и микрофона . Если вы хотите сохранить захваченные фотографии и видео в библиотеку изображений или видео пользователей, необходимо также объявить возможность photoLibrary и видеоLibrary .

Добавление возможностей в манифест приложения

  1. В Microsoft Visual Studio в Обозреватель решений откройте конструктор манифеста приложения, дважды щелкнув элемент package.appxmanifest.
  2. Перейдите на вкладку Возможности.
  3. Установите флажок для веб-камеры и флажок для микрофона.
  4. Для доступа к библиотеке "Изображения и видео" проверка поля для библиотеки изображений и поля для библиотеки видео.

Инициализация объекта MediaCapture

Все методы захвата, описанные в этой статье, требуют первого шага инициализации объекта MediaCapture путем вызова конструктора, а затем вызова InitializeAsync. Так как объект MediaCapture будет обращаться из нескольких мест в приложении, объявите переменную класса для хранения объекта. Реализуйте обработчик события Failed объекта MediaCapture, чтобы получать уведомления о сбое операции записи.

MediaCapture mediaCapture;
bool isPreviewing;
mediaCapture = new MediaCapture();
await mediaCapture.InitializeAsync();
mediaCapture.Failed += MediaCapture_Failed;

Настройка предварительной версии камеры

Вы можете записывать фотографии, видео и звук с помощью MediaCapture , не отображая предварительный просмотр камеры, но обычно вы хотите показать поток предварительного просмотра, чтобы пользователь смог увидеть, что фиксируется. Кроме того, для некоторых функций MediaCapture требуется запустить поток предварительной версии, прежде чем их можно включить, включая автофокус, автоматическое воздействие и автобаланс. Сведения о настройке предварительной версии камеры см. в разделе "Отображение предварительного просмотра камеры".

Запись фотографии в SoftwareBitmap

Класс SoftwareBitmap был представлен в Windows 10 для предоставления общего представления изображений в нескольких функциях. Если вы хотите записать фотографию, а затем сразу же использовать захваченный образ в приложении, например отображение его в XAML, а не запись в файл, необходимо записать в SoftwareBitmap. Вы по-прежнему можете сохранить образ на диск позже.

После инициализации объекта MediaCapture можно записать фотографию в SoftwareBitmap с помощью класса LowLagPhotoCapture. Получите экземпляр этого класса, вызвав Метод PrepareLowLagPhotoCaptureAsync, передав объект ImageEncodingProperties, указывающий нужный формат изображения. CreateUncompressed создает несжатую кодировку с указанным форматом пикселей. Захватить фотографию с помощью вызова CaptureAsync, который возвращает объект CapturedPhoto. Получите SoftwareBitmap путем доступа к свойству Frame, а затем свойству SoftwareBitmap.

Если вы хотите, можно записать несколько фотографий, многократно вызвав CaptureAsync. После завершения записи вызовите FinishAsync , чтобы завершить сеанс LowLagPhotoCapture и освободить связанные ресурсы. После вызова FinishAsync, чтобы снова начать запись фотографий, необходимо снова вызвать PrepareLowLagPhotoCaptureAsync, чтобы повторно инициализировать сеанс захвата перед вызовом CaptureAsync.

// Prepare and capture photo
var lowLagCapture = await mediaCapture.PrepareLowLagPhotoCaptureAsync(ImageEncodingProperties.CreateUncompressed(MediaPixelFormat.Bgra8));

var capturedPhoto = await lowLagCapture.CaptureAsync();
var softwareBitmap = capturedPhoto.Frame.SoftwareBitmap;

await lowLagCapture.FinishAsync();

Начиная с Windows версии 1803, можно получить доступ к свойству BitmapProperties класса CapturedFrame, возвращенного из CaptureAsync, чтобы получить метаданные о захваченной фотографии. Эти данные можно передать в BitmapEncoder , чтобы сохранить метаданные в файл. Ранее не было способа получить доступ к этим данным для несжатых форматов изображений. Вы также можете получить свойство ControlValues, чтобы получить объект CapturedFrameControlValues, описывающий значения элемента управления, такие как экспозиция и баланс белого цвета для захваченного кадра.

Сведения об использовании BitmapEncoder и работе с объектом SoftwareBitmap, включая отображение одного на странице XAML, см. в статье "Создание, изменение и сохранение растровых изображений".

Дополнительные сведения о настройке значений элементов управления устройством записи см. в разделе "Запись элементов управления устройствами" для фотографий и видео.

Начиная с Windows 10 версии 1803, можно получить метаданные, такие как сведения EXIF, для фотографий, захваченных в несжатом формате, путем доступа к свойству BitmapProperties объекта CapturedFrame, возвращаемого MediaCapture. В предыдущих выпусках эти данные были доступны только в заголовке фотографий, захваченных в сжатый формат файла. Эти данные можно предоставить BitmapEncoder при написании файла изображения вручную. Дополнительные сведения о кодировке растровых изображений см. в разделе "Создание, изменение и сохранение растровых изображений". Вы также можете получить доступ к значениям элемента управления кадром, таким как экспозиция и параметры флэш-памяти, используемые при захвате изображения путем доступа к свойству ControlValues . Дополнительные сведения см. в разделе "Захват элементов управления устройствами" для фото и видеозахвата.

Запись фотографии в файл

Обычное приложение для фотографии сохранит записанную фотографию на диск или в облачное хранилище и потребуется добавить метаданные, такие как ориентация фотографии, в файл. В следующем примере показано, как записать фотографию в файл. Вы по-прежнему можете создать SoftwareBitmap из файла образа позже.

Метод, показанный в этом примере, записывает фотографию в поток в памяти, а затем перекодирует фотографию из потока в файл на диске. В этом примере используется GetLibraryAsync для получения библиотеки изображений пользователя, а затем свойства SaveFolder для получения папки сохранения по умолчанию ссылки. Не забудьте добавить возможность библиотеки изображений в манифест приложения для доступа к этой папке. CreateFileAsync создает новый служба хранилища File, в который будет сохранена фотография.

Создайте InMemoryRandomAccessStream, а затем вызовите CapturePhotoToStreamAsync, чтобы записать фотографию в поток, передавая поток и объект ImageEncodingProperties, указывающий формат изображения, который следует использовать. Настраиваемые свойства кодирования можно создавать самостоятельно, но класс предоставляет статические методы, такие как ImageEncodingProperties.CreateJpeg для распространенных форматов кодирования. Затем создайте поток файлов в выходной файл, вызвав OpenAsync. Создайте BitmapDecoder, чтобы декодировать изображение из потока памяти, а затем создать BitmapEncoder для кодирования изображения в файл путем вызова CreateForTranscodingAsync.

При необходимости можно создать объект BitmapPropertySet, а затем вызвать SetPropertiesAsync в кодировщике изображений, чтобы включить метаданные о фотографии в файл изображения. Дополнительные сведения о свойствах кодирования см. в разделе метаданных изображения. Правильная обработка ориентации устройства необходима для большинства приложений фотографии. Дополнительные сведения см. в разделе "Обработка ориентации устройства с помощью MediaCapture".

Наконец, вызовите FlushAsync в объекте кодировщика, чтобы перекодировать фотографию из потока в памяти в файл.

var myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);
StorageFile file = await myPictures.SaveFolder.CreateFileAsync("photo.jpg", CreationCollisionOption.GenerateUniqueName);

using (var captureStream = new InMemoryRandomAccessStream())
{
    await mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), captureStream);

    using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
        var decoder = await BitmapDecoder.CreateAsync(captureStream);
        var encoder = await BitmapEncoder.CreateForTranscodingAsync(fileStream, decoder);

        var properties = new BitmapPropertySet {
            { "System.Photo.Orientation", new BitmapTypedValue(PhotoOrientation.Normal, PropertyType.UInt16) }
        };
        await encoder.BitmapProperties.SetPropertiesAsync(properties);

        await encoder.FlushAsync();
    }
}

Дополнительные сведения о работе с файлами и папками см. в разделе "Файлы", "Папки" и "Библиотеки".

Запись видео

Быстрое добавление видеозахвата в приложение с помощью класса LowLagMediaRecording . Сначала объявите переменную класса для объекта.

LowLagMediaRecording _mediaRecording;

Затем создайте объект служба хранилища File, в который будет сохранено видео. Обратите внимание, что для сохранения в видеотеку пользователя, как показано в этом примере, необходимо добавить в манифест приложения возможность библиотеки видео. Вызовите PrepareLowLagRecordTo служба хранилища FileAsync, чтобы инициализировать запись мультимедиа, передавая файл хранилища и объект MediaEncodingProfile, указывающий кодировку для видео. Класс предоставляет статические методы, такие как CreateMp4, для создания общих профилей кодирования видео.

Наконец, вызовите StartAsync , чтобы начать запись видео.

var myVideos = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Videos);
StorageFile file = await myVideos.SaveFolder.CreateFileAsync("video.mp4", CreationCollisionOption.GenerateUniqueName);
_mediaRecording = await mediaCapture.PrepareLowLagRecordToStorageFileAsync(
        MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto), file);
await _mediaRecording.StartAsync();

Чтобы остановить запись видео, вызовите StopAsync.

await _mediaRecording.StopAsync();

Вы можете продолжать вызывать StartAsync и StopAsync для записи дополнительных видео. Когда вы завершите запись видео, вызовите FinishAsync , чтобы удалить сеанс записи и очистить связанные ресурсы. После этого вызова необходимо снова вызвать PrepareLowLagRecordTo служба хранилища FileAsync, чтобы повторно инициализировать сеанс захвата перед вызовом StartAsync.

await _mediaRecording.FinishAsync();

При записи видео следует зарегистрировать обработчик события RecordLimitationExceed объекта MediaCapture, который будет вызываться операционной системой, если вы превысите ограничение для одной записи, в настоящее время три часа. В обработчике события необходимо завершить запись, вызвав StopAsync.

mediaCapture.RecordLimitationExceeded += MediaCapture_RecordLimitationExceeded;
private async void MediaCapture_RecordLimitationExceeded(MediaCapture sender)
{
    await _mediaRecording.StopAsync();
    System.Diagnostics.Debug.WriteLine("Record limitation exceeded.");
}

Воспроизведение и изменение захваченных видеофайлов

После записи видео в файл может потребоваться загрузить файл и воспроизвести его в пользовательском интерфейсе приложения. Это можно сделать с помощью элемента управления MediaPlayerElement XAML и связанного mediaPlayer. Сведения о воспроизведении мультимедиа на странице XAML см. в разделе "Воспроизведение звука и видео" с помощью MediaPlayer.

Вы также можете создать объект MediaClip из видеофайла, вызвав CreateFromFileAsync. MediaComposition предоставляет основные функции редактирования видео, такие как упорядочение последовательности объектов MediaClip, обрезка длины видео, создание слоев, добавление фоновой музыки и применение эффектов видео. Дополнительные сведения о работе с композициями мультимедиа см. в разделе "Композиции мультимедиа" и редактирование.

Приостановка и возобновление записи видео

Вы можете приостановить запись видео, а затем возобновить запись без создания отдельного выходного файла путем вызова PauseAsync и вызова ResumeAsync.

await _mediaRecording.PauseAsync(Windows.Media.Devices.MediaCapturePauseBehavior.ReleaseHardwareResources);
await _mediaRecording.ResumeAsync();

Начиная с Windows 10 версии 1607, вы можете приостановить запись видео и получить последний кадр, захваченный до приостановки записи. Затем вы можете наложить этот кадр на предварительную версию камеры, чтобы разрешить пользователю выровнять камеру с приостановленным кадром перед возобновлением записи. Вызов PauseWithResultAsync возвращает объект MediaCapturePauseResult. Свойство LastFrame — это объект VideoFrame, представляющий последний кадр. Чтобы отобразить кадр в XAML, получите представление SoftwareBitmap видеокадры. В настоящее время поддерживаются только изображения в формате BGRA8 с предварительно заданным или пустым альфа-каналом, поэтому при необходимости вызовите преобразование, чтобы получить правильный формат. Создайте объект SoftwareBitmapSource и вызовите SetBitmapAsync , чтобы инициализировать его. Наконец, задайте свойство Source элемента управления image XAML для отображения изображения. Чтобы этот трюк работал, изображение должно быть выровнено с элементом управления CaptureElement и должно иметь значение непрозрачности меньше одного. Не забывайте, что вы можете изменять пользовательский интерфейс только в потоке пользовательского интерфейса, поэтому выполните этот вызов внутри RunAsync.

PauseWithResultAsync также возвращает длительность видео, записанного в предварительном сегменте, если необходимо отслеживать общее время записи.

MediaCapturePauseResult result = 
    await _mediaRecording.PauseWithResultAsync(Windows.Media.Devices.MediaCapturePauseBehavior.RetainHardwareResources);

var pausedFrame = result.LastFrame.SoftwareBitmap;
if(pausedFrame.BitmapPixelFormat != BitmapPixelFormat.Bgra8 || pausedFrame.BitmapAlphaMode != BitmapAlphaMode.Ignore)
{
    pausedFrame = SoftwareBitmap.Convert(pausedFrame, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore);
}

var source = new SoftwareBitmapSource();
await source.SetBitmapAsync(pausedFrame);

await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    PauseImage.Source = source;
    PauseImage.Visibility = Visibility.Visible;
});

_totalRecordedTime += result.RecordDuration;

При возобновлении записи можно задать для источника изображения значение NULL и скрыть его.

await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    PauseImage.Source = null;
    PauseImage.Visibility = Visibility.Collapsed;
});

await _mediaRecording.ResumeAsync();

Обратите внимание, что вы также можете получить кадр результатов при остановке видео, вызвав StopWithResultAsync.

Запись звука

Вы можете быстро добавить звукозапись в приложение с помощью того же метода, который показан выше для записи видео. В приведенном ниже примере создается файл служба хранилища File в папке данных приложения. Вызовите PrepareLowLagRecordTo служба хранилища FileAsync, чтобы инициализировать сеанс записи, передавая файл и MediaEncodingProfile, созданный в этом примере статическим методом CreateMp3. Чтобы начать запись, вызовите StartAsync.

mediaCapture.RecordLimitationExceeded += MediaCapture_RecordLimitationExceeded;

var localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile file = await localFolder.CreateFileAsync("audio.mp3", CreationCollisionOption.GenerateUniqueName);
_mediaRecording = await mediaCapture.PrepareLowLagRecordToStorageFileAsync(
        MediaEncodingProfile.CreateMp3(AudioEncodingQuality.High), file);
await _mediaRecording.StartAsync();

Вызов StopAsync , чтобы остановить запись звука.

await _mediaRecording.StopAsync();

Вы можете вызывать StartAsync и StopAsync несколько раз для записи нескольких звуковых файлов. Когда вы завершите запись звука, вызовите FinishAsync , чтобы удалить сеанс записи и очистить связанные ресурсы. После этого вызова необходимо снова вызвать PrepareLowLagRecordTo служба хранилища FileAsync, чтобы повторно инициализировать сеанс захвата перед вызовом StartAsync.

await _mediaRecording.FinishAsync();

Обнаружение и реагирование на изменения уровня звука системой

Начиная с Windows 10 версии 1803, ваше приложение может определить, когда система снижает или отключает уровень звука аудиозаписи приложения и потоков отрисовки звука. Например, система может отключить потоки приложения при переходе в фоновом режиме. Класс AudioStateMonitor позволяет зарегистрировать событие, когда система изменяет громкость звукового потока. Получите экземпляр AudioStateMonitor для мониторинга потоков аудиозахвата путем вызова CreateForCaptureMonitoring. Получите экземпляр для мониторинга потоков отрисовки звука, вызвав CreateForRenderMonitoring. Зарегистрируйте обработчик события SoundLevelChanged каждого монитора, чтобы получать уведомления при изменении звука для соответствующей категории потока системой.

// Namespaces for monitoring audio state
using Windows.Media;
using Windows.Media.Audio;
AudioStateMonitor captureAudioStateMonitor;
AudioStateMonitor renderAudioStateMonitor;
captureAudioStateMonitor = AudioStateMonitor.CreateForCaptureMonitoring();
captureAudioStateMonitor.SoundLevelChanged += CaptureAudioStateMonitor_SoundLevelChanged; ;

renderAudioStateMonitor = AudioStateMonitor.CreateForRenderMonitoring();
renderAudioStateMonitor.SoundLevelChanged += RenderAudioStateMonitor_SoundLevelChanged; ;

В обработчике SoundLevelChanged для потока записи можно проверка свойство SoundLevel отправителя AudioStateMonitor, чтобы определить новый уровень звука. Обратите внимание, что поток записи никогда не должен быть понижен или "утка" системой. Он должен быть отключен или переключен на полный том. Если аудиопоток отключен, можно остановить запись. Если аудиопоток восстанавливается до полного тома, вы можете снова начать запись. В следующем примере используются некоторые логические переменные класса для отслеживания того, записывается ли приложение в настоящее время звук и если запись была остановлена из-за изменения состояния звука. Эти переменные используются для определения того, когда оно подходит для программной остановки или запуска аудиозахвата.

bool isCapturingAudio = false;
bool capturingStoppedForAudioState = false;
private void CaptureAudioStateMonitor_SoundLevelChanged(AudioStateMonitor sender, object args)
{
    switch (sender.SoundLevel)
    {
        case SoundLevel.Full:
            if(capturingStoppedForAudioState)
            {
                StartAudioCapture();
                capturingStoppedForAudioState = false;
            }  
            break;
        case SoundLevel.Muted:
            if(isCapturingAudio)
            {
                StopAudioCapture();
                capturingStoppedForAudioState = true;
            }
            break;
        case SoundLevel.Low:
            // This should never happen for capture
            Debug.WriteLine("Unexpected audio state.");
            break;
    }
}

В следующем примере кода показана реализация обработчика SoundLevelChanged для отрисовки звука. В зависимости от сценария приложения и типа воспроизводимого содержимого может потребоваться приостановить воспроизведение звука, когда уровень звука удобен. Дополнительные сведения об обработке изменений уровня звука для воспроизведения мультимедиа см. в разделе "Воспроизведение звука и видео" с помощью MediaPlayer.

private void RenderAudioStateMonitor_SoundLevelChanged(AudioStateMonitor sender, object args)
{
    if ((sender.SoundLevel == SoundLevel.Full) ||
  (sender.SoundLevel == SoundLevel.Low && !isPodcast))
    {
        mediaPlayer.Play();
    }
    else if ((sender.SoundLevel == SoundLevel.Muted) ||
         (sender.SoundLevel == SoundLevel.Low && isPodcast))
    {
        // Pause playback if we’re muted or if we’re playing a podcast and are ducked
        mediaPlayer.Pause();
    }
}