Preview image for MediaElement and more

This article covers two topics. One is how to get over ugly clr-namespace syntax by defining your own namespaces, the other – what is MediaPlayer control and how to create your own MediaElement clone with video preview as most of video hosting services like YouTube do. So let’s start

First of all, I want my control looks like a normal one in XAML page. I do not want ugly clr-namespace:myNamespace etc, reference, I WANT URL!!!

<Window x:Class=MediaSense.Window1

    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation

    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml

    xmlns:l=http://schemas.sharpsoft.net/xaml

    Title=MediaSense Height=600 Width=800

    >

    <l:PreviewMediaElement Name=video  Width=640 Height=480 Source=../../Butterfly.wmv />

</Window>

Don’t “xmlns:l=http://schemas.sharpsoft.net/xaml” looks much better? How to do it. Just go to your AssemblyInfo.cs file in the assembly, where your control sits and add namespace mapping. Something like this, will be enough to make your reference looking better

 

[assembly: XmlnsDefinition("http://schemas.sharpsoft.net/xaml", "MediaSense")]

[assembly: XmlnsDefinition("http://schemas.sharpsoft.net/xaml", "MediaSense.Controls")]

Please, don’t ask me why this does not works for controls in the assembly, that reference it. I do not know :) . The other point is, that this method will not solve warnings like ” The element ‘StackPanel’ in namespace ‘http://schemas.microsoft.com/winfx/2006/xaml/presentation’ has invalid child element ‘PreviewMediaElement’ in namespace ‘http://schemas.sharpsoft.net/xaml’. List of possible elements expected: ‘StackPanel.CanHorizontallyScroll, etc., etc., etc.,”

The other thing that not covered by this, as well as the old method is intellisense and autocomplete. You can do it yourself by adding xsd schema file into C:\Program Files\Microsoft Visual Studio 8\Xml\Schemas. You should create xsd like following in order to get over this problem and recieve intellisense. The only way to do it is by hand, due XSD Generator does not works good enought for XAML maps. Good forces are working on it those days, so it worth to wait.

<?xml version=1.0 encoding=utf-8?>

<xs:schema targetNamespace=http://schemas.sharpsoft.net/xaml

  elementFormDefault=qualified

  xmlns=http://schemas.sharpsoft.net/xaml

  xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml

  xmlns:xs=http://www.w3.org/2001/XMLSchema

  >

  <xs:import namespace=http://schemas.sharpsoft.net/xaml schemaLocation=xaml2006.xsd/>

  <xs:element name=PreviewMediaElement type=dPreviewMediaElement substitutionGroup=xs:dMediaElement>

    <xs:annotation>

      <xs:documentation>Represents a control that contains audio and/or video with preview. </xs:documentation>

    </xs:annotation>

  </xs:element>

  <xs:complexType name=dPreviewMediaElement >

    <xs:choice minOccurs=0 maxOccurs=unbounded>

      <xs:element name=MediaElement.Source type=dUriContainer minOccurs=0 maxOccurs=1>

        <xs:annotation>

          <xs:documentation>Gets or sets a media source on the MediaElement. This is a dependency property.</xs:documentation>

        </xs:annotation>

      </xs:element>

If you are using Orcas bit, you can forget all above, there even custom controls are having intellisese support as well as user controls in current framework 2.0

So far so good. Now, let’s cover preview image. In order to draw first (or any other) video frame we have to treat video drawing “by code”, so the only class usable for us is MediaPlayer.  After first initialization, we’ll subscribe to Video Opened event to get the first frame drawn like this

 

void getFirstPreview()

        {

            RenderTargetBitmap target = new RenderTargetBitmap(_player.NaturalVideoWidth, _player.NaturalVideoHeight, 1 / 100, 1 / 100, PixelFormats.Pbgra32);

            DrawingVisual visual = new DrawingVisual();

            DrawingContext context = visual.RenderOpen();

            context.DrawVideo(_player, frameRect);

            context.Close();

            target.Render(visual);

 

            if (_prev == null)

            {

                _prev = new Image();

            }

 

 

            _prev.Source = BitmapFrame.Create(target).GetAsFrozen() as BitmapFrame;

 

            this.Content = _prev;

            _player.Stop();

            _player.Position = TimeSpan.FromSeconds(0);

        }

As you can see, we just renderred first video frame into Bitmap and put it as a source for our Image. Then we just put an image instead of text like “loading”

The next step is to draw video. The same player, giving us VideoDrawing, derrived from Drawing, that can be DrawingBrush for our rectangle element.

 

if (_video == null)

            {

                _video = new VideoDrawing();

                _video.Player = _player;

            }

            _video.Rect = frameRect;

 

            if (_frame == null)

            {

                _frame = new Rectangle();

 

 

                Brush brush = new DrawingBrush(_video);

 

 

                _frame.Fill = brush;

 

 

            }

But what’s going on with the performance? You can not freeze this brush, it’s dynamic, but you can cache it

RenderOptions.SetCachingHint(brush, CachingHint.Cache);

                RenderOptions.SetCacheInvalidationThresholdMinimum(brush, 0.5);

                RenderOptions.SetCacheInvalidationThresholdMaximum(brush, 2.0);

Fine, we almost done. A couple of problems, in order to get something from video, we should play it first, it is not really fun, but else, you have no even first frame. So, mute it before :) There are a couple of “nice adds” in this control, so it can be used as great start for your next video player.

That’s all, kids. Have a nice day.

Source code for this article

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DotNetKicks
  • DZone
  • Live
  • Reddit
  • TwitThis
  • email
  • Slashdot
  • StumbleUpon

You may also be interested with:

  1. Real singleton approach in WPF application
  2. INotifyPropertyChanged auto wiring or how to get rid of redundant code

No comments yet

Leave a Reply

Recommended

 


Sponsor


Partners

WPF Disciples
Dreamhost
Code Project
Switched to Better Place

Together