Pengambilan foto, video, dan audio dasar dengan MediaCapture

Artikel ini menunjukkan cara paling sederhana untuk mengambil foto dan video menggunakan kelas MediaCapture. Kelas MediaCapture mengekspos sekumpulan API yang kuat yang memberikan kontrol tingkat rendah atas alur tangkapan dan mengaktifkan skenario penangkapan tingkat lanjut, tetapi artikel ini dimaksudkan untuk membantu Anda menambahkan tangkapan media dasar ke aplikasi Anda dengan cepat dan mudah. Untuk mempelajari selengkapnya tentang fitur yang disediakan MediaCapture, lihat Kamera.

Jika Anda hanya ingin mengambil foto atau video dan tidak berniat untuk menambahkan fitur pengambilan media tambahan, atau jika Anda tidak ingin membuat UI kamera Anda sendiri, Anda mungkin ingin menggunakan kelas Kamera CaptureUI, yang memungkinkan Anda untuk cukup meluncurkan aplikasi kamera bawaan Windows dan menerima file foto atau video yang diambil. Untuk informasi selengkapnya, lihat Mengambil foto dan video dengan UI kamera bawaan Windows

Kode dalam artikel ini diadaptasi dari sampel kit pemula Kamera. Anda dapat mengunduh sampel untuk melihat kode yang digunakan dalam konteks atau untuk menggunakan sampel sebagai titik awal untuk aplikasi Anda sendiri.

Menambahkan deklarasi kemampuan ke manifes aplikasi

Agar aplikasi Anda dapat mengakses kamera perangkat, Anda harus menyatakan bahwa aplikasi Anda menggunakan kemampuan webcam dan perangkat mikrofon . Jika Anda ingin menyimpan foto dan video yang diambil ke pustaka Gambar atau Video pengguna, Anda juga harus mendeklarasikan kemampuan picturesLibrary dan videosLibrary .

Untuk menambahkan kemampuan ke manifes aplikasi

  1. Di Microsoft Visual Studio, di Penjelajah Solusi, buka perancang untuk manifes aplikasi dengan mengklik dua kali item package.appxmanifest.
  2. Pilih tab Kemampuan.
  3. Centang kotak untuk Webcam dan kotak untuk Mikrofon.
  4. Untuk akses ke pustaka Gambar dan Video centang kotak untuk Pustaka Gambar dan kotak untuk Pustaka Video.

Menginisialisasi objek MediaCapture

Semua metode pengambilan yang dijelaskan dalam artikel ini memerlukan langkah pertama untuk menginisialisasi objek MediaCapture dengan memanggil konstruktor lalu memanggil InitializeAsync. Karena objek MediaCapture akan diakses dari beberapa tempat di aplikasi Anda, deklarasikan variabel kelas untuk menahan objek. Terapkan handler untuk peristiwa Gagal objek MediaCapture untuk diberi tahu jika operasi penangkapan gagal.

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

Menyiapkan pratinjau kamera

Anda dapat mengambil foto, video, dan audio menggunakan MediaCapture tanpa menampilkan pratinjau kamera, tetapi biasanya Anda ingin menampilkan streaming pratinjau sehingga pengguna dapat melihat apa yang diambil. Selain itu, beberapa fitur MediaCapture mengharuskan aliran pratinjau berjalan sebelum dapat diaktifkan, termasuk fokus otomatis, paparan otomatis, dan keseimbangan putih otomatis. Untuk melihat cara menyiapkan pratinjau kamera, lihat Menampilkan pratinjau kamera.

Mengambil foto ke SoftwareBitmap

Kelas SoftwareBitmap diperkenalkan di Windows 10 untuk memberikan representasi umum gambar di beberapa fitur. Jika Anda ingin mengambil foto dan kemudian segera menggunakan gambar yang diambil di aplikasi Anda, seperti menampilkannya di XAML, alih-alih mengambil ke file, maka Anda harus mengambil ke SoftwareBitmap. Anda masih memiliki opsi untuk menyimpan gambar ke disk nanti.

Setelah menginisialisasi objek MediaCapture, Anda dapat mengambil foto ke SoftwareBitmap menggunakan kelas LowLagPhotoCapture. Dapatkan instans kelas ini dengan memanggil PrepareLowLagPhotoCaptureAsync, meneruskan objek ImageEncodingProperties yang menentukan format gambar yang Anda inginkan. CreateUncompressed membuat pengodean yang tidak dikompresi dengan format piksel yang ditentukan. Ambil foto dengan memanggil CaptureAsync, yang mengembalikan objek CapturedPhoto. Dapatkan SoftwareBitmap dengan mengakses properti Bingkai lalu properti SoftwareBitmap.

Jika mau, Anda dapat mengambil beberapa foto dengan berulang kali memanggil CaptureAsync. Setelah selesai menangkap, panggil FinishAsync untuk mematikan sesi LowLagPhotoCapture dan membebaskan sumber daya terkait. Setelah memanggil FinishAsync, untuk mulai mengambil foto lagi, Anda harus memanggil PrepareLowLagPhotoCaptureAsync lagi untuk menginisialisasi ulang sesi pengambilan sebelum memanggil 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();

Dimulai dengan Windows, versi 1803, Anda dapat mengakses properti BitmapProperties dari kelas CapturedFrame yang dikembalikan dari CaptureAsync untuk mengambil metadata tentang foto yang diambil. Anda dapat meneruskan data ini ke bitmapEncoder untuk menyimpan metadata ke file. Sebelumnya, tidak ada cara untuk mengakses data ini untuk format gambar yang tidak dikompresi. Anda juga dapat mengakses properti ControlValues untuk mengambil objek CapturedFrameControlValues yang menjelaskan nilai kontrol, seperti pencahayaan dan keseimbangan putih, untuk bingkai yang diambil.

Untuk informasi tentang menggunakan BitmapEncoder dan tentang bekerja dengan objek SoftwareBitmap, termasuk cara menampilkannya di halaman XAML, lihat Membuat, mengedit, dan menyimpan gambar bitmap.

Untuk informasi selengkapnya tentang mengatur nilai kontrol perangkat pengambilan, lihat Mengambil kontrol perangkat untuk foto dan video.

Dimulai dengan Windows 10, versi 1803, Anda bisa mendapatkan metadata, seperti informasi EXIF, untuk foto yang diambil dalam format yang tidak dikompresi dengan mengakses properti BitmapProperties dari CapturedFrame yang dikembalikan oleh MediaCapture. Dalam rilis sebelumnya, data ini hanya dapat diakses di header foto yang diambil ke format file terkompresi. Anda dapat memberikan data ini ke BitmapEncoder saat menulis file gambar secara manual. Untuk informasi selengkapnya tentang mengodekan bitmap, lihat Membuat, mengedit, dan menyimpan gambar bitmap. Anda juga dapat mengakses nilai kontrol bingkai, seperti pengaturan pencahayaan dan lampu kilat, yang digunakan saat gambar diambil dengan mengakses properti ControlValues. Untuk informasi selengkapnya, lihat Mengambil kontrol perangkat untuk pengambilan foto dan video.

Mengambil foto ke file

Aplikasi fotografi umum akan menyimpan foto yang diambil ke disk atau ke penyimpanan cloud dan perlu menambahkan metadata, seperti orientasi foto, ke file. Contoh berikut menunjukkan cara mengambil foto ke file. Anda masih memiliki opsi untuk membuat SoftwareBitmap dari file gambar nanti.

Teknik yang ditunjukkan dalam contoh ini mengambil foto ke aliran dalam memori dan kemudian mentranskode foto dari aliran ke file di disk. Contoh ini menggunakan GetLibraryAsync untuk mendapatkan pustaka gambar pengguna lalu properti SaveFolder untuk mendapatkan folder penyimpanan default referensi. Ingatlah untuk menambahkan kemampuan Pustaka Gambar ke manifes aplikasi Anda untuk mengakses folder ini. CreateFileAsync membuat StorageFile baru tempat foto akan disimpan.

Buat InMemoryRandomAccessStream lalu panggil CapturePhotoToStreamAsync untuk mengambil foto ke aliran, melewati aliran dan objek ImageEncodingProperties yang menentukan format gambar yang harus digunakan. Anda dapat membuat properti pengodean kustom dengan menginisialisasi objek sendiri, tetapi kelas menyediakan metode statis, seperti ImageEncodingProperties.CreateJpeg untuk format pengodean umum. Selanjutnya, buat aliran file ke file output dengan memanggil OpenAsync. Buat BitmapDecoder untuk mendekode gambar dari aliran memori lalu buat BitmapEncoder untuk mengodekan gambar ke file dengan memanggil CreateForTranscodingAsync.

Anda dapat secara opsional membuat objek BitmapPropertySet lalu memanggil SetPropertiesAsync pada encoder gambar untuk menyertakan metadata tentang foto dalam file gambar. Untuk informasi selengkapnya tentang properti pengodean, lihat Metadata gambar. Menangani orientasi perangkat dengan benar sangat penting untuk sebagian besar aplikasi fotografi. Untuk informasi selengkapnya, lihat Menangani orientasi perangkat dengan MediaCapture.

Terakhir, panggil FlushAsync pada objek encoder untuk mentranskode foto dari aliran dalam memori ke file.

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();
    }
}

Untuk informasi selengkapnya tentang bekerja dengan file dan folder, lihat File, folder, dan pustaka.

Mengambil video

Tambahkan pengambilan video dengan cepat ke aplikasi Anda dengan menggunakan kelas LowLagMediaRecording. Pertama, deklarasikan variabel kelas ke untuk objek .

LowLagMediaRecording _mediaRecording;

Selanjutnya, buat objek StorageFile tempat video akan disimpan. Perhatikan bahwa untuk menyimpan ke pustaka video pengguna, seperti yang ditunjukkan dalam contoh ini, Anda harus menambahkan kemampuan Pustaka Video ke manifes aplikasi Anda. Panggil PrepareLowLagRecordToStorageFileAsync untuk menginisialisasi perekaman media, meneruskan file penyimpanan dan objek MediaEncodingProfile yang menentukan pengodean untuk video. Kelas ini menyediakan metode statis, seperti CreateMp4, untuk membuat profil pengodean video umum.

Terakhir, panggil StartAsync untuk mulai mengambil video.

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();

Untuk berhenti merekam video, panggil StopAsync.

await _mediaRecording.StopAsync();

Anda dapat terus memanggil StartAsync dan StopAsync untuk mengambil video tambahan. Setelah selesai mengambil video, panggil FinishAsync untuk membuang sesi pengambilan dan bersihkan sumber daya terkait. Setelah panggilan ini, Anda harus memanggil PrepareLowLagRecordToStorageFileAsync lagi untuk menginisialisasi ulang sesi pengambilan sebelum memanggil StartAsync.

await _mediaRecording.FinishAsync();

Saat mengambil video, Anda harus mendaftarkan handler untuk peristiwa RecordLimitationExceeded dari objek MediaCapture , yang akan dinaikkan oleh sistem operasi jika Anda melampaui batas untuk satu perekaman, saat ini tiga jam. Di handler untuk peristiwa, Anda harus menyelesaikan rekaman Anda dengan memanggil StopAsync.

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

Memutar dan mengedit file video yang diambil

Setelah mengambil video ke file, Anda mungkin ingin memuat file dan memutarnya kembali dalam UI aplikasi Anda. Anda dapat melakukan ini menggunakan kontrol MediaPlayerElement XAML dan MediaPlayer terkait. Untuk informasi tentang memutar media di halaman XAML, lihat Memutar audio dan video dengan MediaPlayer.

Anda juga dapat membuat objek MediaClip dari file video dengan memanggil CreateFromFileAsync. MediaComposition menyediakan fungsionalitas pengeditan video dasar seperti mengatur urutan objek MediaClip, memangkas panjang video, membuat lapisan, menambahkan musik latar belakang, dan menerapkan efek video. Untuk informasi selengkapnya tentang bekerja dengan komposisi media, lihat Komposisi dan pengeditan media.

Menjeda dan melanjutkan perekaman video

Anda dapat menjeda perekaman video lalu melanjutkan perekaman tanpa membuat file output terpisah dengan memanggil PauseAsync lalu memanggil ResumeAsync.

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

Dimulai dengan Windows 10, versi 1607, Anda dapat menjeda perekaman video dan menerima bingkai terakhir yang diambil sebelum perekaman dijeda. Anda kemudian dapat melapisi bingkai ini pada pratinjau kamera untuk memungkinkan pengguna menyelaraskan kamera dengan bingkai yang dijeda sebelum meneruskan perekaman. Memanggil PauseWithResultAsync mengembalikan objek MediaCapturePauseResult. Properti LastFrame adalah objek VideoFrame yang mewakili bingkai terakhir. Untuk menampilkan bingkai di XAML, dapatkan representasi SoftwareBitmap dari bingkai video. Saat ini, hanya gambar dalam format BGRA8 dengan saluran alfa yang telah diisi sebelumnya atau kosong yang didukung, jadi panggil Konversi jika perlu untuk mendapatkan format yang benar. Buat objek SoftwareBitmapSource baru dan panggil SetBitmapAsync untuk menginisialisasinya. Terakhir, atur properti Sumber dari kontrol Gambar XAML untuk menampilkan gambar. Agar trik ini berfungsi, gambar Anda harus selaras dengan kontrol CaptureElement dan harus memiliki nilai opasitas kurang dari satu. Jangan lupa bahwa Anda hanya dapat memodifikasi UI pada utas UI, jadi lakukan panggilan ini di dalam RunAsync.

PauseWithResultAsync juga mengembalikan durasi video yang direkam di segmen sebelumnya jika Anda perlu melacak berapa banyak total waktu yang telah direkam.

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;

Saat melanjutkan perekaman, Anda dapat mengatur sumber gambar ke null dan menyembunyikannya.

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

await _mediaRecording.ResumeAsync();

Perhatikan bahwa Anda juga bisa mendapatkan bingkai hasil saat menghentikan video dengan memanggil StopWithResultAsync.

Mengambil audio

Anda dapat dengan cepat menambahkan pengambilan audio ke aplikasi Anda dengan menggunakan teknik yang sama yang ditunjukkan di atas untuk menangkap video. Contoh di bawah ini membuat StorageFile di folder data aplikasi. Panggil PrepareLowLagRecordToStorageFileAsync untuk menginisialisasi sesi pengambilan, meneruskan file dan MediaEncodingProfile yang dihasilkan dalam contoh ini dengan metode statis CreateMp3. Untuk mulai merekam, panggil 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();

Panggil StopAsync untuk menghentikan perekaman audio.

await _mediaRecording.StopAsync();

Anda dapat memanggil StartAsync dan StopAsync beberapa kali untuk merekam beberapa file audio. Setelah selesai mengambil audio, panggil FinishAsync untuk membuang sesi pengambilan dan bersihkan sumber daya terkait. Setelah panggilan ini, Anda harus memanggil PrepareLowLagRecordToStorageFileAsync lagi untuk menginisialisasi ulang sesi pengambilan sebelum memanggil StartAsync.

await _mediaRecording.FinishAsync();

Mendeteksi dan merespons perubahan tingkat audio oleh sistem

Dimulai dengan Windows 10, versi 1803, aplikasi Anda dapat mendeteksi kapan sistem menurunkan atau mematikan suara tingkat audio tangkapan audio dan aliran render audio aplikasi Anda. Misalnya, sistem dapat membisukan streaming aplikasi Anda saat masuk ke latar belakang. Kelas AudioStateMonitor memungkinkan Anda mendaftar untuk menerima peristiwa ketika sistem memodifikasi volume aliran audio. Dapatkan instans AudioStateMonitor untuk memantau aliran pengambilan audio dengan memanggil CreateForCaptureMonitoring. Dapatkan instans untuk memantau aliran render audio dengan memanggil CreateForRenderMonitoring. Daftarkan handler untuk peristiwa SoundLevelChanged dari setiap monitor yang akan diberi tahu ketika audio untuk kategori aliran yang sesuai diubah oleh sistem.

// 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; ;

Di handler SoundLevelChanged untuk aliran pengambilan, Anda dapat memeriksa properti SoundLevel pengirim AudioStateMonitor untuk menentukan tingkat suara baru. Perhatikan bahwa aliran pengambilan tidak boleh diturunkan, atau "di-duck", oleh sistem. Ini hanya boleh dibisukan atau dialihkan kembali ke volume penuh. Jika aliran audio dibisukan, Anda dapat menghentikan pengambilan yang sedang berlangsung. Jika aliran audio dipulihkan ke volume penuh, Anda dapat mulai mengambil lagi. Contoh berikut menggunakan beberapa variabel kelas boolean untuk melacak apakah aplikasi saat ini menangkap audio dan apakah pengambilan dihentikan karena perubahan status audio. Variabel ini digunakan untuk menentukan kapan tepat untuk menghentikan atau memulai pengambilan audio secara terprogram.

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;
    }
}

Contoh kode berikut mengilustrasikan implementasi handler SoundLevelChanged untuk penyajian audio. Bergantung pada skenario aplikasi Anda, dan jenis konten yang Anda putar, Anda mungkin ingin menjeda pemutaran audio saat tingkat suara dibekukan. Untuk informasi selengkapnya tentang menangani perubahan tingkat suara untuk pemutaran media, lihat Memutar audio dan video dengan 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();
    }
}