1 out of 2 rated this helpful - Rate this topic

Media on the Windows Phone Platform

This topic contains the following sections.

The new Windows Phone platform has support for a wide range of media standards. Users can easily view photos, listen to FM radio, play just about any kind of music and video file, and even stream media to the device from the web.

If you are familiar with audio and video files and their respective formats, you might be familiar with the term codec. One of the early limitations of mobile devices was that there was limited support for some popular codecs. A codec is similar to a system driver whose sole responsibility is to decode a particular media format. Two very popular music codecs are MP3 and WMA, and almost every portable music device and many car stereos now offer support for these two formats. Most of the digital music that is downloaded from online music stores comes in these formats. It follows that for the Windows Phone platform to have value as a media player, it would make sense that these two audio formats would have to be supported—and they are. In fact, in addition to MP3 and WMA, the Windows Phone platform provides support in some form for many popular media codecs.

MPEG and WMV are two important codecs that are responsible for decoding and playing video. It is important to know exactly what codecs are supported on the phone platform so that you can ensure that users of your applications will never have to take the time to download a media file just to find out that it cannot be played on the device.

To help facilitate support for a wide range of media formats and to ensure the smooth playback of those formats, Windows Phone makes use of the Silverlight platform. Silverlight for the web and for Windows Phone was developed from the ground up with an emphasis on providing rich-media playback capabilities. In addition to those playback capabilities, it was important to provide developers with the ability to easily support popular media formats without having to write a large amount of code for each possible format. Silverlight provides you with a few different choices for handling media playback. For a complete list of supported media codecs visit http://msdn.microsoft.com/en-us/library/ff462087%28v=VS.92%29.aspx

When beginning a media-based application for Windows Phone, perhaps the easiest thing to do is to use the Silverlight MediaElement control. With just a few lines of code, you can easily play or stream video in your app. In this example, you will build a very simple media player that makes use of the control to play videos that have been included in your .xap file. To get started, you need to create a new Windows Phone project using the default project template in Visual Studio 2010, shown in Figure 1. You can use the full version of Visual Studio 2010 or the Express version that is included with the Windows Phone developer tools. Either of those two programs work just fine for the examples in this article. You should call this sample “MediaElement Sample.”

Figure 1: Creating a new Windows Phone project

Referenced Image

When the project finishes loading, the MainPage.xaml file is opened and displayed. It contains the basic shell of a Windows Phone application. Before using the MediaElement control, you first need a media file. In the code accompanying this article is a folder called Videos; right-click the project node in the Solution Explorer, and select Add Existing Item. Navigate to the Videos folder, and select the video_1.wmv file to add the video clip to the project.

Because the MediaElement control is part of the basic Silverlight control package, you do not need to add any namespace information at the top of the file. All you need to do is add the MediaElement XAML declaration to the file. Following is the updated code:

<phone:PhoneApplicationPage 
    x:Class="MediaElement_Sample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="PortraitOrLandscape" Orientation="Landscape"
    shell:SystemTray.IsVisible="True">
    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
             <MediaElement x:Name="MainMedia"  Source="video_1.wmv" />
        </Grid>
    </Grid>
 
    <!--Sample code showing usage of ApplicationBar-->
    <!--<phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
            <shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
            </shell:ApplicationBar.MenuItems>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>-->

</phone:PhoneApplicationPage>

Notice a couple things about the preceding code: First, notice how at the top of the file the SupportedOrientations tag has been modified. Because most video clips are designed for a wide screen view, you can expect that users will want to flip the phone sideways to actually watch most video clips. By changing this setting to PortraitOrLandscape, you allow your application to support viewing the clip in both modes. In this code, the Orientation tag is also set to Landscape by default, which guides the user to flip the phone as soon as the application starts. This maximizes the viewing area of the MediaElement control. If you were to run this application at this point, the user would see the video being loaded and ultimately played as shown in Figure 2. However, as you can see, you have no way to pause, stop, fast forward, or rewind the video.

Figure 2: MediaElement Sample application with no interface controls

Referenced Image

Although the video plays, the user does not have much of a user interface to work with and has no way to manipulate the video stream. Take a look at fixing that. When using the MediaElement as your primary video viewer in your application, no default controls are displayed for manipulating the video stream. You must supply these on your own. For a media-based application, the Windows Phone application bar provides the best place to add that functionality. If you are not familiar with the application bar, it is basically a built-in toolbar available to all applications as a place to put buttons for commonly used user interface functions. For this example, it is a perfect place to put buttons for stop, play/pause, fast forward, and rewind. If you take a look at the MainPage.xaml code again, you can see the following area:

<!--Sample code showing usage of ApplicationBar-->
    <!--<phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
            <shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
            </shell:ApplicationBar.MenuItems>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>-->

As you can see, a default application bar basically comes for free with the default Windows Phone application project template; it is just commented out. The application bar provides you with a choice of using only icon buttons, full menu items, or both. For this application, you just want some buttons that can manipulate the video stream. The MediaElement control provides functionality to do this via Stop, Start, Play (and so on) methods. Now you just need to hook everything up.

But first, where can you get good icon images that represent these tasks? Well, if you are not an artist or do not have access to one, you can find a great set of icons available for free in the SDK tools that you installed for Windows Phone. Just look in the following location: C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.0\Icons. The Icons folder contains folders that hold royalty-free icon files that you can use in your own applications. For this application, you will be adding the icons that match the operations you are adding.

Create an Images folder in the project, and then right-click the folder and choose the Add Existing Items option. Next select the .png files in the “dark” directory that correspond to rewind, stop, pause, fast forward and play, then click Add. Now each of the icon images is added to the project. After you complete the copy/paste operation, be sure to select all of the icon files and set the build action to Content in the Properties window, as shown in Figure 3.

Figure 3: Application Bar icons and build action

Referenced Image

After you have the icon files in place, you need to update the application bar code to use them. Uncomment the ApplicationBar area of code in MainPage.xaml, and update it to the following:

<phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="False">
            <shell:ApplicationBarIconButton x:Name="Rewind" IconUri="/Images/appbar.transport.rew.rest.png" Text="Rewind"/>
            <shell:ApplicationBarIconButton x:Name="Stop" IconUri="/Images/appbar.stop.rest.png" Text="Stop"/>
            <shell:ApplicationBarIconButton x:Name="PlayPause" IconUri="/Images/appbar.transport.pause.rest.png" Text="Play/Pause"/>
            <shell:ApplicationBarIconButton x:Name="FastForward" IconUri="/Images/appbar.transport.ff.rest.png" Text="Fast Forward"/>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>

Because the video will start playing as soon as the application is running, you should default the Play/Pause button to the paused state. Now all that is left is to actually handle the event when the user clicks one of these application bar choices.

Open up MainPage.xaml.cs, and first add a new event handler for the Loaded event of the page in the constructor area of the class:

public MainPage()
{
     InitializeComponent();
     this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}

I find this to be the best place to add additional event handlers for other controls. This ensures that those controls—in this case, ApplicationBarIconButton controls—are ready and available. Before using the buttons, you need to add a couple of using statements at the top of the file. The following code gives you access to the ApplicationBarIconButton class:

using Microsoft.Phone.Shell;
using Microsoft.Phone.Controls;

In this loaded event, you need to add additional Click event handlers for each of the icons. Following is the updated code for the MainPage_Loaded method:

private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
     // Rewind
     (ApplicationBar.Buttons[0] as 
ApplicationBarIconButton).Click += (eventSender, eventArgs) =>
     {
     };

     // Stop
     (ApplicationBar.Buttons[1] as 
ApplicationBarIconButton).Click += (eventSender, eventArgs) =>
     {
     };

     // Play/Pause
     (ApplicationBar.Buttons[2] as 
ApplicationBarIconButton).Click += (eventSender, eventArgs) =>
     {
     };

     // Fast Forward
     (ApplicationBar.Buttons[3] as 
ApplicationBarIconButton).Click += (eventSender, eventArgs) =>
     {
     };

}

You might have noticed that instead of adding full event handler methods for each Click event, I am making use of the new Lambda Expression syntax feature of C#. You can find more information about this new feature by visiting: http://msdn.microsoft.com/en-us/library/bb397687.aspx. This is really just a personal preference, and nothing is wrong with adding full-blown methods for each of these Click events. In this case, because each handler does not contain a large amount of code, it can be easier to just perform the logic using Lambda Expression syntax. Also, instead of referencing the individual icon buttons by name as you normally would with Silverlight controls, you must access the icon buttons by their appropriate index. The ApplicationBar instance provides a Buttons property that contains the actual instances of each ApplicationIconButton object. After you index it, you can simply cast it to the ApplicationIconButton type and access its properties and events normally.

At this point, whenever a user clicks one of the application bar icons, your program is notified in these event handlers. Logically, you want the Stop handler to stop the video, fast forward, and rewind to perform its traditional operations, and PlayPause to pause a running video and play a currently stopped or paused video. The only real issue is that when the user clicks the Stop button or the Pause button, you will want to actually change the image displayed for the PlayPause choice. Again, nothing too complex is involved here, and the MediaElement control provides all the real work of actually manipulating the video stream. Using the MediaElement functions to do the work results in the following updated code:

private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
     // Rewind
     (ApplicationBar.Buttons[0] as 
ApplicationBarIconButton).Click += (eventSender, eventArgs) =>
     {
          if (MainMedia.CanSeek)
               MainMedia.Position -= new TimeSpan(0, 0, 1);
     };

     // Stop
     (ApplicationBar.Buttons[1] as 
ApplicationBarIconButton).Click += (eventSender, eventArgs) =>
     {
          MainMedia.Stop();
          MainMedia.Position = new TimeSpan(0, 0, 0);

          (ApplicationBar.Buttons[2] as ApplicationBarIconButton).IconUri = new Uri("/Images/appbar.transport.play.rest.png", UriKind.Relative);
     };

     // Play/Pause
     (ApplicationBar.Buttons[2] as 
ApplicationBarIconButton).Click += (eventSender, eventArgs) =>
     {
          if (MainMedia.CurrentState == MediaElementState.Paused ||
              MainMedia.CurrentState == MediaElementState.Stopped)
          {
               MainMedia.Play();

               // Update the icon to reflect the current state.

               (eventSender as ApplicationBarIconButton).IconUri = new Uri("/Images/appbar.transport.pause.rest.png", UriKind.Relative);
          }
          else if (MainMedia.CurrentState == MediaElementState.Playing)
          {
               MainMedia.Pause();
               (eventSender as ApplicationBarIconButton).IconUri = new Uri("/Images/appbar.transport.play.rest.png", UriKind.Relative);
          }
     };

     // Fast forward
     (ApplicationBar.Buttons[3] as 
ApplicationBarIconButton).Click += (eventSender, eventArgs) =>
     {
          if( MainMedia.CanSeek )
               MainMedia.Position += new TimeSpan(0, 0, 1);
     };
}

Looking at the code, notice a couple of things. First, switching the currently displayed icon is as simple as updating the IconUri property of the ApplicationBarIconButton control. Second, you should always check to see whether the media source supports operations like fast forward and rewind. This can be done by checking the CanSeek property of the MediaElement control. Finally, in this example, fast forwarding and rewinding do not advance the video very much, only one second. You can easily change this by setting the Position property of the MediaElement to a new TimeSpan value of your choice. If you build and run the application in the Windows Phone emulator at this point, you should see something similar to Figure 4.

Figure 4: MediaElement Sample application running with ApplicationBar

Referenced Image

As you run the application in the emulator, try some of the various operations using the application bar buttons. Notice how the video stream responds accordingly. Now if you have an actual unlocked Windows Phone device and have a paid registration to the App Hub site, you can easily deploy and run this sample on the physical hardware. In Visual Studio 2010, you can do this by simply changing the target deployment option from the emulator to a connected device. Figure 5 shows where this is changed in Visual Studio 2010.

Figure 5: Change application deployment option

Referenced Image

Alternatively, you have the option of using the deployment tool that comes with the Windows Phone tools. It is called “Application Deployment” and can be found under the menu options after you have installed the tools. Figure 6 shows the included Application Deployment tool.

Figure 6: Application Deployment tool

Referenced Image

After you have selected your deployment option, you also need to have the Windows Zune software running to actually deploy to the device. Later in this article, you will see an alternate deployment method that does not require the use of the Zune software.

Now that you have mastered the use of the MediaElement control, take a look at another option at your disposal for playing media in your Windows Phone 7 applications—the MediaPlayerLauncher task.

Another way to play video and media files without having to set up your own player controls is to use the MediaPlayerLauncher task. The MediaPlayerLauncher task provides users with built-in playback controls by using the internal Windows Phone media playback capabilities. Take a look at an example.

Create a new Windows Phone project called “MediaPlayerLauncher Sample.” When the project initialization is complete, open the MainPage.xaml.cs file. Unlike when using the Silverlight MediaElement control, you cannot simply declare XAML code and have the media play. The MediaPlayerLauncher task, as with any of the Windows Phone Task objects, must be initialized and launched in the code behind. In this example, you set the MediaPlayerLauncher instance to play an audio podcast from the Channel 9 site. First create an event handler for the page’s Loaded event in the constructor, just as you did in the previous example, as follows:

// Constructor
public MainPage()
{
     InitializeComponent();
     this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}

Next you need to add the required using statement to bring the MediaPlayerLauncher and other tasks into your code. At the top of the file, add the following:

using Microsoft.Phone.Tasks;

Now in the MainPage_Loaded event handler, add the following code to properly initialize the task:

private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
     MediaPlayerLauncher launcher = new MediaPlayerLauncher();

     launcher.Media = new Uri("http://ecn.channel9.msdn.com/o9/ch9/6/2/5/2/0/5/msdnflash010.mp3", UriKind.Absolute);
     launcher.Controls = MediaPlaybackControls.All;
     launcher.Show();
}

If you were to now build and run the application in the emulator, you would see that the podcast begins playing and that the default media controls are now available. However, what you do not see is your application title or any other controls that you might have added to your page. This is because, unlike the Silverlight MediaElement control, the MediaPlayerLauncher task and all other tasks launch over your application. This means that when the user is presented with media using this launcher, technically the user is no longer in your application. This is one of the drawbacks to using the launcher task versus the MediaElement control. If you need complete control over the media experience provided by your application, the MediaPlayerLauncher somewhat limits you. In fact, the only way for the user to get back to your application is through the use of the Back button on the hardware interface. As you can imagine, this might not be an ideal scenario for all applications, so although you gain the built-in playback buttons, you do lose control over how the media is presented in your application.

Continue on to the Next Article: Integrating with a WCF Web Service

Did you find this helpful?
(1500 characters remaining)