/*
* 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;
}
}
}
}