Ø Playing Video
Subservient Cat is a "virtual pet" application. Unlike most cats, Subservient Cat obeys the owner's instructions very much! However, the user needs to know which commands it can respond to. It has a bit of a game element, because users must discover these commands through their own exploration.
The application uses a video clip of a black cat (named Boo) as the main interface. Therefore, this is a good example for learning how to play a video in an application through the MediaElement control.
Playing Video with MediaElement
If we want users to be able to play, pause and other control operations on the video, the best choice is to use the Media Player launcher. However, if we want to play video content in the application page, we can choose to use MediaElement. MediaElement is a UI control, it can play video files through its Source property. E.g:
The path of the video source file can point to a file included in the project, or an online network video. By default, MediaElement automatically plays the video when it is loaded (for network video, as long as enough video stream is buffered, it starts to play), but we can change this setting by setting the AutoPlay property to false. In the code behind, we can use the Play, Pause and Stop methods of MediaElement. It also has the Position attribute, which is used to indicate the current playback position (identified by a time period value). In addition, if the video supports search, we can set Position as a playback time point. Just like other Silverlight elements, MediaElement supports transformation and cutting operations, and it can also be mixed with other elements. From the interface point of view, using the MediaElement element is straightforward. However, there are many things that need to be explained. Here are five points to note:
1. The frame of an application can only contain one MediaElement! Using multiple MediaElements in a frame is not supported, and the program will return failure. Note that this restriction is stricter than using one MediaElement for a page; at any time, only one MediaElement can be loaded onto the frame (regardless of whether the MediaElement is in a stopped, paused or playing state). Therefore, only when multiple pages do not appear in the navigation stack at the same time can each page contain its own MediaElement. Otherwise, if we need to play multiple videos, then we need to reuse the same MediaElement, or remove the unused MediaElement from the element tree.
2. When including the video into the application, make sure its Build Action attribute value is set to Content, not Resource! Doing so can improve the performance of video startup. When a video file is embedded as a resource, before it is played, the application will compress it first, and then temporarily store it in the isolated storage space (for audio files used by MediaElement, this issue also needs to be paid attention to).
3. When the MediaElement starts to play, any background audio playback (such as music played by Zune) will pause! This is the main reason why MediaElement is not used to play sound effects. In addition, even if the video file does not contain audio, this point should be noted.
4. MediaElement has a bug in the light theme of the simulator! This sounds strange, but it is true. To test MediaElement on the emulator, we must make sure it runs under the dark theme. But don't worry, this problem does not exist in the real machine.
5. MediaElement cannot render completely opaque effects! If there are other elements in MediaElement, we can see them clearly through the video, even the Opacity property of MediaElement is set to 1 (the default value of this property is 1). This is an anomaly synthesized between the phone's media player (which performs MediaElement video rendering inside) and Silverlight. For details, see "Media File Formats Supported by Windows Phone" (link is http://goo.gl/6NhuD ) to view video formats supported by MediaElement; and "Recommended Video Encoding Parameter Settings" (link is http://goo.gl/6NhuD) gl/ttPkO ) to see which encoding format is most suitable for our application. If we are using Expression Encoder, we can use the parameters that have been preset specifically for the Windows Phone (and Zune HD) platform for video encoding.
The User Interface
In addition to the introduction page (not described here), the Subservient Cat application uses another page, the main page. The root grid of the main page contains three different user controls, as shown in Figure 33.1.
1. Contains MediaElement elements for video playback 2. A simple "intro screen" that introduces the instructions that the cat can execute, and then the application will play the video clips corresponding to the commands. 3. A panel with a text box allows users to guess new instructions.
Figure 33.1 The three main user controls on the main page
➔ When the video is playing, the phone is in landscape mode, so it is just a page in landscape mode. However, the text box element is used to guess new instructions for the user, so the code behind temporarily changes the value of the SupportedOrientations property of the page so that when the focus is on the text box, both screen modes can be used. In this way, mobile phones with hardware keyboards can give users a better experience.
➔ The application bar has three buttons: one for displaying the command input panel, one for navigating to the introduction page, and one for indicating the number of commands the user has discovered (updated in the code behind). Clicking the last button can also prompt us whether there are more instructions waiting for us to discover, because for our users, the total number of instructions is a mystery. The application bar menu is dynamically added through code. It contains a list of instructions that the user has discovered. When the user clicks any of these instructions, the cat will do the corresponding action. See Figure 33.2 for details.
Figure 33.2 The application bar menu provides quick access to the list of discovered instructions, such as "yawn".
➔ Although the application can play different video clips, from a performance point of view, it actually uses a single longer video file (cat.wmv). The code behind will be responsible for selecting the appropriate video clip for playback.
➔ Use CompositeTransform to realize the movement and expansion of MediaElement, because the head and tail of the "cat.wmv" source file have some black bars that we don't want to see.
➔ The Volume property of MediaElement (the value range is 0~1) is set to 1 (representing the maximum volume), because its default value is 0.85. Although the maximum sound played can only reach the value set by the user, this ensures that the detailed part (short "meow" sound) in the video file can also be heard.
Note: Make sure to name the MediaElement element! If we did not name it, it is possible that the marketplace release review process will not find that you are using MediaElement, so it will not ensure that our application has the "media library" capability, which is necessary for this application.
➔ The main page's constructor uses the possibleCommands method to generate an instruction set that the cat can recognize. The sound accompanying the instruction set is represented by its start and end time in the "cat.wmv" file.
➔ In the OnNavigatedTo event processing, use the previously discovered instructions to fill the application bar menu. These commands are stored in discoveredCommands, and discoveredCommands are saved as a setting.
➔ In order to display the number of instructions found in the application bar button icon, the application project contains some pictures, including appbar.1.png, appbar.2.png, appbar.3.png, and so on. As for which picture to choose, it needs to be determined according to the number of discoveredCommands collections.
➔ When the page loads, the video starts to play automatically (because the AutoPlay property in the code is not set to false), but we don't want to play the entire video to show all the cat's actions. Instead, we should only play the first 1.5 seconds of the video. Therefore, in the MediaOpened event processing function of MediaElement (this event is triggered when the media file is loaded and ready to play), we use videoTimer to pause the video after 1.48 seconds. The pause is completed in the Tick event processing function "VideoTimer_Tick" of videoTimer.
Note: We will not be able to play the video in MediaElement until the MediaOpened event is triggered! After setting the source file of the MediaElement (which can be done in XAML or the code behind), we cannot interact with the media file immediately. Instead, we must wait for the trigger of the MediaOpened event. If for some reason, the media file cannot be loaded, the MediaFailed event will be triggered. The Subservient Cat application does not use the method of manually calling Play, that is because it uses the auto-play feature of MediaElement. But if you don't use its auto-play feature, you must call the Play method in the MediaElement_MediaOpened event handler.
Note: Why can't I play the video on the phone after connecting the phone to the Zune of the PC? This reason has actually been explained in the previous chapter. Zune is a desktop application that locks the phone's media library, which causes MediaElement to fail to load media files. Remember, if we need to debug video playback-related functions in the application, we can use the Windows Phone Connect Tool provided in Windows Phone Developer Tools to connect to the phone instead of connecting through Zune. In the Subservient Cat application, we can detect this situation through the MediaFailed event. Of course, we assume that this situation occurs because of the Zune connection, because for the application, the video file is a local file.
➔ The PlayClip method can pause the video, return to the start time point specified by the beginTime parameter, and reinitialize the videoTimer so that the video can stop playing at the end time specified by the endTime parameter. However, because setting the Position of MediaElement will bring some unfriendly effects, such as the video will quickly advance or quickly rewind to a specified point in time (rather than an instant jump), the introduction page of the application has already carried out this transition Video hiding processing (we don’t want to show which video clips are waiting for users to discover). The position setting is completed in the BeginInvoke callback function, so that the introduction page can be displayed. If this is not done, we will see unwanted situations appear. The length of the video delay is set to 2 seconds, this period of time allows users to browse instructions on the introduction page. We have no way to know the actual time consumed by the user, but 2 seconds is long enough.
Note: After we set the Position parameter of MediaElement, the effect cannot be seen immediately! On the contrary, we can see a short video before or after the target time point, just like watching fast-forward or fast-rewind. Because the method used by the Subservient Cat application is: temporarily use other elements to cover the video.
In the current Windows Phone version, the MediaElement element does not support markup. Using markers to distinguish individual video clips in the cat.wmv video file is an ideal solution, and it can also greatly reduce the processing code behind it. However, using DispatcherTimer to notify the application that the related video has been played is also an alternative solution. The following are two things to note:
1. The accuracy of the timer does not reach the "frame" level. The video used in this application uses some buffering at the end of each segment to prevent the Tick event of the videoTimer from triggering lag. 2. If we want to pop up a message box, the video file will continue to play in the background, but the Tick event processing of the timer cannot be called. No matter how long the video is played, Tick event processing cannot be resumed until the message box is dismissed (MessageBox.Show is a blocking operation). This is why in the source code, DiscoveredButton_Click is first used to pause the video playback.
When I started writing the Subservient Cat application, I called the Stop method of MediaElement in the OnNavigatedFrom event, because when the introduction page is displayed and the main page is in the stack, I am worried that unnecessary video playback will cause performance degradation. . However, it turns out that this worry is superfluous, because MediaElement will pause the video when the page leaves. If we don't need this feature (for example, when in other pages, I also want to hear the sound of the video playing), we must attach the MediaElement to a certain frame, not a specific page.
MediaElement and files in the isolated storage space If you want to play files in the isolated storage space (for example, our application downloads and saves it here), we can call the SetSource method of MediaElement, which takes a stream as a parameter Instead of a URI. With it, we can pass in a suitable IsolatedStorageFileStream.