Windows Phone 7

Usando câmeras no seu aplicativo para Windows Phone

Matt Stroshane

As imagens podem comunicar com eficiência e elegância incomparáveis às das palavras isoladas. Você já ouviu que "uma imagem vale por mil palavras"; imagine os tipos de problemas que poderiam ser solucionados se o seu aplicativo para Windows Phone tivesse acesso direto a uma câmera. Bem, começando pelo Windows Phone 7.5, você pode solucionar esses problemas de “mil palavras” usando câmeras integradas ao dispositivo.

Nesse artigo, vou apresentar as câmeras frontal e traseiras, as APIs de câmera e os recursos de manifesto associados, além disso, irei discutir sobre os diversos modos de utilização da câmera no seu próximo aplicativo para Windows Phone 7.5. Serão abordados os seguintes tópicos:

  • Captura de fotos: Criarei um aplicativo de fotos muito simples.
  • Acesso ao buffer de visualização da câmera: Vou apresentar a amostra da escala de cinza da câmera.
  • Gravação de vídeo: Examinarei a amostra do gravador de vídeo.

Você precisará do SDK do Windows Phone 7.1 para criar um aplicativo para o Windows Phone 7.5. O SDK inclui exemplos de código que demonstram cada um desses cenários em detalhes. Para obter mais informações, consulte a amostra de câmera básica, a amostra da escala de cinza da câmera e a amostra do gravador de vídeo na página Amostras de código, no SDK em wpdev.ms/officialsamples.

Observe que este artigo não cobrirá a tarefa de captura de câmera, disponível desde o Windows Phone 7. Embora essa tarefa seja uma forma simples de obter fotos para o aplicativo, ela não permite que você capture fotos de maneira programada ou acesse o buffer de visualização da câmera.

O dispositivo Windows Phone 7.5 pode incluir até duas câmeras, designadas de principal e frontal. A câmera principal está situada na parte posterior do dispositivo e normalmente oferece uma resolução mais alta e mais recursos do que a câmera frontal. Nenhuma dessas câmeras é necessária num dispositivo Windows Phone 7.5, então, certifique-se da presença das mesmas no código antes de criar os objetos de câmera. Posteriormente, eu demonstrarei como usar o método IsCameraTypeSupported com essa finalidade.

Muitos dispositivos Windows Phone disponíveis nos Estados Unidos incluem uma câmera principal com um sensor maior de 5MP, foco automático e flash. A câmera frontal é um recurso novo do Windows Phone 7.5.

Para obter informações sobre as especificações do dispositivo, consulte a guia Comprar em windowsphone.com.

Captura de fotos

Você pode usar as mesmas classes para acessar tanto a câmera principal quanto a câmera frontal. Como você terá a oportunidade de ver, selecionar o tipo de câmera é uma questão de definir um único parâmetro no construtor do objeto PhotoCamera. Da perspectiva do desenho, você pode desejar tratar da interação com a câmera frontal de maneira diferente. Por exemplo, você poderá inverter as imagens da câmera frontal para permitir ao usuário tirar uma foto mais natural, "como num espelho".

Na captura de fotos num aplicativo para Windows Phone 7.5, você poderá trabalhar, principalmente, com a classe PhotoCamera do namespace Microsoft.Devices. Essa classe oferece um grande controle sobre as configurações e o comportamento da câmera. Por exemplo, você pode:

  • Ativar o disparador da câmera com o método PhotoCamera.CaptureImage
  • Acionar o foco automático com o método PhotoCamera.Focus
  • Especificar a resolução da imagem configurando a propriedade Photo-Camera.Resolution
  • Definir as configurações de flash configurando a propriedade Photo-Camera.FlashMode
  • Incorporar o botão do disparador do hardware com eventos da classe estática CameraButtons
  • Implementar o foco de toque com o método PhotoCamera.Focus­AtPoint

Neste artigo, demonstrarei apenas o primeiro ponto. Para obter um exemplo que mostre como fazer tudo isso, consulte a Amostra de câmera básica da página de amostras do código do SDK do Windows Phone.

Observe que mesmo quando a câmera estiver disponível, ela não poderá suportar todas essas APIs. As seguintes abordagens podem ajudar a determinar o que está disponível:

  • Câmera: Use o método estático PhotoCamera.IsCameraTypeSupported.
  • Foco automático: Use o método PhotoCamera.IsFocus­­-Supported.
  • Configurações de resolução da imagem: Verifique a coleção Photo­-Camera.AvailableResolutions.
  • Configurações de flash: Use o método PhotoCamera.IsFlashMode­Supported.
  • Foco específico do ponto: Use o método PhotoCamera.IsFocus­AtPointSupported.

Para oferecê-lo uma ideia de como capturar fotos no seu aplicativo, vamos observar um aplicativo simples que captura uma foto quando você toca no visor e, em seguida salva a imagem na pasta Álbum da câmera, no hub Imagens.

Comece com um projeto padrão do Windows Phone, usando o modelo do aplicativo para Windows Phone. Você pode gravar os aplicativos para Windows Phone 7.5 no C# ou Visual Basic. Esse exemplo usará o C#.

Eu simplificarei esse exemplo limitando o aplicativo à orientação somente paisagem e usando apenas a câmera principal. Gerenciar a orientação para o dispositivo e as duas câmeras, cada qual apontada em direções diferentes, pode gerar confusão; por isso recomendo testar com um dispositivo físico para garantir o comportamento desejado. Abordarei a orientação em mais detalhes posteriormente.

Em MainPage.xaml, atualize os atributos PhoneApplicationPage, como a seguir:

SupportedOrientations="Landscape" Orientation="LandscapeLeft"

Em seguida, substitua o conteúdo da grade LayoutRoot por Canvas e TextBlock, conforme mostrado na Figura 1.

Figura 1 Adicionando Canvas e TextBlock

<Canvas x:Name="viewfinderCanvas" Width="640" Height="480" Tap="viewfinder_Tapped">
  <Canvas.Background>
    <VideoBrush x:Name="viewfinderBrush">
      <VideoBrush.RelativeTransform>
        <CompositeTransform
          x:Name="viewfinderTransform"
          CenterX="0.5"
          CenterY="0.5"/>
      </VideoBrush.RelativeTransform>
    </VideoBrush>
  </Canvas.Background>
</Canvas>
<TextBlock Width="626" Height="40"
           HorizontalAlignment="Left"
           Margin="8,428,0,0"
           Name="txtMessage"
           VerticalAlignment="Top"
           FontSize="24"
           FontWeight="ExtraBold"
           Text="Tap the screen to capture a photo."/>

O XAML na Figura 1 usa o VideoBrush no Canvas para exibir o visor e fornecer o TextBlock para a comunicação com o usuário. O sensor da câmera possui uma proporção de 4:3 e a proporção da tela é de 15:9. Se você não especificar o tamanho da tela com a mesma proporção de 4:3 (640x480), a imagem aparecerá esticada na tela.

No elemento Canvas, o atributo Tap especifica o método a ser chamado quando o usuário tocar na tela, método viewfinder_Tapped. Para exibir o fluxo de imagem do buffer de visualização da câmera, um Video­Brush denominado viewfinderBrush será especificado como o plano de fundo da tela. Como o visor de uma câmera SLR (single-lens reflex), o viewfinderBrush permite ver os quadros de visualização da câmera. A transformação no viewfinderBrush simplesmente “fixa” o visor no centro da tela, à medida que esse é girado. Vamos discutir sobre o código por trás desse XAML nas seções a seguir. AFigura 2 exibe a interface do usuário do aplicativo Simple Photo.

The Simple Photo App UI
Figura 2 Interface do usuário do aplicativo Simple Photo

Ao inicializar e liberar a câmera para capturar fotos e salvá-las na pasta Álbum da câmera no hub Imagens, você precisará das classes PhotoCamera e MediaLibrary, respectivamente. Comece adicionando uma referência ao assembly Microsoft.Xna.Framework. Você não precisa conhecer a programação em XNA para esse exemplo; no entanto, você precisará de tipos neste assembly para acessar a biblioteca de mídia.

Na parte superior do arquivo MainPage.xaml.cs, adicione diretivas para a câmera e a biblioteca de mídia:

using Microsoft.Devices;
using Microsoft.Xna.Framework.Media;

Na classe MainPage, adicione as seguintes variáveis de nível de classe:

private int photoCounter = 0;
PhotoCamera cam;
MediaLibrary library = new MediaLibrary();

A câmera pode levar alguns segundos para inicializar. Declarando o objeto PhotoCamera no nível da classe, você poderá criá-lo quando navegar para a página e removê-lo da memória quando navegar para fora da página. Nós usaremos os métodos OnNavigatedTo e OnNavigatingFrom para esse fim.

No método OnNavigatedTo, crie o objeto da câmera, registre os eventos da câmera que serão usados e configure a visualização da câmera como a fonte do visor, viewfinderBrush. Embora sejam comuns, as câmeras são opcionais no Windows Phone 7.5; é importante verificá-las antes de criar o objeto da câmera. Se a câmera principal não estiver disponível, o método gravará uma mensagem para o usuário.

Adicione os métodos exibidos na Figura 3 à classe MainPage.

Figura 3 Métodos OnNavigatedTo e OnNavigatingFrom

protected override void OnNavigatedTo
  (System.Windows.Navigation.NavigationEventArgs e)
{
  if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary) == true)
  {
    cam = new PhotoCamera(CameraType.Primary);
    cam.CaptureImageAvailable +=
      new EventHandler<Microsoft.Devices.ContentReadyEventArgs>
        (cam_CaptureImageAvailable);
    viewfinderBrush.SetSource(cam);
  }
  else
  {
    txtMessage.Text = "A Camera is not available on this device.";
  }
}
protected override void OnNavigatingFrom
  (System.Windows.Navigation.NavigatingCancelEventArgs e)
{
  if (cam != null)
  {
    cam.Dispose();
  }
}

Ao navegar para fora da página, use o método OnNavigatingFrom para descartar o objeto da câmera e cancelar o registro dos eventos da câmera. Isso ajuda a minimizar o consumo de energia, agilizar o desligamento e liberar a memória.

Na captura de foto conforme mostrado no XAML, quando o usuário tocar no visor, o método viewfinder_Tapped será chamado. Esse método iniciará a captura de imagem quando a câmera estiver pronta. Se a câmera não tiver inicializado ou estiver executando atualmente o processo de captura de outra imagem, uma exceção será gerada. Para ajudar a reduzir as exceções, considere desativar os mecanismos que acionam a captura de fotos até que o evento inicializado seja acionado. Para simplificar as coisas nesse exemplo, nós pularemos essa etapa.

AFigura 4 exibe o código necessário para ser adicionado à classe MainPage.

Figura 4 Método viewfinder_Tapped

void viewfinder_Tapped(object sender, GestureEventArgs e)
{
  if (cam != null)
  {
    try
    {
      cam.CaptureImage();
    }
    catch (Exception ex)
    {
      this.Dispatcher.BeginInvoke(delegate()
      {
        txtMessage.Text = ex.Message;
      });
    }
  }
}

Capturar uma foto e salvá-la são ações assíncronas. Quando o método CaptureImage é chamado, uma cadeia de eventos é iniciada e o controle retorna à Interface do Usuário. Conforme mostrado no diagrama da sequência de eventos na Figura 5, há dois estágios para cada captura de imagem. Primeiro, o sensor da câmera captura a foto e, em seguida, as imagens são criadas com base nos dados do sensor.

The Image-Capture Event Sequence of the PhotoCamera Class
Figura 5 Sequência de eventos de captura de imagem da classe PhotoCamera

Na gravação de uma foto depois de o sensor capturá-la, serão criados dois arquivos de imagens em paralelo, uma imagem em tamanho integral e uma miniatura. Você não tem obrigação de usar as duas. Cada uma estará disponível como um fluxo de imagem JPG da propriedade e.ImageStream nos argumentos dos eventos correspondentes.

A biblioteca de mídia cria automaticamente as suas próprias miniaturas para exibição no hub Imagens do dispositivo, portanto, esse exemplo não precisa da versão de miniatura da imagem. Contudo, se você desejar exibir uma miniatura no seu próprio aplicativo, a propriedade e.ImageStream do manipulador de eventos Capture­ThumbnailAvailable seria uma escolha eficiente.

Quando o fluxo estiver disponível, você poderá usá-lo para salvar a imagem em vários locais. Por exemplo:

  • Pasta Álbum da câmera: Use o método MediaLibrary.SavePictureToCameraRoll.
  • Pasta Imagens salvas: Use o método MediaLibary.Save­-Picture.
  • Armazenamento isolado: Use o método IsolatedStorageFile­-Stream.Write.

Neste exemplo, vamos salvar a imagem na pasta Álbum da câmera. Para obter um exemplo de como salvar uma imagem no armazenamento isolado, consulte a Amostra de câmera básica do SDK do Windows Phone. Adicione o código na Figura 6 à classe MainPage.

Figura 6 Salvando uma imagem na pasta Álbum da câmera

void cam_CaptureImageAvailable(object sender,
  Microsoft.Devices.ContentReadyEventArgs e)
{
  photoCounter++;
  string fileName = photoCounter + ".jpg";
  Deployment.Current.Dispatcher.BeginInvoke(delegate()
  {
    txtMessage.Text = "Captured image available, saving picture.";
  });
  library.SavePictureToCameraRoll(fileName, e.ImageStream);
  Deployment.Current.Dispatcher.BeginInvoke(delegate()
  {
    txtMessage.Text = "Picture has been saved to camera roll.";
  });
}

No código da Figura 6, as mensagens são enviadas à Interface do Usuário antes e depois de a imagem ser salva na pasta Álbum da câmera. Essas mensagens visam simplesmente ajudá-lo a entender o que está ocorrendo; elas não são necessárias. O método BeginInvoke é necessário para transmitir a mensagem ao thread da interface do usuário. Se você não usou o BeginInvoke, uma exceção de threading cruzado será gerada. Por questões de brevidade, esse método não possui um código de tratamento de erros.

Manipulação do giro - Quando você salva uma imagem na biblioteca de mídia, a orientação correta da imagem será anotada nas informações EXIF do arquivo. A principal preocupação com o seu aplicativo é como a visualização da câmera será orientada na Interface do Usuário. Para manter a visualização na orientação correta, gire o visor (VideoBrush) adequadamente. O giro é obtido com a substituição do método virtual OnOrientationChanged. Adicione o código na Figura 7 à classe MainPage.

Figura 7 Substituindo o método virtual OnOrientationChanged.

void cam_CaptureImageAvailable(object sender,
  Microsoft.Devices.ContentReadyEventArgs e)
{
  photoCounter++;
  string fileName = photoCounter + ".jpg";
  Deployment.Current.Dispatcher.BeginInvoke(delegate()
  {
    txtMessage.Text = "Captured image available, saving picture.";
  });
  library.SavePictureToCameraRoll(fileName, e.ImageStream);
  Deployment.Current.Dispatcher.BeginInvoke(delegate()
  {
    txtMessage.Text = "Picture has been saved to camera roll.";
  });
}
protected override void OnOrientationChanged
  (OrientationChangedEventArgs e)
{
  if (cam != null)
  {
    Dispatcher.BeginInvoke(() =>
    {
      double rotation = cam.Orientation;
      switch (this.Orientation)
      {
        case PageOrientation.LandscapeLeft:
          rotation = cam.Orientation - 90;
          break;
        case PageOrientation.LandscapeRight:
          rotation = cam.Orientation + 90;
          break;
      }
        viewfinderTransform.Rotation = rotation;
    });
  }
  base.OnOrientationChanged(e);
}

Sem ajustes na orientação, o visor de uma câmera principal normal só será exibido na orientação correta quando o botão disparador do hardware estiver apontando para cima (LandscapeLeft). Se você girar o dispositivo de modo que o botão disparador do hardware esteja apontando para baixo (LandscapeRight), o visor deverá ser girado 180 graus para ser exibido corretamente na Interface do Usuário. A propriedade PhotoCamera Orientation é usada aqui no caso de a orientação física da câmera principal ser atípica.

Declarando recursos do aplicativo - Finalmente, quando o aplicativo usar uma câmera, você deverá declarar isso no arquivo de manifesto do aplicativo, WMAppManifest.xml. Não importa a câmera que está sendo usada, você precisará do recurso ID_CAP_ISV_CAMERA. Opcionalmente, você poderá usar o recurso ID_HW_FRONTCAMERA para informar que o seu aplicativo requer uma câmera frontal:

<Capability Name="ID_CAP_ISV_CAMERA"/>
<Capability Name="ID_HW_FRONTCAMERA"/>

O aplicativo da sua câmera não será executado sem o recurso ID_CAP_ISV_CAMERA. Se você não tiver tido problemas ao executá-lo até o momento, isso ocorreu porque o recurso foi adicionado automaticamente aos novos projetos do Windows Phone. No entanto, se você estiver atualizando o seu aplicativo, você precisará adicioná-lo manualmente. O recurso ID_HW_FRONTCAMERA deve sempre ser adicionado manualmente, mas a sua ausência não impedirá a execução do aplicativo.

Esses recursos ajudam a alertar os usuários que não possuem uma câmera em seu dispositivo, mas esses não são impedidos de baixar e comprar o aplicativo. Por esse motivo, é uma boa ideia disponibilizar uma versão de avaliação do aplicativo. Portanto, se os usuários não perceberem os alertas, eles não gastarão dinheiro apenas para saber que o aplicativo não funciona como esperado em seu dispositivo. As classificações do aplicativo irão recompensá-lo posteriormente.

Se você ainda não tiver feito isso, pressione F5 para depurar esse aplicativo de câmera simples em seu dispositivo. Você pode depurar o aplicativo no emulador, mas você verá apenas uma caixa preta se movendo na tela porque o emulador não possui uma câmera física. Ao depurar o dispositivo, lembre-se de que você não pode visualizar as novas imagens no hub Imagens até liberar o dispositivo do seu PC.

Para ir mais fundo, observe a Amostra de câmera básica no SDK do Windows Phone. Essa amostra demonstra a API completa para a captura de fotos: desde o ajuste do flash e das configurações de resolução à incorporação do foco por toque e do botão disparador do hardware.

Acesso ao buffer de visualização da câmera

No exemplo anterior, os quadros do buffer de visualização da câmera foram transmitidos para o visor. A classe PhotoCamera também expõe o quadro atual do buffer de visualização para permitir a manipulação de cada quadro pixel a pixel. Vamos verificar uma amostra do SDK do Windows Phone para saber como é possível manipular os quadros do buffer de visualização e exibi-los num bitmap gravável na Interface do Usuário.

A classe PhotoCamera expõe o quadro atual do buffer de visualização com os seguintes métodos “get preview”:

  • GetPreviewBufferArgb32: Matriz de inteiros do quadro atual no formato ARGB
  • GetPreviewBufferYCbCr: Matriz de bytes do quadro atual no formato YCbCr
  • GetPreviewBufferY: Matriz de bytes do plano de luminância apenas, num formato semelhante

ARGB é o formato usado para descrever cores no Silverlight para aplicativos Windows Phone. O formato YCbCr permite o processamento eficiente de imagens, mas o Silverlight não pode usar o YCbCr. Se desejar manipular um quadro YCbCr no seu aplicativo, você precisará converter o quadro para o formato ARGB antes de exibi-lo. Para obter mais informações sobre esses formatos e a conversão de cores, consulte a seguinte página da Biblioteca MSDN: “Conversão de cores da câmera (YCbCr para ARGB) para o Windows Phone,” em wpdev.ms/colorconversion.

A Amostra da escala de cinza da câmera do SDK do Windows Phone (consulte a Figura 8) demonstra como manipular quadros ARGB do buffer de visualização e gravá-los numa imagem de bitmap gravável, quase que em tempo real. Nessa amostra, cada quadro é convertido de uma cor para a escala de cinza. Observe que o objetivo dessa amostra é demonstrar a manipulação do formato ARGB, se o aplicativo precisar apenas da escala de cinza, considere usar o método GetPreviewBufferY em vez disso.

The Camera Grayscale Sample UIFigura 8 A Interface do usuário da Amostra da escala de cinza da câmera

No arquivo XAML, uma marca de imagem será usada para hospedar o bitmap gravável correspondente (a imagem em preto e branco no canto esquerdo inferior da Interface do Usuário), como a seguir:

<Image x:Name="MainImage"
       Width="320" Height="240"
       HorizontalAlignment="Left" VerticalAlignment="Bottom" 
       Margin="16,0,0,16"
       Stretch="Uniform"/>

Quando um botão for pressionado para ativar a conversão da escala de cinza, um novo thread será criado para executar o processamento; um bitmap gravável, com as mesmas dimensões do buffer de visualização, será criado e atribuído como fonte do controle de imagem:

wb = new WriteableBitmap(
        (int)cam.PreviewResolution.Width,
        (int)cam.PreviewResolution.Height);
this.MainImage.Source = wb;

O thread executa o seu trabalho no método PumpARGBFrames. Neste, uma matriz de inteiros denominada ARGBPx será usada para manter um instantâneo do buffer de visualização atual. Cada inteiro na matriz representa um pixel do quadro, no formato ARGB. Essa matriz também é criada com as mesmas dimensões do buffer de visualização:

int[] ARGBPx = new int[
    (int)cam.PreviewResolution.Width *
    (int)cam.PreviewResolution.Height];

Enquanto o recurso “escala de cinza” da amostra é ativado, o thread copia o quadro atual no buffer de visualização para a matriz ARGBPx. Aqui, o objeto da câmera é phCam:

phCam.GetPreviewBufferArgb32(ARGBPx);

Depois que o buffer tiver sido copiado para a matriz, o thread fará um loop em cada pixel e o converterá para a escala de cinza (consulte a amostra para obter mais detalhes sobre como isso é executado):

for (int i = 0; i < ARGBPx.Length; i++)
{
  ARGBPx[i] = ColorToGray(ARGBPx[i]);
}

Por fim, antes de processar o próximo quadro, o thread usará o método BeginInvoke para atualizar o WriteableBitmap na Interface do Usuário. O método CopyTo substitui os pixels WriteableBitmap pela matriz ARGBPx e o método Invalidate força o WriteableBitmap a redesenhar, como a seguir:

Deployment.Current.Dispatcher.BeginInvoke(delegate()
{
  // Copy to WriteableBitmap.
  ARGBPx.CopyTo(wb.Pixels, 0);
  wb.Invalidate();
  pauseFramesEvent.Set();
});

A classe WriteableBitmap permite uma variedade de possibilidades criativas. Agora, você pode incorporar o buffer de visualização da câmera no seu repertório de recursos visuais da Interface do Usuário.

Gravação de vídeo

Embora você possa usar a classe PhotoCamera para transmitir o buffer de visualização para a Interface do Usuário, você não pode usá-la para gravar um vídeo. Por isso, você precisará de algumas classes do namespace System.Windows.Media. Na parte final desse artigo, nós examinaremos a Amostra do gravador de vídeo do SDK do Windows Phone (consulte a Figura 9) para saber como gravar vídeo para um arquivo MP4 no Armazenamento isolado. É possível encontrar essa amostra na página de amostras do código do SDK.

The Video Recorder Sample UI
Figura 9 Interface do usuário da amostra do gravador de vídeo

As principais classes para a gravação de vídeo são:

  • CaptureDeviceConfiguration: Use essa classe para verificar a disponibilidade de um dispositivo de captura de vídeo.
  • CaptureSource: Use essa classe para iniciar e interromper a gravação ou visualização de um vídeo.
  • VideoBrush: Use essa classe para preencher os controles da Interface do Usuário do Silverlight com um objeto CaptureSource ou PhotoCamera.
  • FileSink: Use essa classe para gravar vídeos no Armazenamento isolado quando um objeto CaptureSource estiver sendo executado.

No arquivo XAML, um controle de retângulo será usado para exibir o visor da câmera:

<Rectangle
  x:Name="viewfinderRectangle"
  Width="640"
  Height="480"
  HorizontalAlignment="Left"
  Canvas.Left="80"/>

Contudo, o controle de retângulo não é necessário para exibir vídeos. Você poderia usar o controle de tela, conforme exibido no primeiro exemplo. O controle de retângulo é usado simplesmente para mostrar outra maneira de exibir um vídeo.

No nível da página, as seguintes variáveis são declaradas:

// Viewfinder for capturing video.
private VideoBrush videoRecorderBrush;
// Source and device for capturing video.
private CaptureSource captureSource;
private VideoCaptureDevice videoCaptureDevice;
// File details for storing the recording.       
private IsolatedStorageFileStream isoVideoFile;
private FileSink fileSink;
private string isoVideoFileName = "CameraMovie.mp4";

Quando um usuário navega para a página, o método InitializeVideoRecorder inicia a câmera e envia a visualização da câmera para o retângulo. Depois de criar os objetos captureSource e fileSink, o método InitializeVideoRecorder usa o objeto estático Capture­DeviceConfiguration para encontrar um dispositivo de vídeo. Se nenhuma câmera estiver disponível, o videoCaptureDevice será nulo:

videoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();

No Windows Phone 7.5, as câmeras são opcionais. Embora elas sejam comuns nos dispositivos atuais, a prática recomendada é verificá-las no código. Conforme a Figura 10 mostra, o videoCaptureDevice é usado para verificar a presença de uma câmera. Se uma câmera estiver disponível, o captureSource será definido como a fonte de um VideoBrush denominado videoRecorderBrush e o videoRecorderBrush será usado como o preenchimento do controle de retângulo denominado viewfinderRectangle. Quando o método Start do captureSource for chamado, a câmera começará a enviar o vídeo para o retângulo.

Figura 10 Exibindo a visualização do vídeo

// Initialize the camera if it exists on the device.
if (videoCaptureDevice != null)
{
  // Create the VideoBrush for the viewfinder.
  videoRecorderBrush = new VideoBrush();
  videoRecorderBrush.SetSource(captureSource);
  // Display the viewfinder image on the rectangle.
  viewfinderRectangle.Fill = videoRecorderBrush;
  // Start video capture and display it on the viewfinder.
  captureSource.Start();
  // Set the button state and the message.
  UpdateUI(ButtonState.Initialized, "Tap record to start recording...");
}
else
{
  // Disable buttons when the camera is not supported by the device.
  UpdateUI(ButtonState.CameraNotSupported, "A camera is not supported on this device.");
}

Nesse exemplo, um método auxiliar denominado UpdateUI gerencia os estados do botão e grava mensagens para o usuário. Consulte a Amostra do gravador de vídeo para obter mais detalhes.

Apesar de o objeto fileSink ter sido criado, nenhum vídeo está sendo gravado no momento. Esse estado do aplicativo é descrito como "visualização" de vídeo. Para gravar um vídeo, o fileSink precisa estar conectado ao captureSource antes de ser iniciado. Em outras palavras, antes de gravar um vídeo, você precisa interromper o captureSource.

Quando o usuário tocar o botão de gravação na amostra do gravador de vídeo, o método StartVideoRecorder começará a transição da visualização para a gravação. A primeira etapa na transição é interromper o captureSource e reconfigurar o fileSink:

// Connect fileSink to captureSource.
if (captureSource.VideoCaptureDevice != null
    && captureSource.State == CaptureState.Started)
{
  captureSource.Stop();
  // Connect the input and output of fileSink.
  fileSink.CaptureSource = captureSource;
  fileSink.IsolatedStorageFileName = isoVideoFileName;
}

Embora as classes CaptureSource e VideoBrush possam parecer familiar, se você tiver desenvolvido aplicativos para o plug-in do Silverlight, a classe FileSink será completamente nova. A classe FileSink é exclusiva dos aplicativos para Windows Phone e conhece tudo a respeito da gravação no Armazenamento isolado; tudo o que você precisa fazer é fornecer o nome do arquivo.

Depois de a classe fileSink ter sido reconfigurada, o método StartVideoRecorder reinicia o captureSource e atualiza a Interface do Usuário:

captureSource.Start();
// Set the button states and the message.
UpdateUI(ButtonState.Ready, "Ready to record.");

Quando o usuário interromper a gravação para fazer a transição de gravação para visualização, o captureSource precisará ser interrompido novamente antes do fileSink ser reconfigurado, conforme ilustrado na Figura 11.

Figura 11 Fazendo a transição da gravação para a visualização

// Stop recording.
if (captureSource.VideoCaptureDevice != null
&& captureSource.State == CaptureState.Started)
{
  captureSource.Stop();
  // Disconnect fileSink.
  fileSink.CaptureSource = null;
  fileSink.IsolatedStorageFileName = null;
  // Set the button states and the message.
  UpdateUI(ButtonState.NoChange, "Preparing viewfinder...");
  StartVideoPreview();
}

A lógica de visualização do início do vídeo foi isolada em outro método para ativar a transição para visualização do estado de reprodução de vídeo (não abordado nesse artigo). Embora a reprodução de vídeo não seja abordada aqui, é importante observar que no Windows Phone somente um fluxo de vídeo poderá ser executado de cada vez.

A Amostra do gravador de vídeo apresenta dois fluxos de vídeo separados:

  1. captureSource g videoRecorderBrush g viewfinderRectangle (controle de retângulo)
  2. isoVideoFile g VideoPlayer (controle MediaElement)

Uma vez que apenas um fluxo de vídeo pode ser executado de cada vez, essa amostra apresenta um método de descarte para cada fluxo que pode ser chamado antes de executar o outro fluxo. Nos métodos DisposeVideoPlayer e Dispose­VideoRecorder, o fluxo será interrompido ao chamar o método Stop no respectivo objeto (e configurar a fonte do MediaElement para nulo). Os objetos CaptureSource e MediaElement não implementam realmente a interface IDisposable.

Nesse momento, você poderá estar pensando que a Amostra da escala de cinza da câmera parecia apresentar dois vídeos executados ao mesmo tempo. Na realidade, havia apenas um fluxo de vídeo nesse aplicativo: o fluxo do objeto PhotoCamera para o controle VideoBrush. O "vídeo" da escala de cinza era, de fato, apenas um bitmap redesenhado em alta velocidade, baseado em quadros manipulados individualmente do buffer de visualização da câmera.

Conclusão

A API da câmera, nova no Windows Phone 7.5, abre as portas para uma nova geração de aplicativos que solucionam problemas e divertem de maneiras nunca antes possíveis nas versões mais antigas do SO. Este artigo descreveu apenas alguns aspectos da API. Para obter uma descrição completa, consulte a seção Câmera e Fotos da documentação SDK do Windows Phone em wpdev.ms/cameraandphotos.

Matt Stroshane escreve a documentação destinada ao desenvolvedor para a equipe do Windows Phone. As outras contribuições de Matt para a Biblioteca MSDN incluem produtos como o SQL Server, SQL Azure e Visual Studio. Quando ele não está escrevendo, você pode encontrá-lo nas ruas de Seattle, treinando para a sua próxima maratona. Siga-o no Twitter em twitter.com/mattstroshane.

Agradecemos aos seguintes especialistas técnicos pela revisão deste artigo: Eric BennettNikhil DeoreAdam Lydick e Jon Sheller