撮影した動画を専用サーバーに保存し、再生する
2012年1月20日(金)

次に、MainPage.xamlを展開して表示される、MainPage.xaml.vbをダブルクリックしてリスト3のコードを記述します。
ロジックコードを記述する
リスト3 (MainPage.xaml.vb)
Option Strict On
Silverlight ベースのアプリケーション内の描画、テキスト、オーディオ コンテンツ、ビデオ コンテンツなどのメディアを提供するクラスの含まれる、System.Windows.Media名前空間をインポートします。
Imports System.Windows.Media
仮想ファイルシステムを作成および使用するための型が含まれている、System.IO.IsolatedStorage名前空間をインポートします。分離ストレージによって、安全なクライアント側のストレージが提供されます。
Imports System.IO.IsolatedStorage
Imports System.IO
XML to LINQでXMLを処理するクラスの含まれる、System.Xml.Linqをインポートします。
Imports System.Xml.Linq
Partial Public Class MainPage
Inherits PhoneApplicationPage
' コンストラクター
Public Sub New()
InitializeComponent()
End Sub
ビデオ キャプチャに関連付けられている、キャプチャ デバイスから使用するためのメソッドを提供する、新しいCaptureSourceクラスのインスタンス、mySourceをメンバ変数として宣言します。
Dim mySource As New CaptureSource
ビデオキャプチャに Windows PhoneのSilverlight をファイルに保存するために使用する、新しいFileSinkクラスのインスタンス、fsをメンバ変数として宣言します。
Dim fs As New FileSink
ビデオコンテンツで領域を塗りつぶす、VideoBrushクラス型のメンバ変数myVideoBrushを宣言します。
Dim myVideoBrush As VideoBrush
mp4のファイル名を格納するメンバ変数videoFileNameを宣言します。
Dim videoFileName As String
Dim readSize As Integer
ユーザーの専用サーバーに配置したASP.NETのDefault.aspxファイル(後ほど作成します)にfileNameを引数として渡すURLを定数変数として宣言します。
Const UploadUri As String = "ユーザーの専用サーバーURL/VideoFileUpload/Default.aspx?fileName={0}"
ページがアクティブになった時の処理
新しいWebClientのインスタンスmyWebClientオブジェクトを作成します。WebClientクラスは、データの送受信用のメソッドを提供するクラスです。
String またはUriとして指定したリソースをダウンロードする、DownloadStringAsyncメソッドで、サーバー上のVideoInfo.xmlをダウンロードします。キャッシュから読み込まないように、常に新しいデータを読み込むよう、引数に現在の時間、分、秒を指定しています。
AddHandlerステートメントで、非同期のリソース ダウンロード操作の完了時に発生する、DownloadStringCompletedイベントに、イベントハンドラを追加します。イベントハンドラ内では以下の処理を実行します。
ダウンロードが成功しなかった場合は、警告メッセージを出して、処理を抜けます。成功した場合は、XElement.Parseメソッドでダウンロードした結果(resultArgs.Result)を読み込みます。読み込んだ結果はxmldoc変数に格納されます。
読み込んだVideoInfo.xmlから<fileName>要素を取得するクエリを定義します。Countプロパティで<fileName>要素の個数を取得します。その個数が0より大きい場合、つまり<fileName>要素が存在する場合は、[一覧]ボタンの使用を可能とします。それ以外は[一覧]ボタンの使用は不可となります。
Protected Overrides Sub OnNavigatedTo(e As System.Windows.Navigation.NavigationEventArgs)
Dim myWebClient As New WebClient
AddHandler myWebClient.DownloadStringCompleted, Sub(resultSender As Object, resultArgs As DownloadStringCompletedEventArgs)
If resultArgs.Error Is Nothing = False Then
MessageBox.Show("XMLファイルが見つかりません")
Exit Sub
Else
Dim xmldoc As XElement = XElement.Parse(resultArgs.Result)
Dim query = From c In xmldoc.Descendants("fileName") Select c
If query.Count > 0 Then
ichiranButton.IsEnabled = True
Else
ichiranButton.IsEnabled = False
End If
End If
End Sub
myWebClient.DownloadStringAsync(New Uri(String.Format(ユーザーの専用サーバーURL/VideoFileUpload/VideoData/VideoInfo.xml?myTime={0}", DateTime.Now.ToLongTimeString), UriKind.Absolute))
MyBase.OnNavigatedTo(e)
End Sub
[開始]ボタンがタップされた時の処理
保存するビデオのファイル名(変数videoFileNameに格納)を、現在の「年月日時間分秒.mp4」とします。DateTime.Now.ToString("yyyyMMddHHmmmmss")と指定します。
CaptureDeviceConfiguration.GetDefaultVideoCaptureDeviceメソッドで、クライアント上の既定のビデオキャプチャデバイスを表すVideoCaptureDevice オブジェクトを取得します。
CaptureDeviceConfiguration.GetDefaultAudioCaptureDeviceメソッドで、クライアント上の既定のオーディオキャプチャデバイスを表すAudioCaptureDevice オブジェクトを取得します。
CaptureSourceのVideoCaptureDeviceプロパティに既定のビデオキャプチャデバイス(myVideo)を指定します。
CaptureSourceのAudioCaptureDeviceプロパティに既定のオーディオキャプチャデバイス(myAudio)を指定します。
VideoBrushクラスの新しいインスタンス、myVideoBrushオブジェクトを作成します。VideoBrush.SetSourceメソッドで、CaptureSourceを指定し、VideoBrushのソースを設定します。
RectangleのFillプロパティに、VideoBrushソースの設定されたmyVideoBrushを指定し塗りつぶします。これで、Rectangle内にビデオが表示されます。
変数isostoreを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。FileExistsメソッドでvideoFileNameに格納されたファイル名が既に存在する場合は、DeleteFileメソッドで変数videoFileNameに格納されたファイルをいったん削除します。
分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数myStream変数を用意し、IsolatedStorageFile.CreateFileメソッドで、分離ストレージ内に、変数videoFilNameに格納されているファイルを作成します。
FileSinkクラスのIsolatedStorageFileNameプロパティに、変数videoFileNameに格納されているファイル名を指定します。IsolatedStorageFileNameプロパティには、関連付けられている分離ストレージファイルの名前を指定します。
FileSinkクラスのCaptureSourceプロパティに、mySourceオブジェクトを指定します。CaptureSourceプロパティは、この FileSink が関連付けられているキャプチャソースを取得します。
CaptureSourceのStartメソッドで、CaptureSource に関連した全てのキャプチャデバイスからのキャプチャを開始します。[サーバーに保存終了]ボタンの使用を可能にします。
今回の、サーバーにmp4ビデオファイルを保存する処理は、いったん分離ストレージにmp4ファイルを保存し、その後専用サーバーに保存します。専用サーバーに保存した後、分離ストレージ内のmp4関連のファイルを削除しています。
Private Sub startButton_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles startButton.Click
videoFileName = DateTime.Now.ToString("yyyyMMddHHmmmmss") & ".mp4"
Dim myVideo As VideoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice
Dim myAudio As AudioCaptureDevice = CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice
mySource.VideoCaptureDevice = myVideo
mySource.AudioCaptureDevice = myAudio
myVideoBrush = New VideoBrush
myVideoBrush.SetSource(mySource)
Rectangle1.Fill = myVideoBrush
Using isostore As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
If isostore.FileExists(videoFileName) = True Then
isostore.DeleteFile(videoFileName)
Else
Dim myStream As IsolatedStorageFileStream = isostore.CreateFile(videoFileName)
myStream.Close()
End If
End Using
fs.IsolatedStorageFileName = videoFileName
fs.CaptureSource = mySource
mySource.Start()
endButton.IsEnabled = True
End Sub
[サーバーに保存終了]ボタンがタップされた時の処理
CaptureSourceのStopメソッドで、CaptureSourceに関連した全てのキャプチャデバイスからのキャプチャを停止します。
変数myUploadUriを宣言し、定数変数UploadUriに指定した専用サーバーに、引数としてビデオのファイル名を持たし、myUploadUriに格納しておきます。
新しいWebClientのインスタンスmyWebClientオブジェクトを作成します。WebClientクラスは、データの送受信用のメソッドを提供するクラスです。
OpenWriteAsyncメソッドに、専用サーバーのUriとビデオのファイル名で初期化された新しいUriのオブジェクト、myUriを指定します。OpenWriteAsyncメソッドは、指定したリソースにデータを書き込むためのストリームを開くメソッドです。Headersにはvideo/jpegと指定します。
AddHandlerステートメントで、リソースにデータを書き込むためにストリームを開き、非同期操作の完了時に発生する、OpenWriteCompletedイベントにイベントハンドラを指定します。イベントハンドラ内では以下の処理を実行します。
非同期操作中にエラーが発生しなかった場合は、変数myStorageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数myStreamを用意し、IsolatedStorageFileクラスのOpenFileメソッドでビデオのファイルを指定したモード、アクセスで開きます。
ビデオファイルと、データをサーバーに送信するために使用される書き込み可能なストリームを引数にPushDataプロシージャを実行します。ストリームを閉じ、保存した旨のメッセージを表示します。
変数isostorageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。分離ストレージ内にビデオファイルが存在すれば、DeleteFileメソッドで削除します。また分離ストレージ内には.mp4ファイルと同時に.mp4.jpgファイルも作成されますので、.mp4.jpgファイルも削除します。
FileSinkのCaptureSource、IsolatedStorageFileNameプロパティにNothingを指定し、全てのオブジェクトの関連付けを破棄します。[一覧]ボタンの使用を可能にします。
Private Sub endButton_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles endButton.Click
mySource.Stop()
Dim myUploadUri As String = String.Empty
myUploadUri = String.Format(UploadUri, videoFileName)
Dim myWebClient As New WebClient
AddHandler myWebClient.OpenWriteCompleted, Sub(mySender As Object, myArgs As OpenWriteCompletedEventArgs)
If myArgs.Error Is Nothing = True Then
Dim myStorage = IsolatedStorageFile.GetUserStoreForApplication
Dim myStream As IsolatedStorageFileStream = myStorage.OpenFile(videoFileName, FileMode.Open, FileAccess.Read)
PushData(myStream, myArgs.Result)
myArgs.Result.Close()
myStream.Close()
MessageBox.Show(videoFileName & "を保存しました。")
Using isostorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
If isostorage.FileExists(videoFileName) = True Then
isostorage.DeleteFile(videoFileName)
End If
If isostorage.FileExists(videoFileName & ".jpg") = True Then
isostorage.DeleteFile(videoFileName & ".jpg")
End If
End Using
End If
End Sub
myWebClient.Headers(HttpRequestHeader.ContentType) = "video/mpeg"
Dim myUri As Uri = New Uri(myUploadUri, UriKind.Absolute)
myWebClient.OpenWriteAsync(myUri)
fs.CaptureSource = Nothing
fs.IsolatedStorageFileName = Nothing
ichiranButton.IsEnabled = True
End Sub
サーバーに送るためのビデオファイルの情報をストリームに書き込む処理
バイト単位で取得したストリームの長さで初期化された新しいByte型配列変数bufferを作成します。
FileStreamクラスのFileStream.Readメソッドで、リソースに格納されているストリームを読み取りWriteメソッドで書き込みます。InlineAssignHelperヘルパー関数(後述)を使っています。
Stream.Write メソッドの書式は下記の通りです。
Stream.Write(バイト配列(現在のストリームに書き込むバイト数だけコピーします), 現在のストリームへのバイトのコピーを開始する位置を示すbuffer 内のバイトオフセット。インデックス番号は0から始まる,現在のストリームに書き込むバイト数)
Private Sub PushData(input As FileStream, output As Stream)
Dim buffer () As Byte = New Byte(CInt(input.Length)) {}
Dim bytesRead As Integer
While (InlineAssignHelper(bytesRead, input.Read(buffer, 0, buffer.Length))) <> 0
output.Write(buffer, 0, bytesRead)
End While
End Sub
[一覧]ボタンがタップされた時の処理
IchiranPage.xamlに遷移します。
Private Sub ichiranButton_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles ichiranButton.Click
NavigationService.Navigate(New Uri("/IchiranPage.xaml", UriKind.Relative))
End Sub
MSDNのドキュメントで下記のように定義されているInlineAssignHelperヘルパー関数
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
target = value
Return value
End Function
End Class
「撮影した動画を専用サーバーに保存し、再生する」サンプルプログラム
連載バックナンバー
Think ITメルマガ会員登録受付中
Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。


