Why does WPF MediaElement not work on secondary monitor? - wpf

My application uses the WPF MediaElement to play video (MOV files). This works well when playing on the Primary monitor but freezes when the window is moved to the secondary monitor.
I have tried the following without success:
Starting the application on the secondary monitor
Swapping the primary & secondary monitors (problem transfers to the new secondary monitor)
When the application window spans both monitors it works correctly but as soon as it is entirely within the secondary monitor the video freezes. Once in this state, moving the application back to the primary monitor doesn't help (and loading a new video doesn't help either).
The monitors are arranged so that the co-ordinates are always positive (both monitors are 1920x1080 and the secondary monitor origin is 1920,0).
Has anyone else seen this problem and/or found a fix?
EDIT
Does anyone use the WPF MediaElement with multiple monitors???

This is still a known issue in .NET Framework 4.0, which MS described as "The issue occurs when a synchronization between WPF and the underlying WMP control have to resynchronize when the display changes occur." It happens to H.264 codec video files.
Here are 3 workarounds.
1 . Use software rendering for the window containing the MediaElement control
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var hwndSource = PresentationSource.FromVisual(this) as HwndSource;
if (hwndSource != null)
{
var hwndTarget = hwndSource.CompositionTarget;
if (hwndTarget != null) hwndTarget.RenderMode = RenderMode.SoftwareOnly;
}
}
However this is not utilizing the GPU and graphics memory and could slow down the video playback.
2. Overlap at least 1 pixel onto the primary display
For example, suppose the primary screen in on the left, and the MediaElement fills the entire window. In the window's constructor, suppose Rect bounds represents the secondary monitor boundary, use
this.Left = bounds.Left - 1;
this.Width = bounds.Width;
this.Top = bounds.Top;
this.Height = bounds.Height;
so the MediaElement has 1 pixel wide overlapped on the primary monitor, and then it's able to play H.264 video files normally.
3. Use another MP4 codec other than MS's Media Foundation codec
Download a tool "Win7DSFilterTweaker" to disable Media Foundation "MP4" playback.
Install another MP4 codec, ffshow, for example.

Check if events: MediaOpened, MediaEnded and MediaFailed are still being raised.
I assume not as this is a known issue that this control "ignores" the second monitor.

Related

Is there a way to move some images on the screen and while they are moving record the scene as a video?

as you can read from the title i want to be able to draw some images on the screen, move them in some direction and video capture the movement with a good fps rate.
I want to specify that i do not want to record the desktop nor some portion of it but the content of the actual window in which the images are moving(so the window can also be minimized). Also if possible i want to be able to set a custom size for my view where everything will happen.
Where i should start from?
I have already tried with WPF but as the UI is single threaded i am not able to take a screenshot of the view while something is moving on it.
What library you would suggest me?
Are there similar open-source projects i can learn from?
Any suggestion i welcomed!
Here's some code I recently wrote to do this, it cycles through a number of frames and renders a control (in this case, a Canvas) into PNGs:
private void Export(int frame)
{
// force the control to update after any changes you've just made
theCanvas.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
// render the control into a bitmap
RenderTargetBitmap bitmap = new RenderTargetBitmap(1920, 1080, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(theCanvas);
// save the bitmap out as a PNG
using (var stream = File.Create($"Animation/Frame_{frame.ToString("D3")}.png"))
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
encoder.Save(stream);
}
}
You can then use ffmpeg to pack those PNGs into the movie file format of your choice.

WPF Seamless video play back

I'm working on a project right now where we are in need of seamless video transition between multiple videos in a WPF application.
A second monitor is being used as a media player, events are being sent to the screen to fire off videos, the video position is then being used to fire events back according to the video hitting specific intervals. The project is using a PRISM so the events are being fired by it's Event Aggregator.
The issue is finding a way of playing Videos in WPF that will accommodate for buffering between videos. I don't have code examples for methods tried but I have attempted to do this using.
The native WPF Media Element. This was very buggy and most certainly not user friendly. Bad play back and huge gaps between media files.
WPFMediaKit This is probably the best solution so far, video play back is fine with two issues. The media screen stops playing videos at it seems random times and the control goes black. And the transition between videos is about half a second of black.
Hosting AxWindowsMediaPlayer in a WindowsFormsHost. Play back is great but there is a huge gap between videos, even when running a playlist (This does not happen in Windows Media player so there could be something we are missing.) also as the control is hosted in a WindowsFormsHost I'm not sure if it is possible to keep(Bind) the videos position, and the position event does not appear to be caught.
GMF Play - Seems to have the same issues as WPFMediaKit except the seen is collapsed rather than the screen going black during transitions.
Edit
Media Player Example
Media Element Setup
private void CreateMediaKitElement()
{
WpfMediaKit.BeginInit();
WpfMediaKit.Stretch = Stretch.Fill;
WpfMediaKit.LoadedBehavior = WPFMediaKit.DirectShow.MediaPlayers.MediaState.Manual;
WpfMediaKit.MediaEnded += WpfMediaKit_MediaEnded;
WpfMediaKit.Volume = 0;
WpfMediaKit.EndInit();
}
private void PlayVideo(string uri, IEnumerable<Interval> intervals)
{
// Stop the current Audio track if a new video is being shown.
AudioElement.Stop();
WpfMediaKit.Stop();
// WpfMediaKit = null;
//Try recreating Element
WpfMediaKit = new MediaUriElement();
CreateMediaKitElement();
WpfMediaKit.Source = new Uri(uri, UriKind.Relative);
WpfMediaKit.Play();
}
So my question, does anyone know of or have an example of a method to play videos in WPF with a seamless transition between videos?
Thanks in advance,
Oli

WPF MediaElement video won't play after being hidden in storyboard

I'll start of by describing the problem, and then follow up with details about the process I'm going though.
Problem:
I'm having an issue where I'm playing a MediaElement on one storyboard and then setting the same MediaElement to hidden in another. After having the MediaElement set to hidden, I'm unable to replay the video portion of that storyboard again (non-MediaElement animations still happen.) Videos are WMVs encoded in VC-1 at 10,000 Kbps at a resolution of 1560x1004 and provided alongside the project as relative assets.
Details:
I'm working on a Kiosk application which makes use of a large number of videos combined with some graphical effects for real-time animation. Presently I'm creating storyboards using Blend, layering the videos for playback in the desired sequence. Below details two sample storyboard from the page:
Open performs the following:
Set's meOpen's visibility to 100%, Visible
Set's meIn's visibility to Hidden at 1 second (masking the start of meOpen)
Starts playing meOpen at 0:00.900.
Before playing the Close storyboard the Open storyboard is played, and the system waits for user input to continue. Once Close is triggered, the following happens:
meOpen - A MediaElement that has it's visibility set to 'Hidden' at 1 second
meClose - A MediaElement that is the desired video to play. I have it starting slightly before meOpen is hidden to mask the first frame 'black frame' while the element is loading the video
The rest of the items is just fading visibility of overlay elements.
The storyboard works for running through the video; however, if I try and play the Open storyboard a second time, meOpen does not play.
Thanks

Changing MediaElement source without Flicker

I have a simple video player that plays a series of videos using the WPF MediaElement. The videos together form one continuous film that move around a still image. At the end of each video the movement freezes on the final frame of the currently playing video. When I press a button the next video plays, which continues the movement around the still image. It's an application I'm going to use to give a speech. Effectively I've got a series of videos for which the last frame of each video is the same as the first frame of the next video.
I'm using a WPF MediaElement and changing the Source property when the user clicks on the mouse.
The problem that I have is that, when I change the Source property, the MediaElement becomes transparent while the next video is loaded. This means there is a flicker between videos. Is there any way of preventing this flicker? What other strategies could I use?
Here's some code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.x_MediaElement.MouseLeftButtonDown += x_MediaElement_MouseLeftButtonDown;
this.MouseLeftButtonDown += MainWindow_MouseLeftButtonDown;
this.WindowStyle = WindowStyle.None;
this.WindowState = WindowState.Maximized;
}
void MainWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MoveNext();
}
private void MoveNext()
{
_sourceIndex++;
if (_sourceIndex >= _sources.Length)
_sourceIndex = 0;
Debug.WriteLine(string.Format("Playing {0}", _sources[_sourceIndex]));
this.x_MediaElement.Source = new Uri(_sources[_sourceIndex]);
this.x_MediaElement.Play();
}
private int _sourceIndex = -1;
private string[] _sources = new string[] {
//SOURCE GO HERE
};
void x_MediaElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MoveNext();
e.Handled = true;
}
}
I am gonna be honest with you. MediaElement has more bugs than you can count with fingers. Starting from that the mediaElement blows up after playing 20 videos(no more MediaEnded event, it will crash or something like that). And ofcourse the performance. Its not synchronized with vertical sync. So the video might actually seem laggy.
I advise you to look into DirectShow technology(essentially what WPF is based on, but you can switch renderer which will avoid lag). COnsidering that you will not be developing any professional application, I guess MediaElement will be fine.
However, MediaElement is the simplest option, and if it works for you, then keep working with it. As for your problem, I think there are few possible solutions:
Have two MediaElements and switch between them. If one video ends, start another vid in another MediaElement, as long as you play first frame on second mediaElement, hide the first mediaElement, and vice versa. You can poll for position, and maybe MediaStarted event. This way the flicker will be almost impossible to notice.
If you want fluent video playing without ANY flicker at all, there is GMFPlay. You can check it out. Though it's not MediaElement. But it can play videos simultaneously without any flicker.
Take screenshot of the last frame(you can take screenshots with WPF) and show it as Image while MediaElement is secretly loading.

WPF custom drawing and transparency - how to optimize?

I have a WPF application with a custom windows style (AllowsTransparency="True" WindowStyle="None"). This window has a custom Peak Meter control which uses WriteableBitmap to draw data from DirectSound audio input.
I am using a bitmap with all levels drawn as colored rectangles (red/yellow/green/red) and when the audio arrives I just draw a black rectangle over my level meter form the top. It works fine on my machine (Windows 7, Pentium 4 single core). But it works bad on a laptop with Windows XP SP3 and integrated video.
I know that transparency effects have some issues on DirectX 9, but I have read the problem should be fixed in SP3. Still the call to _writeableBitmap.AddDirtyRect takes 30-40% CPU on XP and sometimes it causes dropouts in audio (if USB audio is used, and those dropouts occur not in my application but somewhere in DirectSound<->drivers subsystem).
On Windows 7 the same app takes no more than 3% CPU and no audio dropouts noticed (but the CPU is actually weaker on the Win7 PC than on the laptop with XP).
I tried not to use AddDirtyRect but just draw a WPF Rectangle element over the Image with leds and set the height of the rectangle when new audio level arrives. What a surprise! Somehow changing the height of a Rectangle element takes noticeably less resources than calling _writeableBitmap.AddDirtyRect for 100x20 pixel rectangle! Now on XP it took just 10-20% instead of 30-40% with AddDirtyRect.
But when I removed transparency effect from the window, finally also XP (and even on VirtualBox) went down to 2-6% CPU. Obviously transparency makes it really hard to redraw 20x100 rectangle 10 times per second.
I could live with no transparency in my application, but the problem is - the design uses rounded corner windows and I need to cutoff the area around them. But as soon as I set AllowsTransparency="False", the window shows the background color behind.
So the main question is - how do I make the contents of the window to clip away the background of the window so the corners stay round without using XP-heavy transparency?
I remember that I could do than even on a C++ Windows application just by setting a custom window region and not using any transparency (that was on a Windows 98 machine). Can the same thing be done on WPF?
Or maybe there is some trick how to make WriteableBitmap to use less resources on XP?
As I did not find anything better, I used the old way: SetWindowRgn API.
It was a bit complicated because my application uses some animated slide-out parts which protrude out of the main window so I had to sync WPF animation with SetWindowRgn calls to make slide-out effect look as clean as possible. The result is not ideal but acceptable. And the main thing - no more high CPU and no audio dropouts.

Resources