Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Non-Destructive Media Edits

  This sample allows you to mark out the offensive sections of your media and skip or mute the sections automatically during playback without modifying the actual media file. Uses Windows Media Player 10 SDK.
Arian Kulp's Blog

Difficulty: Intermediate
Time Required: 1-3 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions, Windows Media Player 10 SDK
Hardware:
Download:

For this column, I decided to implement something I've seen a need for before, but never taken the next step to actually create. If you have audio and video files on your computer (and who doesn't these days!), perhaps there are sections of those files that you don't care for as much. It could be commercials in a Windows XP Media Center Edition recorded TV file, or explicit lyrics in a song. For some files you can edit the files in a program such as Windows Movie Maker or various audio editing utilities, but then you would need to either keep two copies of the file, or overwrite the original. You are also limited by what you can modify with DRM-protected formats, or files which are just too big to edit effectively. Wouldn't it be great if you could just mark out the offensive sections of your media and skip or mute the sections automatically during playback without modifying the actual media file? I thought so!

This article requires Visual C# 2005 Express Edition or Visual Basic 2005 Express Edition. You can find the Express Edition downloads at http://lab.msdn.microsoft.com/express/. You can also install the Windows Media Player 10 SDK for samples and help files, though this isn't a requirement. Code downloads for this article are available in both C# and Visual Basic.

To simplify the code, I started with the .NET sample included with the Media Player 10 SDK. If you choose to install the SDK, you can find the original code at C:\WMSDK\WMPSDK10\samples\dotNet\csharp (assuming you install in the default location). This application demonstrates interacting with the Windows Media Player media library, standard play/pause/stop/forward/reverse buttons, seeking within a file, and embedding a viewer control in a managed form. Most of the original code is intact with only small changes, with the rest of the code added on in new methods.

Figure 1: Original user interface

I decided that the easiest way to structure the user interface was to allow the user to mark sections of the media during viewing. The start of a section is marked as A, with the end of the section being B. The section within these marks is then either muted or skipped based on an action indicator. The sample covered many basic Windows Media playback needs, so turned out to be a great starting point. The next step was to add the ability to capture the time codes for the A and B marks, and a drop-down box to indicate the action to take. Finally, the marks can be added to a list, with basic add and remove capabilities.

As the media plays, the current position is evaluated against the list of marks. If the current position is found to be within a pair of marks, the position is either advanced to skip, or the sound is muted to the next mark. This provides a very seamless viewing experience, and depending on the source media, may not even be noticeable. New marks can be added or removed even during playback, and individual marks can be set active or inactive without needing to remove them from the list. All marks are saved to disk at the same location as the original file ({filename}.marks) and loaded automatically when the media is subsequently loaded.

Diagram 2: The improved user interface with marking controls

How it Works

Windows Media Player has a rich object and event model, making it easy to tie into what it is doing at any time. Using the OpenStateChange event, you can detect media events such as media connecting, media waiting, playlist changed, and other event related to opening and changing streams. The PlayStateChange event lets you know events such as player is ready, playing, reconnecting, scanning, or stopped.

The Player object contains a property, currentPosition, representing the number of seconds into the media. If the user clicks the Mark A or Mark B button, the current position is saved to the corresponding label in the UI. The Action drop-down box can then be used to skip or mute the corresponding section, and the mark can be added to the list. Each change to marks results in a save.

To indicate the current position in the file using a slider, a timer is triggered every 250ms. When the timer fires, the current position is retrieved from the player control, compared against the media duration, and a new position for the slider is set. This turns out to also be a good place to evaluate the list of marks to see if the media has played to a marked section. This is checked in the EvaluateMarks() section.

Visual C#

private void EvaluateMarks()
{
    if (Player.playState == WMPPlayState.wmppsPlaying
    || Player.playState == WMPPlayState.wmppsScanForward
    || Player.playState == WMPPlayState.wmppsScanReverse)
    {
        double pos = Player.Ctlcontrols.currentPosition;
        bool inMark = false;

        foreach (MediaMarkListViewItem mark in lvMarks.Items)
        {
            if (mark.Active && (pos >= mark.MarkA && pos <= mark.MarkB))
            { 
                switch (mark.Action)
                {
                    case MediaMarkAction.SKIP:
                        Player.Ctlcontrols.currentPosition = mark.MarkB;
                        break;

                    case MediaMarkAction.MUTE:
                        Player.settings.mute = true;
                        currentlyMuting = true;
                        break;
                }
                inMark = true;
            }
        }                
        if (!inMark)
        {
            if (currentlyMuting)
            {
                Player.settings.mute = false;
                currentlyMuting = false;
            }
        }
    }
}

Visual Basic

Private Sub EvaluateMarks()
    If (Player.playState = WMPPlayState.wmppsPlaying) Then
        Dim pos As Double = Player.Ctlcontrols.currentPosition
        Dim inMark As Boolean = False

        For Each mark As MediaMarkListViewItem In lvMarks.Items
            If (mark.Active AndAlso ((pos >= mark.MarkA) _
                        AndAlso (pos <= mark.MarkB))) Then

                Select Case (mark.Action)
                    Case MediaMarkAction.SKIP
                        Player.Ctlcontrols.currentPosition = mark.MarkB
                    Case MediaMarkAction.MUTE
                        Player.settings.mute = True
                        currentlyMuting = True

                End Select
                inMark = True
            End If
        Next

        ' In not in a mark, but muting, then un-mute
        If Not inMark Then
            If currentlyMuting Then

                Player.settings.mute = False
                currentlyMuting = False
            End If
        End If

    End If
End Sub

The first check is to confirm that a clip is currently playing. If the user drags the scrollbar, it could cause strange behavior if the scrollbar snapped to positions based on marks. So then, the current position is retrieved and set aside. The "For Each" loop just compares the current position with each mark range, and skips or mutes accordingly, finally un-muting if not in any mark.

Internally, marks are saved as MediaMark objects, which are then added to MediaMarkListViewItem objects to be displayed in the ListView control. This may seem confusing, but by subclassing the ListViewItem object, it simplifies other application code and provides better object encapsulation. When a MediaMark object is created, it is embedded in a MediaMarkListViewItem for display. The original MediaMark object is also stored in a generic List object for easier serializing.

The MediaMark object must be marked with the Serializable attribute, but then saving and loading is trivial.

Visual C#

XmlSerializer s = new XmlSerializer(typeof(List<MediaMark>));
TextWriter w = new StreamWriter(Player.currentMedia.sourceURL + ".marks");
s.Serialize(w, marks);
w.Close();

Visual Basic

Dim s As XmlSerializer = New XmlSerializer(GetType(List(Of MediaMark)))
Dim w As TextWriter = New StreamWriter( Player.currentMedia.sourceURL & ".marks")
s.Serialize(w, marks)
w.Close()

Loading them is just as easy. Just tie into the OpenStateChange event, look for the wmposOpeningUnknownURL state, then load the marks to ensure that they are available as soon as a new media file prepares to play.

Extending the Application

This application was fun to write, and provides some great opportunities to extend it. For one thing, the labels for time codes would probably make more sense as textboxes in order to make minor changes. It would also make sense to allow labels to describe sections. This is actually in the object model now, but not supported in the user interface.

Being able to export the actual media in cut sections based on the marks would be a nice benefit for people transferring tapes or LPs to digital files, but would definitely add some complexity. Calling out to a command-line utility based on marks might be a workable solution.

Supporting DVDs and Internet streams would also be helpful. Obviously, the marks would need to be saved to a common location since the original locations are not writeable. Perhaps using user profile directories would make sense.

Finally, taking the basic idea and integrating it into a Media Player or XP Media Center Edition plug-in would make for a more seamless viewing experience. Instead of requiring the special player, this would be more natural during playback.

Conclusion

Get started with Visual Studio 2005 Express and Windows Media Player interoperability today! It's easier than you would have guessed, and can lead to some very rich user interactions. Download the Visual Studio Express Edition of your choice at http://lab.msdn.microsoft.com/express/, and use your imagination! Once you start working with Windows Media Player, you will see how easy it is, and ideas for projects will keep coming. Now see what you can come up with!

Follow the Discussion

  • Tami CooperTami Cooper

    I have a really long video of the fireworks at DisneyWorld on Christmas Eve 2007.  The video is about 12 minutes so of course it's way to large to upload to myspace or youtube.  I tried using Windows Movie Maker to edit it and maybe cut it in half and make two videos but I wasn't able to import it (wrong type or something).  What would you suggest? Downloading this and editing the video that way?  

  • Clint RutkasClint I'm a "developer"

    @Tami:  Email me the type of camera you have.  If it is a JVC, I may be able to help.  I have one and I know a few work arounds.  crutkas [at] microsoft

  • srilathasrilatha

    thank u ,

    this  info is really helpful

  • bdoburbdobur

    I want to disable WMP default mouse click events. For example if user double clicks he video frame i want it to be fullscreen, when user doubleclicks again video will quit fullscreen. My code is valid and working for frist step. When in fullscreen i am doubleclicking again and just video stops playing. and my video stays in fullscreen. i want to disable stopping video.

  • Arian KulpArian Kulp

    I haven't looked at this code since a few years ago.  Maybe it's time to revisit it!  I can't think of any reason off the top of my head for why this wouldn't work.  Have you verified that the XML file with the marks gets written properly?  I'll take a look at some point, but it probably won't be until after PDC at the earliest.

    -Arian

  • Colin smithColin smith

    Thanks for this article - very helpful and works fine  except when playing DVD files stored on the hard drive. The currentposition can be read O.K. but the marks are ignored on plackback (i.e. the sections aren't skipped). Any ideas about enableing the marks for these files?

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.