Webカメラで撮影した画像に音声コメントを付けて保存・再生するには:2カ月で160本作った還暦開発者が送る10のアプリ開発ノウハウ(6)(3/4 ページ)
古(いにしえ)からのVBでWindows 8.1向けのさまざまな機能のアプリを開発する手順やコツを解説していく。今回は、Webカメラで撮影した画像に音声コメントを付けて保存・再生する方法をサンプルを交えて解説する。
メイン画面のロジックコード(MainWindow.xaml.vb)
次に、[ソリューション・エクスプローラー]内のMainWindow.xamlを展開して表示される、「MainWindow.xaml.vb」のコードを記述する。
ここではコードが長くなるため、名前空間の読み込み、メンバー変数の宣言は一部省略している。全てのコードは、サンプルをダウンロードして「MainWindow.xaml.vb」ファイルで確認してほしい。
MP4の音声ファイルを作成し、実装されているカメラのデバイスを取得してComboBoxに表示する処理(DataShowタスク処理)
Private Async Function DataShow() As Task
AppBar1.Visibility = Xaml.Visibility.Visible
Try
myRecordMediaCapture = New MediaCapture
myCaptureInitSetting = New MediaCaptureInitializationSettings
myCaptureInitSetting.AudioDeviceId = String.Empty
myCaptureInitSetting.StreamingCaptureMode = StreamingCaptureMode.Audio
Await myRecordMediaCapture.InitializeAsync(myCaptureInitSetting)
myProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto)
Dim myStorageFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
Dim mySubFolder = Await myStorageFolder.CreateFolderAsync("ImageVoiceRecord", CreationCollisionOption.OpenIfExists)
Dim myFile = Await mySubFolder.GetFilesAsync()
If myFile.Count > 0 Then
ichiranButton.IsEnabled = True
Else
PhotoArea.Children.Clear()
ichiranButton.IsEnabled = False
End If
For Each result In myFile
If result.Path.Contains("Thumbs.db") Then
Await result.DeleteAsync
End If
Next
cameraComboBox.Items.Clear()
myCamera = Await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture)
For i As Integer = 0 To myCamera.Count - 1
Dim cameraInfo = myCamera(i)
cameraComboBox.Items.Add(cameraInfo.Name)
Next
If cameraNo < 0 Then
cameraComboBox.SelectedIndex = 0
shutterButton.IsEnabled = True
Else
cameraComboBox.SelectedIndex = cameraNo
shutterButton.IsEnabled = True
End If
Catch
ErrorShow()
End Try
End Function
以降、上記コードの中身を詳細に見ていこう。
まず、非同期処理で行われるためメソッドの先頭にAsyncを追加している。
次に、新しいMediaCaptureのインスタンスを作成する。
MediaCaptureオブジェクトの初期化設定を含む、新しいMediaCaptureInitializationSettingsクラスのインスタンスを作成し、myCaptureInitSettingメンバー変数で参照する。
マイクのDeviceInformation.Idを取得する、AudioDeviceIdをString.Emptyで初期化しておく。
ストリーミングモードを設定する、StreamingCaptureModeプロパティに、オーディオのみのキャプチャを指定する。
MediaCaptureオブジェクトを初期化する、InitializeAsyncメソッドで、オーディオのみのキャプチャを初期化する。
CreateMp4メソッドで、エンコーディングプロファイルを作成する。エンコーディング形式をAutoに指定する。
ピクチャライブラリーのImageVoiceRecordサブフォルダーにアクセスする。このサブフォルダー内のファイルをGetFilesAsyncメソッドで取得する。ファイルが存在すれば、「一覧」アイコンの使用を可能にし、そうでない場合は、使用不可とする。
ImageVoiceRecordサブフォルダー内にThumbs.dbが作成されていたら、これを削除する。このファイルは自動的に作成されるファイルだ。
cameraComboBox内を一度クリアする。
FindAllAsyncメソッドで全てのビデオキャプチャデバイスを列挙して、DeviceInfomationオブジェクトのコレクションである、myCameraコレクション変数で参照する。
Webカメラが実装されている場合は、コレクション変数myCameraが格納しているデバイスの個数分、繰り返し変数iで反復処理を行う。DeviceInfomationの列挙体である、変数cameraInfoで、コレクション変数myCameraが格納しているデバイスを参照させる。
cameraComboBoxにAddメソッドで取得したデバイス名を追加する。フロントカメラやリアカメラを実装しているタブレットPCでは、2つのデバイス名が追加表示されるので、cameraComboBoxのSelectedIndexが0より小さい場合、つまりデバイスが選択されていない場合は、最初のデバイスを選択する。
「写真を撮る」アイコンの使用を可能にする。選択されている場合は、それを選択状態にする。
エラーが発生した場合は、ErrorShowメソッドを実行する。
「写真を撮る」アイコンがタップされた時の処理(shutterButton_Clickメソッド処理)
このアプリの肝となる処理。取った画像に音声を関連付ける。
Private Async Sub shutterButton_Click(sender As Object, e As RoutedEventArgs) Handles shutterButton.Click
PhotoArea.Children.Clear()
MediaElement1.Play()
Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
Dim mySubFolder = Await myFolder.CreateFolderAsync("ImageVoiceRecord", CreationCollisionOption.OpenIfExists)
Dim myFile As StorageFile = Await mySubFolder.CreateFileAsync(DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒") & ".png")
saveImageFileName = DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒") & ".png"
Dim myImageEncodingProperty As New ImageEncodingProperties
myImageEncodingProperty.Subtype = "png"
myImageEncodingProperty.Width = 640
myImageEncodingProperty.Height = 480
‘ このアプリの肝、Webカメラからの画像を保存する
Await myMediaCapture.CapturePhotoToStorageFileAsync(myImageEncodingProperty, myFile)
myPictureFiles = Await mySubFolder.GetFilesAsync()
Index = myPictureFiles.Count
saveBmp = New BitmapImage
saveBmp.SetSource(Await myPictureFiles(Index - 1).OpenReadAsync)
Dim myImage As New Image
With myImage
.Width = 640
.Height = 480
.Source = saveBmp
End With
Dim myStackPanel As New StackPanel
Dim recordButton As New Button
With recordButton
.Content = "録音開始"
.Tag = no.ToString
End With
myStackPanel.Children.Add(myImage)
myStackPanel.Children.Add(recordButton)
PhotoArea.Children.Add(myStackPanel)
AddHandler recordButton.Click, Async Sub(delSender As Object, delArgs As RoutedEventArgs)
Dim wavFolder = KnownFolders.PicturesLibrary
Dim myWavSubFolder = Await wavFolder.CreateFolderAsync("ImageRecordSoundFile", CreationCollisionOption.OpenIfExists)
Dim delDbFile = Await myWavSubFolder.GetFilesAsync
For Each result In delDbFile
If result.Path.Contains("Thumbs.db") Then
Await result.DeleteAsync
End If
Next
Select Case recordButton.Content.ToString
Case "録音開始"
recordTextBlock.Visibility = Xaml.Visibility.Visible
Dim recordFile = Await myWavSubFolder.CreateFileAsync(Path.GetFileNameWithoutExtension(saveImageFileName) & ".mp4", CreationCollisionOption.OpenIfExists)
‘ このアプリの肝、音声ファイルを保存する。
Dim saveRecordeFile As StorageFile = recordFile
Await myRecordMediaCapture.StartRecordToStorageFileAsync(myProfile, saveRecordeFile)
recordButton.Content = "録音終了"
ProgressRing1.IsActive = True
ProgressRing1.IsEnabled = True
Exit Select
Case "録音終了"
Await myRecordMediaCapture.StopRecordAsync
recordTextBlock.Visibility = Xaml.Visibility.Collapsed
ProgressRing1.IsActive = False
ProgressRing1.IsEnabled = False
PhotoArea.Children.Clear()
Exit Select
End Select
End Sub
no += 1
ichiranButton.IsEnabled = True
End Sub
以降、上記コードの中身を詳細に見ていこう。
まず、非同期処理で行われるためメソッドの先頭にAsyncを追加している。
次に、Canvas内を一度クリアして、MediaElement1を再生する。つまり、シャッター音が鳴る動作だ。
ピクチャライブラリーにアクセスし、CreateFolderAsyncメソッドで、ピクチャフォルダー内に「ImageVoiceRecord」というサブフォルダーを作成する。その際、CreationCollisionOption.OpenIfExistsと指定しておくと、同名フォルダーやファイルがある場合は、そのフォルダーやファイル名を返し、ない場合は新規に作成してくれる。
CreateFileAsyncメソッドで現在の「年月日時間分秒.png」ファイルを作成し、ファイルを表すメンバー変数「myFile」で参照しておく。メンバー変数「saveImageFileName」に、このpngファイル名を格納しておく。
イメージストリームの書式を表す新しい、ImageEncodingPropertiesクラスのインスタンス、myImageEncodingPropertyオブジェクトを作成する。書式のサブタイプを表すSubtypeプロパティに「png」を指定し、Widthに「640」、Heightに「480」と指定する。
CapturePhotoToStorageFileAsyncメソッドで、ストレージファイルにフォトをキャプチャする。書式は以下の通りだ。
CapturePhotoToStorageFileAsync(ImageEncodingProperties,IStorageFile)
コレクション変数myPictureFilesにGetFilesAsyncメソッドで、「ImageVoiceRecord」フォルダー内の画像ファイルを取得して格納する。
コレクション変数myPictureFilesが格納しているファイルの個数を、Countプロパティで取得して、メンバー変数Indexに格納する。
新しいBitmapImageクラスのインスタンスsaveBmpを作成する。SetSourceメソッドに、「Await myPictureFiles(Index - 1).OpenReadAsync」と指定して、コレクション変数内のIndexに対応するファイルをOpenReadAsyncメソッドで開き、ソースイメージに指定する。
Indexを-1しているのは、コレクション変数「myPictureFiles」が格納しているファイルのインデックスが0から始まるためだ。
新しいImageのインスタンスmyImageオブジェクトを作成し、Widthに「640」、Heightに「480」と指定し、SourceプロパティにSaveBmpオブジェクトを指定する。
StackPanelの新しいインスタンスmyStackPanelオブジェクトを作成する。
Buttonの新しいインスタンスrecordButtonを作成する。Contentプロパティに「録音開始」と指定し、Tagプロパティに文字列にキャストした、1ずつ増加するメンバー変数「no」の値を指定する。
myStackPanelオブジェクトに、myImageとrecordButtonオブジェクトを追加する。「PhotopArea」という名前を持つ、CanvasにAddメソッドでmyStackPanelオブジェクトを追加する。画像に、「録音開始」ボタンが付加して表示される。
AddHandlerステートメントで、recordButtonがクリックされた時のイベントハンドラを追加する。イベントハンドラ内では、以下の処理を行う。
ピクチャライブラリー内の「ImageRecordSoundFile」フォルダーにアクセスする。このフォルダー内のファイルをGetFilesAsyncメソッドで取得し、delDbFileで参照する。このフォルダー内に「Thumbs.db」というファイルがあれば削除する。
Select Case文を使って、recordButtonのContentプロパティの値で条件分岐を行う。
ボタンの文字が「録音開始」だった場合には、以下の処理を行う。「録音中……」という文字を表示する。CreateFileAsyncメソッドで、メンバー変数「saveImageFileName」の格納しているファイル名から、指定したファイル名のパス文字列を、拡張子を付けずに取得する。
文字列".mp4"と連結してMP4ファイルを作成し、変数recordFileで参照しておく。ファイルを表す変数「saveRecordFile」をrecordFileで初期化しておく。
StartRecordToStorageFileAsyncメソッドで、ストレージファイルへ非同期的な記録を開始する。書式は下記の通りだ。
MediaCapture. StartRecordToStorageFileAsync(記録用のエンコーディング プロファイル,イメージを保存するストレージ ファイル)
recordButtonの表面の文字を「録音終了」に変更し、ProgressRing1を動作させる。録音をしている間はプログレスリングが回る。
ボタンの文字が「録音終了」で、このボタンをタップした場合は以下の処理を行う。StopRecordAsyncメソッドでは、「録音中……」の文字を消し、ProgressRing1の動作を停止する。
「PhotoArea」という名前のCanvas内をクリアする。表示されていた画像も消えてしまう。
メンバー変数「no」の値を1ずつ増加し、「一覧」アイコンの使用を可能にする。
Copyright © ITmedia, Inc. All Rights Reserved.