撮影した動画を専用サーバーに保存し、再生する

次に、IchiranPage.xamlを展開して表示される、IchiranPage.xaml.vbをダブルクリックしてリスト4のコードを記述します。
ロジックコードを記述する
リスト4 (IchiranPage.xaml.vb)
Option Strict On
Imports System.Xml.Linq
Partial Public Class IchiranPage
Inherits PhoneApplicationPage
Public Sub New()
InitializeComponent()
End Sub
ページがアクティブになった時の処理
新しいWebClientのインスタンスmyWebClientオブジェクトを作成します。WebClientクラスは、データの送受信用のメソッドを提供するクラスです。
String またはUriとして指定したリソースをダウンロードする、DownloadStringAsyncメソッドで、サーバー上のVideoInfo.xmlをダウンロードします。キャッシュから読み込まないように、常に新しいデータを読み込むよう、引数に現在の時間、分、秒を指定しています。
AddHandlerステートメントで、非同期のリソース ダウンロード操作の完了時に発生する、DownloadStringCompletedイベントに、イベントハンドラを追加します。イベントハンドラ内では以下の処理を実行します。
ダウンロードが成功しなかった場合は、警告メッセージを出して、処理を抜けます。成功した場合は、XElement.Parseメソッドでダウンロードした結果(resultArgs.Result)を読み込みます。読み込んだ結果はxmldoc変数に格納されます。文字列型の新しいリストであるvideoListオブジェクトを作成します。
Descendantsメソッドで、子孫要素である全ての <fileName> 要素のコレクションに対して、各要素を変数 result に格納しながら、リストであるvideoListオブジェクトにAddメソッドで、<filenNme>要素の値を追加していきます。ListBoxのItemsSourceプロパティにvideoListオブジェクトを指定します。これで、mp4ファイルの一覧がリストボックスに表示されます。
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 videoList As New List(Of String)
For Each result In From c In xmldoc.Descendants("fileName") Select c
videoList.Add(result.Value)
Next
ListBox1.ItemsSource = videoList
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
ListBoxより任意のファイル名が選択された時の処理
ListBoxより選択された項目のインデックス番号を引数にして、VideoPlayerPage.xamlに遷移します。
Private Sub ListBox1_SelectionChanged(sender As Object, e As System.Windows.Controls.SelectionChangedEventArgs) Handles ListBox1.SelectionChanged
NavigationService.Navigate(New Uri(String.Format("/VideoPlayerPage.xaml?Index={0}", ListBox1.SelectedIndex.ToString), UriKind.Relative))
End Sub
End Class
次に、VideoPlayerPage.xamlを展開して表示される、VideoPlayerPage.xaml.vbをダブルクリックしてリスト5のコードを記述します。
ロジックコードを記述する
リスト5 (VideoPlayerPage.xaml.vb)
Option Strict On
Imports System.Xml.Linq
Partial Public Class VideoPlayerPage
Inherits PhoneApplicationPage
Public Sub New()
InitializeComponent()
End Sub
Dim myIndex As Integer
[再生]ボタンがタップされた時の処理
IchiranPage.xamlから渡された文字データを受け取ります。文字データはNavigationContextのQueryStringにDictionary として提供されます。受け取ったインデックスを数値に変換して、変数myIndexに格納しておきます。
新しいWebClientのインスタンスmyWebClientオブジェクトを作成します。WebClientクラスは、データの送受信用のメソッドを提供するクラスです。
String またはUriとして指定したリソースをダウンロードする、DownloadStringAsyncメソッドで、サーバー上のVideoInfo.xmlをダウンロードします。キャッシュから読み込まないように、常に新しいデータを読み込むよう、引数に現在の時間、分、秒を指定しています。
AddHandlerステートメントで、非同期のリソース ダウンロード操作の完了時に発生する、DownloadStringCompletedイベントに、イベントハンドラを追加します。イベントハンドラ内では以下の処理を実行します。
ダウンロードが成功しなかった場合は、警告メッセージを出して、処理を抜けます。成功した場合は、XElement.Parseメソッドでダウンロードした結果(resultArgs.Result)を読み込みます。読み込んだ結果はxmldoc変数に格納されます。
変数myIndexのインデックスに位置する<fileName>要素の値を、変数videoに格納しておきます。MediaElementのSourceプロパティに、ユーザーの専用サーバー保存され、変数videoに格納されているmp4ファイルを指定します。Playメソッドでビデオを再生します。[中止]ボタンの使用を可能にし、[この動画をサーバーから削除]ボタンは使用不可のままです。
Private Sub playButton_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles playButton.Click
Dim myParam As IDictionary(Of String, String) = NavigationContext.QueryString
Dim myIndex As Integer = Integer.Parse(myParam("Index"))
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 video = xmldoc.Descendants("fileName")(myIndex).Value
MediaElement1.Source = New Uri(ユーザーの専用サーバーURL/VideoFileUpload/VideoData/" & video, UriKind.Absolute)
MediaElement.Play
End If
End Sub
myWebClient.DownloadStringAsync(New Uri(String.Format(ユーザーの専用サーバーURLVideoFileUpload/VideoData/VideoInfo.xml?myTime={0}", DateTime.Now.ToLongTimeString), UriKind.Absolute))
stopButton.IsEnabled = True
deleteButton.IsEnabled = False
End Sub
[中止]ボタンがタップされた時の処理
Stopメソッドで再生を中止します。[この動画をサーバーから削除]ボタンの使用を可能にします。[中止]ボタンを[休止]にしたい場合は、Tips集第3弾の「第1回 Videoを撮って分離ストレージに保存し、再生する」を参考にしてください。
Private Sub stopButton_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles stopButton.Click
MediaElement1.Stop()
deleteButton.IsEnabled = True
End Sub
[この動画をサーバーから削除]ボタンがタップされた時の処理
削除確認のメッセージを出し、[OK]の場合の処理です。
新しいWebClientのインスタンスmyWebClientオブジェクトを作成します。WebClientクラスは、データの送受信用のメソッドを提供するクラスです。
HeadersのContentTypeにvideo/mpegと指定します。
UploadStringAsyncメソッドで、文字列にしたmyIndexの値をサーバーにアップロードし、サーバー上のDefault2.aspx(作成方法は後述)を実行します。UploadStringAsyncメソッドは、指定したリソースに指定した文字列(この場合、myIndex.ToStringの値)をアップロードします。
AddHanderステートメントで、非同期の文字列アップロード操作の完了時に発生する、UploadStringCompletedイベントに、イベントハンドラを追加します。イベントハンドラ内では、削除した旨のメッセージを表示します。
MainPage.xamlに遷移します。
Private Sub deleteButton_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles deleteButton.Click
Dim kakunin = MessageBox.Show("この画像を削除しますか?", "削除確認", MessageBoxButton.OKCancel)
Select Case kakunin
Case MessageBoxResult.OK
Dim myWebClient As New WebClient
myWebClient.Headers(HttpRequestHeader.ContentType) = "video/mpeg"
AddHandler myWebClient.UploadStringCompleted, Sub(resultSender As Object, resultArgs As UploadStringCompletedEventArgs)
MessageBox.Show("削除しました")
End Sub
myWebClient.UploadStringAsync(New Uri(ユーザーの専用サーバーのURL/VideoFileUpload/Default2.aspx", UriKind.Absolute), myIndex.ToString)
NavigationService.Navigate(New Uri("/MainPage.xaml", UriKind.Relative))
Case Else
Exit Sub
End Select
End Sub
ビデオが最後まで再生された場合の処理
[この動画をサーバーから削除]ボタンの使用を可能にします。[中止]ボタンの使用を不可とします。
Private Sub MediaElement1_MediaEnded(sender As Object, e As System.Windows.RoutedEventArgs) Handles MediaElement1.MediaEnded
deleteButton.IsEnabled = True
stopButton.IsEnabled = False
End Sub
End Class
ASP.NETページの作成(VideoFileUpload)
VS2010のメニューから、[ファイル(F)/新規作成(N)/Webサイト(W)]と選択し、表示される画面から「ASP.NET Webサイト」を選択します。「webの場所(L)」に今回は「フォルダ名\VideoFileUpload」と指定し[OK]ボタンをクリックします。
ソリューションエクスプローラー内にVideoDataというフォルダを作成し、というルート要素だけのVideoInfo.xmlを作成しておきます。このファイルを作成していないとエラーになりますので、注意してください。
VS2010メニューの[Webサイト(S)/参照の追加(R)]と選択して、System.Xml.Linqを追加しておいてください。
ソリューションエクスプローラー内のDefault.aspxを展開して表示される、Default.aspx.vbにリスト5のコードを記述します。
※このコードをサーバーに配置した際の、アクセス権の設定やIISの設定は各自が行ってください。
ロジックコードを記述する
リスト5 (Default.aspx.vb)
Option Strict On Imports System.IO Imports System.Xml Partial Class _Default Inherits System.Web.UI.Page
ページが読み込まれた時の処理
Windows Phoneのプログラムから送られたfileNameを受け取って、変数fileNameに格納します。
サーバーの物理パスとVideoDataフォルダとfileNameを連結して、変数filePathに格納しておきます。
FileStreamクラスの変数streamを用意し、File.Openメソッドで、filePathに指定したファイルを、Createモードで開き、streamで参照します。Createでは、新しいファイルが作成されます。既にファイルが存在する場合は上書きされます。5120バイトで初期化されたByte型の配列変数bufferを宣言します。POSTされたデータ(Request.InputStream)を取得し、Readメソッドで、リソースに格納されているストリームを読み取りFileStreamにWriteメソッドで書き込みます。これで、現在の「年月日時間分秒.mp4」ファイルが作成されます。InlineAssignHelperヘルパー関数(後述)を使っています。ここで、mp4のビデオファイルが作成されます。次に、作成されたビデオファイルのファイル名を記録する処理を行います。
XElement.LoadメソッドでVideoDataフォルダ内のVideoInfo.xmlを読み込みます。Visual Basic の埋め込み式を用いて、<fileName>要素を作成し、内容テキストとして、埋め込み式の構文である <%= expression %>を用いて変数fileNameの値を指定します。生成したXMLを読み込んだVideoInfo.xmlに追加します。Saveメソッドで保存します。このVideoInfo.xmlファイルが保存された.mp4ファイル名の一覧を記録したファイルです。
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
Dim fileName As String = Context.Request.QueryString("fileName").ToString
Dim filePath As String = Server.MapPath("./") & "VideoData/" & fileName
Using stream As FileStream = File.Open(filePath, FileMode.Create)
Dim buffer As Byte() = New Byte(5120) {}
Dim myByteRead As Integer
While (InlineAssignHelper(myByteRead, Context.Request.InputStream.Read(buffer, 0, buffer.Length))) <> 0
stream.Write(buffer, 0, myByteRead)
End While
stream.Flush()
stream.Close()
Response.Flush()
End Using
Dim xmldoc As XElement = XElement.Load(Server.MapPath("./") & "VideoData/VideoInfo.xml")
Dim addXml As XElement = <fileName><%= fileName %></fileName>
xmldoc.Add(addXml)
xmldoc.Save(Server.MapPath("./") & "VideoData/VideoInfo.xml")
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
次にVS2010メニューの[Webサイト(S)/新しい項目の追加(W)]と選択して、「Webフォーム」を作成します。「名前(N)」はDefault2.aspxのままにしておきます。ソリューションエクスプローラー内のDefault2.aspxを展開して表示される、Default2.aspx.vbにリスト6のコードを記述します。
このDefault2.aspx.vbは、Windows Phoneで選択されたビデオファイルを削除する処理です。
ロジックコードを記述する
リスト6 (Default2.aspx.vb)
Option Strict On Imports System.IO Imports System.Xml.Linq Partial Class Default2 Inherits System.Web.UI.Page
ページが読み込まれた時の処理
StreamReaderクラスでPOSTされたデータ(Request.InputStream)を取得します。StreamReaderクラスは、特定のエンコーディングのバイトストリームを読み込むTextReader を実装するクラスです。
取得したデータの内容をReadToEndメソッドで読み取り、変数readStrに格納しておきます。readStrの値を数値に変換してmyIndex変数に格納します。readStrにはWindows Phoneから送られた、選択されたビデオファイルのインデックスが格納されています。
インデックスに該当する.mp4ファイルと、VideoInfo.xml内の該当するビデオファイルの記録されている、<fileName>要素と内容を削除します。削除したVideoInfo.xmlをSaveメソッドで保存します。
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
Dim reader As New StreamReader(Me.Request.InputStream(), System.Text.Encoding.UTF8)
Dim readStr As String = reader.ReadToEnd
Dim myIndex As Integer = Integer.Parse(readStr)
Dim doc As XElement = XElement.Load(Server.MapPath("./") & "VideoData/VideoInfo.xml")
Dim deleteData = doc.Descendants("fileName")(myIndex)
Dim delImage As String = doc.Descendants("fileName")(myIndex).Value
File.Delete(Server.MapPath("./") & "VideoData/" & delImage)
deleteData.Remove()
doc.Save(Server.MapPath("./") & "VideoData/VideoInfo.xml")
End Sub
End Class
「撮影した動画を専用サーバーに保存し、再生する」サンプルプログラム


