[Windows Phone]カメラデバイスを使用した録画・再生アプリ作成

はじめに

今回はWindows Phoneにてカメラデバイスを使用して動画を録画し、また、録画した動画を再生するアプリの作成を行います。

プロジェクトの作成

次の手順で、雛形となるプロジェクトを作成します。

  • windowsのスタートメニューのプログラムより、[Microsoft Visual Studio 2010]-[Visual Studio 2010 for Windows Phone]を起動します。
  • Visual Studio 2010 for Windows Phoneより[新しいプロジェクト]を選択します。
  • 新しいプロジェクトのページより、[Visual C#]-[Silverlight for Windows Phone]のテンプレートを選択し、[Windows Phone アプリケーション]を選択してプロジェクト名を入力します。
  • 新しいwindows Phone アプリケーションダイアログにて対象となるwindows Phone プラットフォームのバージョンを選択します。
    (今回はwindows Phone OS 7.1を対象とします)
  • 新しいプロジェクトが作成され、MainPage.xamlが表示されます。

 

カメラ機能の宣言

アプリケーションでカメラデバイスを使用する際、アプリケーション マニフェスト ファイルにカメラ機能を宣言しなければカメラデバイスは使用できません。

また、動画を録画する際、音声等も記録する場合はマイク機能を有効にする必要があります。

アプリケーション マニフェスト ファイルに次の手順で宣言を追加または確認を行います。

  • プロジェクトの[Properties]内にある[WMAppManifest.xml]を開き、タグ内に次の要素があるか確認し、なければ追加を行います。
  •  <!-- カメラ機能 -->
     <Capability Name="ID_CAP_ISV_CAMERA"/>
     <!-- マイク機能 -->
     <Capability Name="ID_CAP_MICROPHONE"/>
    
  • (また、カメラ機能のうち、前面カメラのみを使用する場合は以下の要素を確認・追加します。今回は使用しませんが蛇足として記述)
  • <!-- 前面カメラ機能 -->
    <Capability Name="ID_HW_FRONTCAMERA"/>
    

 

アイコンの追加(SDK既存のアイコン)

アプリで使用するUIのうち、SDKで既存で用意されているアイコンがありますので、今回はそれを利用して作成を行います。

この項目では、そのアイコンをプロジェクトに追加する手順を記述します。

  • プロジェクト上にて右クリックを行い、[追加]-[新しいフォルダー]を選択し、アイコン用のフォルダを作成します。(今回の場合はこのフォルダに[Icons]とします)
  • 上記にて作成したフォルダ上で右クリックを行い、[追加]-[既存の項目]を選択します。
  • [既存の項目の追加]ダイアログが表示されるので、次のパスの場所
    C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Icons\dark
    へ移動し、使用するアイコンを選択します。
    今回の場合は次の4つを使用します。
    • appbar.feature.video.rest.png(ビデオマークアイコン)
    • appbar.stop.rest.png(ストップアイコン)
    • appbar.transport.pause.rest.png(ポーズアイコン)
    • appbar.transport.play.rest.png(プレイアイコン)
  • 追加されたアイコンをそれぞれ右クリックし、[プロパティ]を選択してプロパティウィンドウを開きます。
  • プロパティにて[出力ディレクトリにコピー]の部分を[常にコピーする]に変更します。

これにより使用する準備が整います。

 

UIの作成(xaml)

アプリのUIを作成します。今回はシステムトレイを表示せず、横向きのアプリを想定するため、まずはMainPage.xamlの要素のプロパティを次のように追加・変更を行います。

<phone:PhoneApplicationPage 
 //省略
 SupportedOrientations="Landscape" 
 Orientation="LandscapeLeft"
 shell:SystemTray.IsVisible="False"
 //省略
?

 

続いて、実際の画面について作成します。作成する画面に関しては、先ほど追加したアイコンを使用したボタンを配置するアプリケーションバーと、録画・再生を行うメイン画面をそれぞれ作成します。

  <!-- メイン画面(録画・再生画面) -->
  <Canvas x:Name="LayoutRoot" Background="Transparent"

  <!-- 録画画面表示用 -->
  <Rectangle 
    x:Name="viewfinderRectangle"
    Width="640" 
    Height="480" 
    HorizontalAlignment="Left" 
    Canvas.Left="80"/>

  <!-- 再生用 -->
  <MediaElement 
    x:Name="VideoPlayer" 
    Width="640" 
    Height="480"
    AutoPlay="True" 
    RenderTransformOrigin="0.5, 0.5" 
    VerticalAlignment="Center" 
    HorizontalAlignment="Center" 
    Stretch="Fill"
    Canvas.Left="80"/>

  <!-- メッセージ表示等テキスト -->
  <TextBlock 
    Height="40" 
    HorizontalAlignment="Left" 
    Margin="100,428,0,0"
    Name="txtDebug" 
    VerticalAlignment="Top"
    Width="626"
    FontSize="24" 
    FontWeight="ExtraBold"/>

  </Canvas>

 <!-- アプリケーションバー(アイコンボタン) -->
  <phone:PhoneApplicationPage.ApplicationBar>
    <shell:ApplicationBar IsVisible="True" 
       IsMenuEnabled="True" 
       x:Name="PhoneAppBar" Opacity="0.0">

    <!-- 録画ボタン -->
      <shell:ApplicationBarIconButton 
         IconUri="/Icons/appbar.feature.video.rest.png"
         Text="record" x:Name="StartRecording" 
         Click="StartRecording_Click" />
    <!-- 停止ボタン -->
      <shell:ApplicationBarIconButton 
         IconUri="/Icons/appbar.stop.rest.png" 
         Text="stop" x:Name="StopPlaybackRecording"
         Click="StopPlaybackRecording_Click"/>
    <!-- 再生ボタン -->
      <shell:ApplicationBarIconButton 
         IconUri="/Icons/appbar.transport.play.rest.png" 
         Text="play" x:Name="StartPlayback" 
         Click="StartPlayback_Click"  />
    <!-- 停止ボタン -->
       <shell:ApplicationBarIconButton 
         IconUri="/Icons/appbar.transport.pause.rest.png" 
         Text="pause" x:Name="PausePlayback" 
          Click="PausePlayback_Click"/>
    </shell:ApplicationBar>
  </phone:PhoneApplicationPage.ApplicationBar>

 

コードの追加

上記xamlを作成を行ったら、今度はコードよりそれを有効化し、また各動作等の実装を行う必要があります。

MainPage.xaml.csより次のようにコードを追加・修正します。

参照の追加

MainPage.xaml.csに、次の7つの参照を追加します。

using System.ComponentModel;
using System.Threading;
using System.IO;
using System.IO.IsolatedStorage;
using Microsoft.Phone.Shell;
using System.Windows.Navigation;
using Microsoft.Devices;

変数・コンストラクターの追加

MainPage.xaml.csに次の変数とコンストラクターを追加します。

public partial class MainPage : PhoneApplicationPage {
  // 画面描画用
  private VideoBrush videoRecorderBrush;
  // 録画記録用
  private CaptureSource captureSource;
  private VideoCaptureDevice videoCaptureDevice;
  // ファイル保存用       
  private IsolatedStorageFileStream isoVideoFile;
  private FileSink fileSink;
  private string isoVideoFileName = "CameraMovie.mp4";
  // ボタン及びメッセージ管理用
  private enum ButtonState { Initialized, Ready, Recording, Playback, Paused, NoChange, CameraNotSupported };
  private ButtonState currentAppState;

  // コンストラクター
  public MainPage()
  {
    InitializeComponent();

    // アプリケーションバー用のボタン
    PhoneAppBar = (ApplicationBar)ApplicationBar;
    PhoneAppBar.IsVisible = true;
    StartRecording = ((ApplicationBarIconButton)ApplicationBar.Buttons[0]);
    StopPlaybackRecording = ((ApplicationBarIconButton)ApplicationBar.Buttons[1]);
    StartPlayback = ((ApplicationBarIconButton)ApplicationBar.Buttons[2]);
    PausePlayback = ((ApplicationBarIconButton)ApplicationBar.Buttons[3]);
  }
  //省略
}

カメラ初期化及び録画・再生オブジェクト破棄のメソッドの追加

MainPage.xaml.csのMainPageクラスに次のメソッドを追加します。

protected override void OnNavigatedTo(NavigationEventArgs e)
{
  base.OnNavigatedTo(e);
  // カメラ初期化
  InitializeVideoRecorder();
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
  // 録画オブジェクト・再生オブジェクトの破棄
  DisposeVideoPlayer();
  DisposeVideoRecorder();
  base.OnNavigatedFrom(e);
}

UI(アプリケーションボタン)の挙動処理

MainPage.xaml.csのMainPageクラスに次のメソッドを追加します。このメソッドはアプリケーションバーの挙動の変更を行ったり、状態を表示させるのに利用されます。

private void UpdateUI(ButtonState currentButtonState, string statusMessage)
{
  Dispatcher.BeginInvoke(delegate
  {
    switch (currentButtonState)
    {
      // カメラデバイスに対応していないWindowsPhoneの場合、操作不可
      case ButtonState.CameraNotSupported:
        StartRecording.IsEnabled = false;
        StopPlaybackRecording.IsEnabled = false;
        StartPlayback.IsEnabled = false;
        PausePlayback.IsEnabled = false;
        break;
      // 起動時及び動画が有効でない場合、録画開始が有効
      case ButtonState.Initialized:
        StartRecording.IsEnabled = true;
        StopPlaybackRecording.IsEnabled = false;
        StartPlayback.IsEnabled = false;
        PausePlayback.IsEnabled = false;
        break;
      // 録画が行われ、動画が有効になっている場合、録画開始及び再生が有効
      case ButtonState.Ready:
        StartRecording.IsEnabled = true;
        StopPlaybackRecording.IsEnabled = false;
        StartPlayback.IsEnabled = true;
        PausePlayback.IsEnabled = false;
        break;
      // 録画が動作している場合、録画停止が有効
      case ButtonState.Recording:
        StartRecording.IsEnabled = false;
        StopPlaybackRecording.IsEnabled = true;
        StartPlayback.IsEnabled = false;
        PausePlayback.IsEnabled = false;
        break;
      // 動画を再生している場合、動画停止と一時停止が有効
      case ButtonState.Playback:
        StartRecording.IsEnabled = false;
        StopPlaybackRecording.IsEnabled = true;
        StartPlayback.IsEnabled = false;
        PausePlayback.IsEnabled = true;
        break;
      // 動画を一時停止している場合、動画停止と再生が有効
      case ButtonState.Paused:
        StartRecording.IsEnabled = false;
        StopPlaybackRecording.IsEnabled = true;
        StartPlayback.IsEnabled = true;
        PausePlayback.IsEnabled = false;
        break;
      default:
        break;
    }
    // メッセージを表示
    txtDebug.Text = statusMessage;
    currentAppState = currentButtonState;
  });
}

カメラ初期化処理の実装

MainPage.xaml.csのMainPageクラスに次のメソッドを追加します。

public void InitializeVideoRecorder()
{
  if (captureSource == null)
  {
    // 録画オブジェクト生成
    captureSource = new CaptureSource();
    fileSink = new FileSink();
    videoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();

    // イベントハンドラー追加
    captureSource.CaptureFailed += new EventHandler<ExceptionRoutedEventArgs>(OnCaptureFailed);

    // カメラデバイスがある場合、初期化
    if (videoCaptureDevice != null)
    {
      // 録画画面の設定
      videoRecorderBrush = new VideoBrush();
      videoRecorderBrush.SetSource(captureSource);
      // 録画範囲
      viewfinderRectangle.Fill = videoRecorderBrush;
      // 録画開始
      captureSource.Start();

      // アプリケーションボタン及びメッセージ表示
      UpdateUI(ButtonState.Initialized, &quot;Tap record to start recording...&quot;);
    }else{
      //  カメラデバイスに対応していない場合、ボタン非表示及びメッセージ表示
      UpdateUI(ButtonState.CameraNotSupported, &quot;A camera is not supported on this device.&quot;);
    }
  }
}

録画及びプレビュー(再生)の切り替えの実装

MainPage.xaml.csのMainPageクラスに次のメソッドを追加します。

// 録画開始
private void StartVideoRecording()
{
  try{
    // ビデオデバイスで録画開始
    if (captureSource.VideoCaptureDevice != null 
      && captureSource.State == CaptureState.Started)
    {
      captureSource.Stop();
      // ビデオデバイスの内容をファイルに保存
      fileSink.CaptureSource = captureSource;
      fileSink.IsolatedStorageFileName = isoVideoFileName;
    }
    // 録画開始
    if (captureSource.VideoCaptureDevice != null
      && captureSource.State == CaptureState.Stopped)
    {
      captureSource.Start();
    }

    // ボタン及びメッセージ表示(UIの挙動処理動作)
    UpdateUI(ButtonState.Recording, "Recording...");
  }
  // エラー発生時
  catch (Exception e){
    this.Dispatcher.BeginInvoke(delegate()
    {
      txtDebug.Text = "ERROR: " + e.Message.ToString();
    });
  }
}

// 録画停止
private void StopVideoRecording()
{
  try{
    // 録画停止
    if (captureSource.VideoCaptureDevice != null
      && captureSource.State == CaptureState.Started)
    {
      captureSource.Stop();
      // 接続解除
      fileSink.CaptureSource = null;
      fileSink.IsolatedStorageFileName = null;

      // ボタン及びメッセージ表示(UIの挙動処理動作)
      UpdateUI(ButtonState.NoChange, "Preparing viewfinder...");

      StartVideoPreview();
    }
  }
  // エラー発生時
  catch (Exception e){
    this.Dispatcher.BeginInvoke(delegate()
    {
      txtDebug.Text = "ERROR: " + e.Message.ToString();
    });
  }
}

// 動画再生
private void StartVideoPreview()
{
  try{
    // 動画表示
    if (captureSource.VideoCaptureDevice != null
      && captureSource.State == CaptureState.Stopped)
    {
      // 画面に録画したデータを表示
      videoRecorderBrush.SetSource(captureSource);
      // 録画範囲解除
      viewfinderRectangle.Fill = videoRecorderBrush;
      captureSource.Start();

      // ボタン及びメッセージ表示(UIの挙動処理動作)
      UpdateUI(ButtonState.Ready, "Ready to record.");
    }
  }
  // エラー発生時
  catch (Exception e){
    this.Dispatcher.BeginInvoke(delegate()
    {
      txtDebug.Text = "ERROR: " + e.Message.ToString();
    });
  }
}

ボタン処理実装

MainPage.xaml.csのMainPageクラスに次のメソッドを追加します。主にアプリケーションバーのアイコンボタンを押した際、メソッドを呼び出す処理を実装します。

// 録画ボタンクリック
private void StartRecording_Click(object sender, EventArgs e)
{
  StartRecording.IsEnabled = false;
  StartVideoRecording();
}

//停止ボタンクリック
private void StopPlaybackRecording_Click(object sender, EventArgs e)
{
  StopPlaybackRecording.IsEnabled = false;

  // 録画停止
  if (currentAppState == ButtonState.Recording)
  {
    StopVideoRecording();

    // ボタン及びメッセージ表示(UIの挙動処理動作)
    UpdateUI(ButtonState.NoChange, "Recording stopped.");
  }else{
    // 再生停止
    // 再生オブジェクト破棄
    DisposeVideoPlayer();
    StartVideoPreview();
    // ボタン及びメッセージ表示(UIの挙動処理動作)
    UpdateUI(ButtonState.NoChange, "Playback stopped.");
  }
}

// 再生ボタンクリック
private void StartPlayback_Click(object sender, EventArgs e)
{
  StartPlayback.IsEnabled = false;

  // ファイルストリームがある場合、再生
  if (isoVideoFile != null)
  {
    VideoPlayer.Play();
  }else{
    // ファイルストリームが無い場合、録画を停止しその内容をメディア化して再生

    // 録画停止
    captureSource.Stop();
    // 撮影範囲クリア
    viewfinderRectangle.Fill = null;

    // メディア化及び再生設定
    isoVideoFile = new IsolatedStorageFileStream(isoVideoFileName,
      FileMode.Open, FileAccess.Read,
      IsolatedStorageFile.GetUserStoreForApplication());
    VideoPlayer.SetSource(isoVideoFile);

    // 動画再生イベントハンドラー生成
    VideoPlayer.MediaEnded += new RoutedEventHandler(VideoPlayerMediaEnded);

    // 再生
    VideoPlayer.Play();
  }
  // ボタン及びメッセージ表示(UIの挙動処理動作)
  UpdateUI(ButtonState.Playback, "Playback started.");
}

// 一時停止ボタンクリック
private void PausePlayback_Click(object sender, EventArgs e)
{
  PausePlayback.IsEnabled = false;

  // メディアがある場合、一時停止
  if (VideoPlayer != null)
  {
    VideoPlayer.Pause();
  }
  // ボタン及びメッセージ表示(UIの挙動処理動作)
  UpdateUI(ButtonState.Paused, "Playback paused.");
}

録画オブジェクト及び再生オブジェクトの破棄の実装

MainPage.xaml.csのMainPageクラスに次のメソッドを追加します。実際に破棄メソッドの実行はされておりませんが、Nullを指定する事でガベージコレクションにより必要によって破棄されるようになります。

//再生オブジェクト破棄
private void DisposeVideoPlayer()
{
  if (VideoPlayer != null){
    // 再生停止
    VideoPlayer.Stop();
    // 再生オブジェクト破棄
    VideoPlayer.Source = null;
    isoVideoFile = null;
    // イベントハンドラー削除
    VideoPlayer.MediaEnded -= VideoPlayerMediaEnded;
  }
}
//録画オブジェクト破棄
private void DisposeVideoRecorder()
{
  if (captureSource != null){
    // 録画停止
    if (captureSource.VideoCaptureDevice != null
      && captureSource.State == CaptureState.Started)
    {
      captureSource.Stop();
    }
    // イベントハンドラー削除
    captureSource.CaptureFailed -= OnCaptureFailed;
    // 録画オブジェクト破棄
    captureSource = null;
    videoCaptureDevice = null;
    fileSink = null;
    videoRecorderBrush = null;
  }
}

録画失敗時及び再生終了時の実装

MainPage.xaml.csのMainPageクラスに次のメソッドを追加します。

// 録画失敗時、エラーメッセージを表示
private void OnCaptureFailed(object sender, ExceptionRoutedEventArgs e)
{
  this.Dispatcher.BeginInvoke(delegate()
  {
    txtDebug.Text = "ERROR: " + e.ErrorException.Message.ToString();
  });
}

// 動画再生終了時、オブジェクトを破棄
public void VideoPlayerMediaEnded(object sender, RoutedEventArgs e)
{
  DisposeVideoPlayer();
  StartVideoPreview();
}

以上にてカメラデバイスを使用した録画・再生アプリは作成されました。

 

ビルド及びデバック実行

上記によりWindows Phoneアプリケーションができましたので、これをビルド及びデバック実行を行います。
(今回の場合はローカル上のエミュレーターでの動作のため、実際には録画・再生は行えませんので注意)

その際の手順は以下のようになります。

  • Visual Studio 2010 for Windows Phoneのメニューより[デバッグ]-[ソリューションのビルド]を選択し、ビルドを行います。
    (現時点では何も弄ってないためそのままビルドされますが、エラーが存在する場合ビルドされず、またそのエラーはメニューの[表示]-[その他のウィンドウ]-[エラー一覧]より表示されるエラー一覧ウィンドウに表示されます。)
  • ビルド成功後、ツールバーの[デバッグ開始]ボタンの隣にある[Windows Phoneプロジェクトターゲット]プルダウンリストより、[Windows Phone Emulator]または[Windows Phone Emulator(JA)]を選択し、
    メニューの[デバッグ]-[デバッグ開始]またはツールバーの[デバッグ開始]ボタンよりデバッグを実行します。
    (この時、開発環境にグラフィック処理装置等が存在していない、または構成していない場合はXNA Framework関係のグラフィックスは表示できませんとの警告が発生しますが、今回の場合は使用していないため、そのまま続行を行います)
  • アプリケーションがエミュレータ上で起動します。その際、横向きやズーム等はエミュレータの横にあるエミュレータのツールバーを利用します。
  • カテゴリー: C#, VisualStudio タグ: , パーマリンク

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

    次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>