/* * PhoneGap is available under *either* the terms of the modified BSD license *or* the * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text. * * Copyright (c) 2005-2011, Nitobi Software Inc. * Copyright (c) 2011, Microsoft Corporation * Copyright (c) 2011, Sergey Grebnov. */ using System; using System.IO; using System.IO.IsolatedStorage; using System.Windows.Media; using System.Windows.Navigation; using Microsoft.Phone.Controls; using Microsoft.Phone.Shell; using Microsoft.Phone.Tasks; using VideoResult = WP7GapClassLib.PhoneGap.UI.VideoCaptureTask.VideoResult; namespace WP7GapClassLib.PhoneGap.UI { public partial class VideoRecorder : PhoneApplicationPage { #region Constants /// /// Caption for record button in ready state /// private const string RecordingStartCaption = "Record"; /// /// Caption for record button in recording state /// private const string RecordingStopCaption = "Stop"; /// /// Start record icon URI /// private const string StartIconUri = "/Images/appbar.feature.video.rest.png"; /// /// Stop record icon URI /// private const string StopIconUri = "/Images/appbar.stop.rest.png"; /// /// Folder to save video clips /// private const string LocalFolderName = "VideoCache"; /// /// File name format /// private const string FileNameFormat = "Video-{0}.mp4"; /// /// Temporary file name /// private const string defaultFileName = "NewVideoFile.mp4"; #endregion #region Callbacks /// /// Occurs when a video recording task is completed. /// public event EventHandler Completed; #endregion #region Fields /// /// Viewfinder for capturing video /// private VideoBrush videoRecorderBrush; /// /// Path to save video clip /// private string filePath; /// /// Source for capturing video. /// private CaptureSource captureSource; /// /// Video device /// private VideoCaptureDevice videoCaptureDevice; /// /// File sink so save recording video in Isolated Storage /// private FileSink fileSink; /// /// For managing button and application state /// private enum VideoState { Initialized, Ready, Recording, CameraNotSupported }; /// /// Current video state /// private VideoState currentVideoState; /// /// Stream to return result /// private MemoryStream memoryStream; /// /// Recording result, dispatched back when recording page is closed /// private VideoResult result = new VideoResult(TaskResult.Cancel); #endregion /// /// Initializes components /// public VideoRecorder() { InitializeComponent(); PhoneAppBar = (ApplicationBar)ApplicationBar; PhoneAppBar.IsVisible = true; btnStartRecording = ((ApplicationBarIconButton)ApplicationBar.Buttons[0]); btnTakeVideo = ((ApplicationBarIconButton)ApplicationBar.Buttons[1]); } /// /// Initializes the video recorder then page is loading /// protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); this.InitializeVideoRecorder(); } /// /// Disposes camera and media objects then leave the page /// protected override void OnNavigatedFrom(NavigationEventArgs e) { this.DisposeVideoRecorder(); if (this.Completed != null) { this.Completed(this, result); } base.OnNavigatedFrom(e); } /// /// Handles TakeVideo button click /// private void TakeVideo_Click(object sender, EventArgs e) { this.result = this.SaveVideoClip(); this.NavigateBack(); } private void NavigateBack() { if (this.NavigationService.CanGoBack) { this.NavigationService.GoBack(); } } /// /// Resaves video clip from temporary directory to persistent /// private VideoResult SaveVideoClip() { try { using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) { if (string.IsNullOrEmpty(filePath) || (!isoFile.FileExists(filePath))) { return new VideoResult(TaskResult.Cancel); } string fileName = String.Format(FileNameFormat, Guid.NewGuid().ToString()); string newPath = Path.Combine("/" + LocalFolderName + "/", fileName); isoFile.CopyFile(filePath,newPath); isoFile.DeleteFile(filePath); memoryStream = new MemoryStream(); using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream(newPath,FileMode.Open,isoFile)) { fileStream.CopyTo(memoryStream); } VideoResult result = new VideoResult(TaskResult.OK); result.VideoFileName = newPath; result.VideoFile = this.memoryStream; result.VideoFile.Seek(0, SeekOrigin.Begin); return result; } } catch (Exception e) { return new VideoResult(TaskResult.None); } } /// /// Updates the buttons on the UI thread based on current state. /// /// current UI state private void UpdateUI(VideoState currentState) { Dispatcher.BeginInvoke(delegate { switch (currentState) { case VideoState.CameraNotSupported: btnStartRecording.IsEnabled = false; btnTakeVideo.IsEnabled = false; break; case VideoState.Initialized: btnStartRecording.Text = RecordingStartCaption; btnStartRecording.IconUri = new Uri(StartIconUri, UriKind.Relative); btnTakeVideo.IsEnabled = false; break; case VideoState.Ready: btnStartRecording.Text = RecordingStartCaption; btnStartRecording.IconUri = new Uri(StartIconUri, UriKind.Relative); btnTakeVideo.IsEnabled = true; break; case VideoState.Recording: btnStartRecording.Text = RecordingStopCaption; btnStartRecording.IconUri = new Uri(StopIconUri,UriKind.Relative); btnTakeVideo.IsEnabled = false; break; default: break; } currentVideoState = currentState; }); } /// /// Initializes VideoRecorder /// public void InitializeVideoRecorder() { if (captureSource == null) { captureSource = new CaptureSource(); fileSink = new FileSink(); videoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice(); if (videoCaptureDevice != null) { videoRecorderBrush = new VideoBrush(); videoRecorderBrush.SetSource(captureSource); viewfinderRectangle.Fill = videoRecorderBrush; captureSource.Start(); this.UpdateUI(VideoState.Initialized); } else { this.UpdateUI(VideoState.CameraNotSupported); } } } /// /// Sets recording state: start recording /// private void StartVideoRecording() { try { if ((captureSource.VideoCaptureDevice != null) && (captureSource.State == CaptureState.Started)) { captureSource.Stop(); fileSink.CaptureSource = captureSource; filePath = System.IO.Path.Combine("/" + LocalFolderName + "/", defaultFileName); using(IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) { if (!isoFile.DirectoryExists(LocalFolderName)) { isoFile.CreateDirectory(LocalFolderName); } if (isoFile.FileExists(filePath)) { isoFile.DeleteFile(filePath); } } fileSink.IsolatedStorageFileName = filePath; } if (captureSource.VideoCaptureDevice != null && captureSource.State == CaptureState.Stopped) { captureSource.Start(); } this.UpdateUI(VideoState.Recording); } catch (Exception e) { this.result = new VideoResult(TaskResult.None); this.NavigateBack(); } } /// /// Sets the recording state: stop recording /// private void StopVideoRecording() { try { if ((captureSource.VideoCaptureDevice != null) && (captureSource.State == CaptureState.Started)) { captureSource.Stop(); fileSink.CaptureSource = null; fileSink.IsolatedStorageFileName = null; this.StartVideoPreview(); } } catch (Exception e) { this.result = new VideoResult(TaskResult.None); this.NavigateBack(); } } /// /// Sets the recording state: display the video on the viewfinder. /// private void StartVideoPreview() { try { if ((captureSource.VideoCaptureDevice != null) && (captureSource.State == CaptureState.Stopped)) { videoRecorderBrush.SetSource(captureSource); viewfinderRectangle.Fill = videoRecorderBrush; captureSource.Start(); this.UpdateUI(VideoState.Ready); } } catch (Exception e) { this.result = new VideoResult(TaskResult.None); this.NavigateBack(); } } /// /// Starts video recording /// private void StartRecording_Click(object sender, EventArgs e) { if (currentVideoState == VideoState.Recording) { this.StopVideoRecording(); } else { this.StartVideoRecording(); } } /// /// Releases resources /// private void DisposeVideoRecorder() { if (captureSource != null) { if ((captureSource.VideoCaptureDevice != null) && (captureSource.State == CaptureState.Started)) { captureSource.Stop(); } captureSource = null; videoCaptureDevice = null; fileSink = null; videoRecorderBrush = null; } } } }