MOBILE

Windows Phone 7 Development : Working with Video (part 2) - Coding the Application

3/18/2011 9:30:13 AM

3. Coding the Application

In Solution Explorer, open MainPage.xaml.cs and replace the code you find there with the following C# code blocks that will implement the media player's functions.

3.1. Specifying the Namespaces

Begin by listing the namespaces the application will use. Notice the inclusion of Microsoft.Phone.Tasks that will allow us to launch Windows Phone's default media player. As for the MediaElement, it is declared in the XAML page, which you will simply reference here by the control's name.

using System;
using System.Windows;
using System.Windows.Media;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Tasks;

namespace MediaPlayerDemo
{
public partial class MainPage : PhoneApplicationPage

3.2. Initializing Variables

The variable _updatingMediaTimeline is an extremely important variable that stops the infinite loop in this demo. By setting _updatingMediaTimeline to true while the media timeline (Slider control) is being updated during the CompositionTarget.Rendering event, the media's backward and forward event will wait to be processed until the timeline update is completed. Another way to look at this complexity is to see the purpose of the Slider control that is responsible for displaying the timeline of the media being played. But the Slider control is also responsible for allowing the user to interact to drag the slider forward or backward in order to move the media position. _updatingMediaTimeline will allow only one specific behavior to happen in the Slider control, thereby avoiding unwanted application behavior.

private bool _updatingMediaTimeline;

public MainPage()
{
InitializeComponent();

_updatingMediaTimeline = false;

// rewinds the media player to the beginning
mediaPlayer.Position = System.TimeSpan.FromSeconds(0);

3.3. Handling Video Download Progress

As the video file download progresses, you will be receiving the percentage of the file got downloaded and you will be displaying the progress updates back to the user by updating the lblDownload.

// Download indicator
mediaPlayer.DownloadProgressChanged += (s, e) =>
{
lblDownload.Text = string.Format("Downloading {0:0.0%}",
mediaPlayer.DownloadProgress);
};


3.4. Handling Video Buffering

You will be setting video BufferingTime property and as the video buffering time progresses you will receive a callback where you will update lblBuffering.

// Handle media buffering
mediaPlayer.BufferingTime =
TimeSpan.FromSeconds(Convert.ToDouble(txtBufferingTime.Text));
mediaPlayer.BufferingProgressChanged += (s, e) =>
{
lblBuffering.Text = string.Format("Buffering {0:0.0%}",
mediaPlayer.BufferingProgress);
};


3.5. Showing Time Elapsed in the Media Player

CompositionTarget.Rendering is a frame-based event that will fire once per frame, allowing you to update the media timeline (Slider control) that reflects how much of the media is played. By default the event will fire 60 times in one second. You can check this by checking the value of Application.Current.Host.Settings.MaxFrameRate. By using the CompositionTarget.Rendering event, you will be able to see the smooth media player timeline filling up as the media plays.

// Updates the media time line (slider control) with total time played
// and updates the status with the time played
CompositionTarget.Rendering += (s, e) =>
{
_updatingMediaTimeline = true;
TimeSpan duration = mediaPlayer.NaturalDuration.TimeSpan;
if (duration.TotalSeconds != 0)
{
double percentComplete =
mediaPlayer.Position.TotalSeconds / duration.TotalSeconds;
mediaTimeline.Value = percentComplete;
TimeSpan mediaTime = mediaPlayer.Position;
string text = string.Format("{0:00}:{1:00}",
(mediaTime.Hours * 60) + mediaTime.Minutes, mediaTime.Seconds);

if (lblStatus.Text != text)


lblStatus.Text = text;

_updatingMediaTimeline = false;
}
};
}

When defining the event handler of CompositionTarget.Rendering, you can use the lambda expression to create a delegate that contains the programming logic. For example, you can rewrite CompositionTarget.Rendering += (s, e) => { ... } by first declaring the event handler CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering) and then creating a method void CompositionTarget_Rendering(object sender, EventArgs e) { ... }. Using the lambda expression technique makes the code much more readable and in this demo project gives you the ability to group the relevant code together. For more information on the lambda expression, please refer to http://msdn.microsoft.com/en-us/library/bb397687.aspx.


3.6. Implementing the Pause Button

When the Pause button is clicked, invoke MediaElement.Pause to pause the media player. Notice also here that you are updating the Status label, communicating to the user the media is in pause mode. Also notice that for unknown reasons, the media player might not be able to pause. You can use mediaPlayer.CanPause to make sure you can pause and otherwise set the Status label to warn the user it could not pause.

private void btnPause_Click(object sender, RoutedEventArgs e)
{
if (mediaPlayer.CanPause)
{
mediaPlayer.Pause();
lblStatus.Text = "Paused";
}
else
{
lblStatus.Text = "Can not be Paused. Please try again!";
}
}

3.7. Implementing the Stop Button

When the stop button is clicked, invoke MediaElement.Stop to stop the media player and then rewind the media player back to the beginning and update the Status label as "Stopped."

private void btnStop_Click(object sender, RoutedEventArgs e)
{
mediaPlayer.Stop();

mediaPlayer.Position = System.TimeSpan.FromSeconds(0);
lblStatus.Text = "Stopped";
}

3.8. Implementing the Play Button

When the play button is clicked, invoke MediaElement.Play to play the media player.

private void btnPlay_Click(object sender, RoutedEventArgs e)
{
mediaPlayer.Play();
}

3.9. Implementing the Mute Button

When the Mute button is clicked, set MediaElement.IsMuted to true in order to mute the sound or set it to false to turn on the sound.

private void btnMute_Click(object sender, RoutedEventArgs e)
{
if (lblSoundStatus.Text.Equals("Sound On", StringComparison.CurrentCultureIgnoreCase))
{
lblSoundStatus.Text = "Sound Off";
mediaPlayer.IsMuted = true;
}
else
{
lblSoundStatus.Text = "Sound On";
mediaPlayer.IsMuted = false;
}

}


NOTE

To mute the player, you could have set MediaElement.Volume to zero instead of setting the IsMuted property to true, as we did in our example.

3.10. Implementing Seek

When the Slider control that displays the timeline of the media is clicked or dragged, MediaElement.Position moves either forward or backward, depending on the user's input on the Slider control. See Figure 15-3 for dragging the slider to the right in order to move forward in the video timeline.

private void mediaTimeline_ValueChanged(object sender,
RoutedPropertyChangedEventArgs<double> e)



{
if (!_updatingMediaTimeline && mediaPlayer.CanSeek)
{
TimeSpan duration = mediaPlayer.NaturalDuration.TimeSpan;
int newPosition = (int)(duration.TotalSeconds * mediaTimeline.Value);
mediaPlayer.Position = new TimeSpan(0, 0, newPosition);
}
}


Figure 3. Dragging the slider to skip the video

NOTE

Using MediaElement.Position you can jump to any part of the media.

3.11. Implementing the MediaPlayerLauncher

When the MediaPlayerLauncher button is clicked, invoke the MediaPlayerLauncher task to launch the default Windows Phone media player.

private void btnMediaPlayerLauncher_Click(object sender, RoutedEventArgs e)
{
MediaPlayerLauncher player = new MediaPlayerLauncher();
player.Media = new
Uri("http://ecn.channel9.msdn.com/o9/ch9/7/8/2/9/1/5/
ARCastMDISilverlightGridComputing_ch9.wmv");
//player.Media =
// new Uri("ARCastMDISilverlightGridComputing_ch9.wmv",
// UriKind.Relative);
//player.Location = MediaLocationType.Data;
player.Show();
}

NOTE

Notice the commented code where MediaPlayerLauncher is going to play the content that is part of the application. player.Location is set to MediaLocationType.Data, which means that it will look at the isolated storage for the file named ARCastMDISilverlightGridComputing_ch9.wmv. If you set player.Location to MediaLocationType.Install, the media file must be added to the application as the content and also the media source's Uri must have UriKind.Relative, which basically means the file is part of the application. The only problem with this is that the size of the application install will get much bigger.

3.12. Testing the Finished Application

To test the application, press F5. The result should resemble Figure 1. Try clicking each button: Play, Pause, Stop, and Mute. Also, as the movie plays, take note of the buffering and downloading progress status. You can also drag the slider back and forth to skip around the movie scenes. You can also put your own favorite movie link if you know of any.

In this first demo, you learned to create a custom media player and then learned to launch the default Windows Phone media player. Both MediaElement and MediaPlayerLauncher accessed the video content on the Web because typically video files are very big. But if you are adding simple sound effects to an application, it is not always ideal to download the contents from the Web when you can simply package the sound along with the application. This is especially true if you are planning to create a game where all the graphical and media assets are packaged as the part of the application. In the next demo, you will learn to add sound effects to an application.

Other  
  •  Windows Phone 7 Development : Plotting an Address on a Bing Maps Map and Working with the Bing Maps Service
  •  Windows Phone 7 Development : Using GeoCoordinateWatcher and the Bing Maps Control to Track Your Movements
  •  iPhone Application Development : Creating a Multi-View Toolbar Application (part 3) - Adding Toolbar Controls
  •  iPhone Application Development : Creating a Multi-View Toolbar Application (part 2) - Instantiating the View Controllers
  •  iPhone Application Development : Creating a Multi-View Toolbar Application (part 1)
  •  Windows Phone 7 Development : Using Location Services - Simulating the Location Service
  •  Introducing the Windows Phone Location Service and Mapping APIs
  •  iPhone Application Development : Implementing a Custom Picker View (part 4) - Tweaking the Picker UI
  •  iPhone Application Development : Implementing a Custom Picker View (part 3) - Reacting to a Picker View Choice
  •  iPhone Application Development : Implementing a Custom Picker View (part 2)
  •  iPhone Application Development : Implementing a Custom Picker View (part 1)
  •  Windows Phone 7 Development : Isolated Storage - Working with Isolated Storage Settings
  •  Mobile Application Security : WebOS Security - Permissions and User Controls
  •  Mobile Application Security : WebOS Security - Code Security
  •  Windows Phone 7 Development : Working with Isolated Directory Storage (part 2)
  •  Windows Phone 7 Development : Working with Isolated Directory Storage (part 1)
  •  iPhone Application Development : Making Multivalue Choices with Pickers - Using Date Pickers (part 3)
  •  iPhone Application Development : Making Multivalue Choices with Pickers - Using Date Pickers (part 2) - Adding a Date Picker
  •  iPhone Application Development : Making Multivalue Choices with Pickers - Using Date Pickers (part 1)
  •  iPhone Application Development : Making Multivalue Choices with Pickers - Understanding Pickers
  •  
    Top 10
    Testing New Technologies – March 2013 (Part 2)
    Testing New Technologies – March 2013 (Part 1)
    Acer Aspire V5 Touch – Best Of All Worlds
    Asus Taichi - The Incredible Fusion Of Notebook And Tablet
    Dell XPS 12 Convertible Ultrabook - Is Its Stunning Two-In-One Design?
    Phone On Your Wrist!
    Windows Phone 8X by HTC
    Beats By Dr Dre Wireless Headphones - Beat The Wires
    In-Ear Headphones - Top Up Your Mobile
    Cool Stuffs Of The Month – March 2013 (Part 3) : Acer Iconia W510, Simmtronics SIMM X720, PANASONIC AE 8000
    Most View
    Getting Familiar with AJAX
    Understanding Mobility Enhancements in Exchange Server 2010
    IIS 7.0 : Managing Application Pools (part 3) - Advanced Application Pool Configuration, Monitoring Application Pool Recycling Events
    Windows Server 2003 : Building a Nameserver (part 2) - Creating and Editing CNAME Records, Creating and Editing MX Records, Generating a Reverse Lookup Zone, Creating and Editing PTR Records
    Happy iMas (Part 1)
    SQL Server 2005 : Basic OLAP - Building Your First Cube (part 2) - Adding a Data Source View
    The Most Wanted Products That We Cannot Wait! – November 2012
    Microsoft Windows Server 2003 : Maintaining the Operating System - Administering Software Licenses
    Buying Advice: DSLR Lens
    SQL Server 2008 : Programming Objects - Implementing Stored Procedures
    Android Security : Files and Preferences
    How To Specify And Build A Media PC (Part 3) - Step-By-Step Guide
    Epic Moments in Sports (Part 1)
    Personalizing Windows 8 : Adding Badges
    The other side of A Galaxy
    Windows 7 : Protecting Your Network from Hackers and Snoops - Configuring Windows Firewall
    Not iPad 3 – Reasons why Apple chose to name its new tablet, “the new iPAD”
    GPS Log Book - Record Journey Automatically In Car
    Managing Exchange Server 2010 : The Exchange Control Panel (ECP)
    Windows Vista : Performing Local PC Administration (part 1) - Working with workstation administration tools