Condividi tramite


Acquisizione di foto, video e audio di base con MediaCapture

Questo articolo illustra il modo più semplice per acquisire foto e video usando la classe MediaCapture. La classe MediaCapture espone un set affidabile di API che forniscono un controllo di basso livello sulla pipeline di acquisizione e abilitano scenari di acquisizione avanzati, ma questo articolo consente di aggiungere l'acquisizione multimediale di base all'app in modo rapido e semplice. Per altre informazioni sulle funzionalità offerte da MediaCapture, vedere Fotocamera.

Se si vuole semplicemente acquisire una foto o un video e non intendi aggiungere funzionalità di acquisizione multimediale aggiuntive o se non si vuole creare un'interfaccia utente della fotocamera personalizzata, si potrebbe voler usare la classe CameraCaptureUI, che consente di avviare semplicemente l'app fotocamera predefinita di Windows e ricevere la foto o il file video acquisito. Per ulteriori informazioni, vedere Acquisire foto e video con l'interfaccia utente della fotocamera incorporata di Windows

Il codice in questo articolo è stato adattato dall'esempio di starter kit Fotocamera. È possibile scaricare questo esempio per visualizzare il codice usato nel contesto o per usare gli esempi come punto di partenza per la propria app.

Aggiungere dichiarazioni di funzionalità al manifesto dell'app

Per consentire all'app di accedere alla fotocamera di un dispositivo, bisogna dichiarare che l'app usa le funzionalità del dispositivo webcam e microfono. Se si vogliono salvare foto e video acquisiti nella raccolta immagini o video degli utenti, devi anche dichiarare le funzionalità picturesLibrary e videosLibrary.

Per aggiungere funzionalità al manifesto dell'app

  1. In Esplora soluzioni in Microsoft Visual Studio aprire la finestra di progettazione per il manifesto dell'applicazione facendo doppio clic sull'elemento package.appxmanifest.
  2. Fare clic sulla scheda Funzionalità.
  3. Selezionare la casella Webcam e la casella microfono.
  4. Per accedere alla raccolta immagini e video, selezionare le caselle Pictures Library e la casella Videos Library.

Inizializzare l'oggetto MediaCapture

Tutti i metodi di acquisizione descritti in questo articolo richiedono il primo passaggio per inizializzare l'oggetto MediaCapture chiamando il costruttore e quindi chiamando InitializeAsync. Poiché l'oggetto MediaCapture sarà accessibile da più posizioni nell'app, dichiarare una variabile di classe per contenere l'oggetto. Implementare un gestore per l'evento Failed dell'oggetto MediaCapture per ricevere una notifica in caso di errore di un'operazione di acquisizione.

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

Nota

Windows consente agli utenti di concedere o negare l'accesso alla fotocamera del dispositivo nell'app Impostazioni di Windows, in Privacy e sicurezza -> Fotocamera. Quando si inizializza il dispositivo di acquisizione, le app devono verificare se hanno accesso alla fotocamera e gestiscono il caso in cui l'accesso viene negato dall'utente. Per altre informazioni, vedere Gestire l'impostazione della privacy della fotocamera di Windows.

Configurare l'anteprima della fotocamera

È possibile acquisire foto, video e audio usando MediaCapture senza visualizzare l'anteprima della fotocamera, ma in genere si vuole mostrare il flusso di anteprima in modo che l'utente possa vedere cosa viene acquisito. Inoltre, alcune funzionalità di MediaCapture richiedono che il flusso di anteprima sia in esecuzione prima che possano essere abilitate, tra cui lo stato attivo automatico, l'esposizione automatica e il bilanciamento del bianco automatico. Per informazioni su come configurare l'anteprima della fotocamera, vedere Visualizzare l'anteprima della fotocamera.

Acquisire una foto in un SoftwareBitmap

La classe SoftwareBitmap è stata introdotta in Windows 10 per fornire una rappresentazione comune delle immagini tra più funzionalità. Se si vuole acquisire una foto e quindi usare immediatamente l'immagine acquisita nell'app, ad esempio la visualizzazione in XAML, anziché l'acquisizione in un file, si deve acquisire in un SoftwareBitmap. È comunque possibile salvare l'immagine su disco in un secondo momento.

Dopo aver inizializzato l'oggetto MediaCapture, si può acquisire una foto in un SoftwareBitmap usando la classe LowLagPhotoCapture. Ottenere un'istanza di questa classe chiamando PrepareLowLagPhotoCaptureAsync, passando un oggetto ImageEncodingProperties che specifica il formato di immagine desiderato. CreateUncompressed crea una codifica non compressa con il formato pixel specificato. CAcquisire una foto chiamando CaptureAsync, che restituisce un oggetto CapturedPhoto. Ottenere un SoftwareBitmap accedendo alla proprietà Frame e quindi alla proprietà SoftwareBitmap.

Se vuoi, puoi acquisire più foto chiamando ripetutamente CaptureAsync. Al termine dell'acquisizione, chiamare FinishAsync per arrestare la sessione LowLagPhotoCapture e liberare le risorse associate. Dopo aver chiamato FinishAsync, per iniziare a acquisire nuovamente le foto, dovrai chiamare di nuovo PrepareLowLagPhotoCaptureAsync per reinizializzare la sessione di acquisizione prima di chiamare 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();

A partire da Windows, versione 1803, è possibile accedere alla proprietà BitmapProperties della classe CapturedFrame restituita da CaptureAsync per recuperare i metadati relativi alla foto acquisita. È possibile passare questi dati a un BitmapEncoder per salvare i metadati in un file. In precedenza non era possibile accedere a questi dati per i formati di immagine non compressi. È anche possibile accedere alla proprietà ControlValues per recuperare un CapturedFrameControlValues che descrive i valori del controllo, ad esempio l'esposizione e il bilanciamento del bianco, per il frame acquisito.

Per informazioni sull'uso di BitmapEncoder e sull'uso dell'oggetto SoftwareBitmap incluso come visualizzarne uno in una pagina XAML, vedere Creare, modificare e salvare immagini.

Per altre informazioni sull'impostazione dei valori di controllo del dispositivo di acquisizione, vedere Acquisire i controlli del dispositivo per foto e video.

A partire da Windows 10, versione 1803, puoi ottenere i metadati, ad esempio le informazioni EXIF, per le foto acquisite in formato non compresso accedendo alla proprietà BitmapProperties di CapturedFrame restituito da MediaCapture. Nelle versioni precedenti questi dati erano accessibili solo nell'intestazione delle foto acquisite in un formato di file compresso. È possibile fornire questi dati a un BitmapEncoder durante la scrittura manuale di un file di immagine. Per altre informazioni sulla codifica delle bitmap, vedere Creare, modificare e salvare immagini bitmap. È anche possibile accedere ai valori del controllo frame, ad esempio l'esposizione e le impostazioni flash, usati quando l'immagine è stata acquisita accedendo alla proprietà ControlValues. Per altre informazioni, vedere Acquisire i controlli del dispositivo per l'acquisizione di foto e video.

Acquisire una foto in un file

Un'app di fotografia tipica salverà una foto acquisita su disco o nell'archiviazione cloud e dovrà aggiungere metadati, ad esempio l'orientamento delle foto, al file. L'esempio seguente illustra come acquisire una foto in un file. È comunque possibile creare un SoftwareBitmap dal file immagine in un secondo momento.

La tecnica illustrata in questo esempio acquisisce la foto in un flusso in memoria e quindi esegue la transcodifica della foto dal flusso a un file su disco. Questo esempio usa GetLibraryAsync per ottenere la raccolta immagini dell'utente e quindi la proprietà SaveFolder per ottenere una cartella di salvataggio predefinita di riferimento. Ricordarsi di aggiungere la funzionalità Raccolta immagini al manifesto dell'app per accedere a questa cartella. CreateFileAsync crea un nuovo Archiviazione File in cui verrà salvata la foto.

Creare un InMemoryRandomAccessStream e quindi chiamare CapturePhotoToStreamAsync per acquisire una foto nel flusso, passando il flusso e un oggetto ImageEncodingProperties che specifica il formato di immagine da usare. È possibile creare proprietà di codifica personalizzate inizializzando l'oggetto manualmente, ma la classe fornisce metodi statici, ad esempio ImageEncodingProperties.CreateJpeg per formati di codifica comuni. Creare quindi un flusso di file nel file di output chiamando OpenAsync. Creare un BitmapDecoder per decodificare l'immagine dal flusso in memoria e quindi creare un BitmapEncoder per codificare l'immagine in un file chiamando CreateForTranscodingAsync.

Facoltativamente, è possibile creare un oggetto BitmapPropertySet e quindi chiamare SetPropertiesAsync nel codificatore di immagini per includere i metadati relativi alla foto nel file di immagine. Per altre informazioni sulle proprietà di codifica, vedere Metadati dell'immagine. Gestire correttamente l'orientamento del dispositivo è essenziale per la maggior parte delle app fotografiche. Per altre informazioni, vedere Gestire l'orientamento del dispositivo con MediaCapture.

Infine, chiamare FlushAsync sull'oggetto codificatore per transcodificare la foto dal flusso in memoria al 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();
    }
}

Per altre informazioni sull'uso di file e cartelle, vedere File, cartelle e librerie.

Acquisire un video

Aggiungere rapidamente l'acquisizione video all'app usando la classe LowLagMediaRecording. Prima di tutto, dichiarare una variabile di classe per l'oggetto .

LowLagMediaRecording _mediaRecording;

Creare quindi un oggetto Archiviazione File in cui verrà salvato il video. Si noti che per salvare nella raccolta video dell'utente, come illustrato in questo esempio, è necessario aggiungere la funzionalità Raccolta video al manifesto dell'app. Chiamare PrepareLowLagRecordToStorageFileAsync per inizializzare la registrazione multimediale, passando il file di archiviazione e un oggetto MediaEncodingProfile che specifica la codifica per il video La classe fornisce metodi statici, ad esempio CreateMp4, per la creazione di profili di codifica video comuni.

Infine, chiamare StartAsync per iniziare l'acquisizione del 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();

Per interrompere la registrazione del video, chiamare StopAsync.

await _mediaRecording.StopAsync();

È possibile continuare a chiamare StartAsync e StopAsync per acquisire video aggiuntivi. Al termine dell'acquisizione di video, chiamare FinishAsync per eliminare la sessione di acquisizione e pulire le risorse associate. Dopo questa chiamata, è necessario chiamare di nuovo PrepareLowLagRecordToStorageFileAsync per reinizializzare la sessione di acquisizione prima di chiamare StartAsync.

await _mediaRecording.FinishAsync();

Durante l'acquisizione di video, devi registrare un gestore per l'evento RecordLimitationExceeded dell'oggetto MediaCapture, che verrà generato dal sistema operativo se superi il limite per una singola registrazione, attualmente tre ore. Nel gestore per l'evento è necessario finalizzare la registrazione chiamando StopAsync.

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

Riprodurre e modificare i file video acquisiti

Dopo aver acquisito un video in un file, è possibile caricare il file e riprodurlo nell'interfaccia utente dell'app. Puoi farlo usando il controllo XAML MediaPlayerElement e un MediaPlayer associato. Per informazioni sulla riproduzione di contenuti multimediali in una pagina XAML, vedere Riprodurre audio e video con MediaPlayer.

È anche possibile creare un oggetto MediaClip da un file video chiamando CreateFromFileAsync. MediaComposition offre funzionalità di modifica video di base, ad esempio la disposizione della sequenza di oggetti MediaClip, la creazione di livelli, l'aggiunta di musica di sottofondo e l'applicazione di effetti video. Per altre informazioni sull'uso delle composizioni multimediali, vedere Composizioni multimediali e modifica.

Sospendere e riprendere la registrazione video

È possibile sospendere una registrazione video e quindi riprendere la registrazione senza creare un file di output separato chiamando PauseAsync e quindi chiamando ResumeAsync.

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

A partire da Windows 10, versione 1607, è possibile sospendere una registrazione video e ricevere l'ultimo fotogramma acquisito prima che la registrazione sia stata sospesa. È quindi possibile sovrapporre questo fotogramma all'anteprima della fotocamera per consentire all'utente di allineare la fotocamera con il fotogramma sospeso prima di riprendere la registrazione. La chiamata a PauseWithResultAsync restituisce un oggetto MediaCapturePauseResult. La proprietà LastFrame è un oggetto VideoFrame che rappresenta l'ultimo frame. Per visualizzare il fotogramma in XAML, ottenere la rappresentazione SoftwareBitmap del fotogramma video. Attualmente sono supportate solo immagini in formato BGRA8 con canale alfa premoltiplicato o vuoto, quindi chiamare Convert se necessario per ottenere il formato corretto. Creare un nuovo oggetto SoftwareBitmapSource e chiamare SetBitmapAsync per inizializzarlo. Impostare infine la proprietà Source di un controllo Image XAML per visualizzare l'immagine. Per il funzionamento di questo trucco, l'immagine deve essere allineata al controllo CaptureElement e deve avere un valore di opacità minore di uno. Non dimenticare che è possibile modificare solo l'interfaccia utente nel thread dell'interfaccia utente, quindi effettuare questa chiamata all'interno di RunAsync.

PauseWithResultAsync restituisce anche la durata del video registrato nel segmento precedente nel caso in cui sia necessario tenere traccia del tempo totale registrato.

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;

Quando si riprende la registrazione, è possibile impostare l'origine dell'immagine su null e nasconderla.

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

await _mediaRecording.ResumeAsync();

Si noti che è anche possibile ottenere un frame di risultato quando si arresta il video chiamando StopWithResultAsync.

Acquisire audio

È possibile aggiungere rapidamente l'acquisizione audio all'app usando la stessa tecnica illustrata in precedenza per l'acquisizione di video. L'esempio seguente crea uno StorageFile nella cartella dei dati dell'applicazione. Chiamare PrepareLowLagRecordToStorageFileAsync per inizializzare la sessione di acquisizione, passando il file e un MediaEncodingProfile generato in questo esempio dal metodo statico CreateMp3. Per iniziare la registrazione, chiamare 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();

Chiamare StopAsync per arrestare la registrazione audio.

await _mediaRecording.StopAsync();

Si possono chiamare StartAsync e StopAsync più volte per registrare più file audio. Al termine dell'acquisizione audio, chiamare FinishAsync per eliminare la sessione di acquisizione e pulire le risorse associate. Dopo questa chiamata, è necessario chiamare di nuovo PrepareLowLagRecordToStorageFileAsync per reinizializzare la sessione di acquisizione prima di chiamare StartAsync.

await _mediaRecording.FinishAsync();

Rilevare e rispondere alle modifiche del livello audio dal sistema

A partire da Windows 10, versione 1803, l'app può rilevare quando il sistema abbassa o disattiva il livello audio dei flussi di rendering audio e audio dell'app. Ad esempio, il sistema potrebbe disattivare i flussi dell'app quando entra in background. La classe AudioStateMonitor consente di registrare per ricevere un evento quando il sistema modifica il volume di un flusso audio. Ottenere un'istanza di AudioStateMonitor per il monitoraggio dei audio flussi di acquisizione audio chiamando CreateForCaptureMonitoring. Ottenere un'istanza per il monitoraggio dei flussi di rendering audio chiamando CreateForRenderMonitoring. Registrare un gestore per l'evento SoundLevelChanged di ogni monitor per ricevere una notifica quando l'audio per la categoria di flusso corrispondente viene modificato dal sistema.

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

Nel gestore SoundLevelChanged per il flusso di acquisizione, puoi controllare la proprietà SoundLevel del mittente AudioStateMonitor per determinare il nuovo livello audio. Si noti che un flusso di acquisizione non deve mai essere abbassato o "ducked" dal sistema. Dovrebbe essere disattivato o tornare al volume completo. Se il flusso audio è disattivato, è possibile arrestare un'acquisizione in corso. Se il flusso audio viene ripristinato in un volume completo, è possibile avviare di nuovo l'acquisizione. L'esempio seguente usa alcune variabili di classe booleane per rilevare se l'app sta attualmente acquisendo audio e se l'acquisizione è stata arrestata a causa della modifica dello stato audio. Queste variabili vengono usate per determinare quando è appropriato arrestare o avviare l'acquisizione audio a livello di codice.

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

L'esempio di codice seguente illustra un'implementazione del gestore SoundLevelChanged per il rendering audio. A seconda dello scenario dell'app e del tipo di contenuto che stai riproducendo, potresti voler sospendere la riproduzione audio quando il livello audio è ducked. Per altre informazioni sulla gestione delle modifiche del livello audio per la riproduzione multimediale, vedere Riprodurre audio e video con 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();
    }
}