How to change the position of a video using MediaElement in Windows8? - c#

Currently I am doing this in my code,
playbackElement1.AutoPlay = true;
playbackElement1.SetSource(stream, this.m_recordStorageFile.FileType);
playbackElement1.Position = new TimeSpan(0, 0, 0, 0, 5000);
playbackElement1.Play();
It doesn't work, checking for a video longer than 5 secs.

There are two problems. First, MediaElement can only set the position once the media is loaded, determined by handling the MediaOpened event. Secondly, not all media is seekable. Check by calling CanSeek. Use something like:
playbackElement1.AutoPlay = true;
// Will fire after the media has loaded
playbackElement1.MediaOpened += (source, args) =>
{
MediaElement player = (MediaElement) source;
if (player.CanSeek)
{
player.Position = new TimeSpan(0, 0, 0, 0, 5000);
}
}
playbackElement1.SetSource(stream, this.m_recordStorageFile.FileType);
Once loaded, use the NaturalDuration property to see the length of the media, converting it to a TimeSpan using HasTimeSpan and TimeSpan properties if needed.

In a nutshell, you will need to add a Slider underneath the MediaElement just like in any video player...
- the Slider will update the player current position
- the Timer will update the slider every 300 millisecond with the current player position
Code:
<Slider x:Name="videoSlider" Thumb.DragStarted="videoSlider_DragStarted" Thumb.DragCompleted="videoSlider_DragCompleted" Margin="10,0,10,30" Height="18" VerticalAlignment="Bottom"/>
<MediaElement x:Name="videoPlayer" Margin="4,59,152,53" Volume=".5" MediaOpened="videoPlayer_MediaOpened">
[This is picture for the Media-Element with the Slider][1]
Now we have a media element and a slider... Next: C# Code :)
public partial class MainWindow : Window
{
bool isSeekingMedia = false;
DispatcherTimer seeker; // the timer to update the Slider
public MainWindow()
{
InitializeComponent();
player = new MediaPLayer();
IsPlaying(false);
seeker = new DispatcherTimer();
seeker.Interval = TimeSpan.FromMilliseconds(200);
seeker.Tick += Seeker_Tick;
}
///Seeker_Tick will update the Slider position while the video is playing
private void Seeker_Tick(object sender, EventArgs e)
{
try
{
MediatimeCounter.Content = String.Format("{0:hh}:{0:mm}:{0:ss}/{1:hh}:{1:mm}:{1:ss}", videoPlayer.Position, videoPlayer.NaturalDuration.TimeSpan);
if (!isSeekingMedia)
{
videoSlider.Value = videoPlayer.Position.TotalSeconds;
}
}
catch (Exception ex) { }
}
//This code is going to set Seeking to true to avoid playing the video if the user is changing the slider position... it kinda causes a performance issue.. so it's better to update the video position once the slider dragging event is completed.
private void videoSlider_DragStarted(object sender, RoutedEventArgs e)
{
isSeekingMedia = true;
}
//and this code is to update the video position based on the slider value.
private void videoSlider_DragCompleted(object sender, RoutedEventArgs e)
{
if (videoPlayer.Source != null)
{
isSeekingMedia = false;
this.videoPlayer = player.SeekVideo(videoPlayer, videoSlider.Value);
}
}

Related

DispatcherTimer stacking - UWP

I'm currently working on a project in UWP and I have a CommandBar that I want to go from Hidden to Compact if the mouse moves. After five seconds (If the mouse dont move) the CommandBar should go back to Hidden again.
I dont get any errors, but when I move the mouse the CommandBar is going crazy and it's just flashing from Hidden to Compact when I move the mouse again. I think the problem is that the OnMouseMovement event is stacking upon itself.
This is my code for the mouse movement event:
public async void OnPointerMoved(object Sender, PointerRoutedEventArgs e)
{
CmdBar.ClosedDisplayMode = AppBarClosedDisplayMode.Compact;
DispatcherTimer ButtonTimer = new DispatcherTimer();
ButtonTimer.Interval = TimeSpan.FromSeconds(5);
ButtonTimer.Tick += (sender, args) =>
{
CmdBar.ClosedDisplayMode = AppBarClosedDisplayMode.Hidden;
};
ButtonTimer.Start();
}
I made a little test project to try it out and get you an answer, this is what I did :
private DispatcherTimer Timer { get; set; }
public MainPage()
{
this.InitializeComponent();
CmdBar.ClosedDisplayMode = AppBarClosedDisplayMode.Hidden;
Timer = new DispatcherTimer(){Interval = TimeSpan.FromSeconds(5) };
Timer.Tick += (sender, args) => {
CmdBar.ClosedDisplayMode = AppBarClosedDisplayMode.Hidden;
Timer.Stop();
};
}
public async void OnPointerMoved(object Sender, PointerRoutedEventArgs e)
{
Timer.Stop();
CmdBar.ClosedDisplayMode = AppBarClosedDisplayMode.Compact;
Timer.Start();
}
Basically as #Evk said, you are creating a new timer every move of your mouse. So I declared a property for the timer and stop it then restart it when your mouse move.

Unfocus live-updating chart

I have a project which consists of two forms, MainForm and CrossCorrPlotForm. On CrossCorrPlotForm, I have two charts (CrossCorrExpChart and CrossCorrRefChart) which I enabled scroll wheel zooming on, using the code described here and here.
Everything was working perfectly fine, until I added another chart (histChart), on MainForm, which is updated on each frame incoming from a camera (15-20 FPS), using a BackgroundWorker to collect and plot the data from the images. Now, both my charts on CrossCorrPlotChart are not zoomable anymore.
I presume this has something to do with the live-updating chart taking back the focus on each update. I tried adding histChart.Focus = false in the code but to no avail, as it seems "Control.Focused is read-only".
Does anyone have an idea how to make my charts zoomable again ?
Thanks
EDIT : Here is the code for the BackgroundWorker that updates chartHist :
private void OnFrameReceived(Frame frame)
{
bgw1.RunWorkerAsync(frame);
}
private void bgw1_DoWork(object s, DoWorkEventArgs e)
{
Frame frame = (Frame)e.Argument;
myBitmap = null;
try
{
frame.Fill(ref myBitmap);
mycamera.QueueFrame(frame);
SaveBitmap = myBitmap.Clone(cloneRect, myBitmap.PixelFormat);
BitmapToPrint = myBitmap.Clone(cloneRect, myBitmap.PixelFormat);
}
catch {}
}
private void bgw1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (this.InvokeRequired)
{
BeginInvoke((Action)(() => bgw1_RunWorkerCompleted(sender, e)));
}
else
{
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
DataFromBitmap DataFromBitmapHist = new DataFromBitmap(SaveBitmap.Clone(cloneRect, SaveBitmap.PixelFormat));
PixelColorCount = DataFromBitmapHist.ColorCountOutput();
}).Start();
chartHist.Titles["Title2"].Visible = false;
chartHist.Series["Pixel count"].Points.Clear();
//Plotting the pixel counter, to detect saturation
for (int i = 0; i < PixelColorCount.Length; i++)
{
chartHist.Series["Pixel count"].Points.AddXY(i, PixelColorCount[i]);
}
//If there are saturated pixels : toggle a title on chartHist to warn the user
if (PixelColorCount.Last() > 1)
{
chartHist.Titles["Title1"].Visible = false;
chartHist.Titles["Title2"].Visible = true;
}
else
{
chartHist.Titles["Title1"].Visible = true;
chartHist.Titles["Title2"].Visible = false;
}
}
}
NOTES :
OnFrameReceived is a function from the API of the camera, it contains code that fires when a Frame is received from the camera.
frame.Fill puts the image contained in the Frame object in a Bitmap.
mycamera.QueueFrame sends back the Frame object to the camera, to receive a new image.
I had to use multiple threads, because using the UI thread too much resulted in blocking the reception from the camera.

Replaying a video continuously in a WPF media element

I have a video file playing in a media element. I need to keep it playing, thus I tried:
me.play();
me.MediaEnded += new RoutedEventHandler(me_MediaEnded);
With this event method:
//loop to keep video playing continuously
void me_MediaEnded(object sender, EventArgs e)
{
//play video again
me.Play();
}
However the above does not replay the video file. Why? What did I do wrong?
According to a post on MSDN:
Play() starts from the current position therefore you have to first go to the starting place and then play it again.
So you have to reset the position before replaying:
me.Position = TimeSpan.FromSeconds(0);
me.Play();
You could also use a Storyboard to control and loop the video without needing to hook events or do any code-behind work. This is the recommended solution on MSDN and is a more elegant and proper solution for MVVM design.
Read more on MSDN here, includes examples:
http://msdn.microsoft.com/en-us/library/ms741866%28v=vs.100%29.aspx
I got it to work with this:
class MyMediaPlayer : MediaPlayer
{
private bool looping;
public MyMediaPlayer() : base()
{
looping = false;
base.MediaEnded += new EventHandler(mediaEnded);
}
public MyMediaPlayer(string _file) : base()
{
looping = false;
base.Open(new Uri(_file, UriKind.Relative));
base.MediaEnded += new EventHandler(mediaEnded);
}
public bool Looping
{
get { return looping;}
set { looping = value; }
}
public void playLooping()
{
looping = true;
base.Play();
}
public void playLooping(string _file)
{
looping = true;
base.Open(new Uri(_file, UriKind.Relative));
base.Play();
}
public void play()
{
looping = false;
base.Play();
}
public void play(string _file)
{
looping = false;
base.Open(new Uri(_file, UriKind.Relative));
base.Play();
}
public void stop()
{
looping = false;
base.Stop();
}
private void mediaEnded(object sender, EventArgs e)
{
if(looping)
{
base.Position = new TimeSpan(0, 0, 0);
base.Play();
}
}
}
Hope this answers your question.
I don't know the reason but this never worked for me with a GIF:
me.Position = TimeSpan.FromSeconds(0);
me.Play();
My GIF stops playing after the first iteration.
The solution is:
<MediaElement x:Name="me"
MediaEnded="MediaElement_MediaEnded"
LoadedBehavior="Play" />
Code:
private void MediaElement_MediaEnded(object sender, RoutedEventArgs e)
{
me.Position = TimeSpan.FromMilliseconds(1);
}
1 ms is used while 0ms might stop the playback you cannot run it again with a 'Play' method.

WPF animation working erraticaly

I have animation code in MainWindow for a cube which is GeometryModel3D object
Animation code
private void animate(GeometryModel3D back)
{
Transform3DGroup transGroup = new Transform3DGroup();
DoubleAnimation cardAnimation = new DoubleAnimation();
cardAnimation.From = 0;
cardAnimation.To = 0.3;
cardAnimation.Duration = new Duration(TimeSpan.FromSeconds(2));
cardAnimation.AutoReverse = true;
Transform3D transform = new TranslateTransform3D(0, 0, 0);
transGroup.Children.Add(transform);
back.Transform = transGroup;
transform.BeginAnimation(TranslateTransform3D.OffsetZProperty,
cardAnimation);
}
In Main window Code I have
Window1 win1 = new Window1();
public MainWindow()
{
InitializeComponent();
}
public void textbox_keydown( KeyEventArgs e)
{
if(e.Key==Key.Return)
{
if( some condition nothing to do with animation at all)
{
animate(cube);
win1.ShowDialogue();
}
//Position1
}
}
When i run program first time animation does not show and window1 show, now again i put some entry in textbox and enter again second time animation shows and after that every time only first time it does not show.
Also if i put "animate(cube);" at position 1 animation works even first time also and off course every other time too.
Why animation is not working first time when textbox_keydown( KeyEventArgs e) invoked in above case and working only second time and onwards when textbox_keydown( KeyEventArgs e) is invoked.
Is there any threadind problem or initiation i am forgetting ?
Above animation function is in MainWindow after textbox_keydown( KeyEventArgs e) .

Mouse Wheel Scroll - How can I capture the time interval between start and stop of scrolling?

Is there any way to capture the time interval between mouse wheel scroll start and stop? Actually I want to capture the interval between the scrolling start and stop when I very quickly scroll the mouse wheel.
I have already looked at MouseWheel event but it don't fulfill my requirement. In senes that it always gives a value of Delta 120 or -120 but i want to call a function depending on the speed of the mouse scroll for example when i scroll the mouse normally i want to perform function 1 and when i scrolled the mouse very quickly i want to perform the function 2. In other words is there any way to distinguish between the mouse scroll high and normal speed.
Any advice will be appreciated.
can't you capture the mouse wheel events and see how long between them. Basically start a timer when you get a mouse wheel event and then in the next event see what the timer is at (and so how long has elapsed between the events) to determine the speed the wheel is being turned at? If the elapsedtime is smaller than a certain threshold, perform function2 and if it is faster than a certain threshold perform function 1.
You will probably have to set it to perform function 1 if the timer goes off in case they only do a single scroll.
In fact you might be able to do it this way:
start a timer (with an interval that indicates slow mouse wheeling) in the mouse wheel event, then if the timer goes off perform function 1. If the mouse wheel event happens again before the timer has gone off then reset the timer and increment a counter (to keep track of the number in wheel events since you did stuff) then start a second (longer) timer. if the counter is greater then a certain threshold perform function 2. When the second timer elapses, reset the counter. Something along those lines should give you the ability to fire function 1 when slow wheel turning and function 2 when the wheel is rapidly turned through a few 'clicks'.
this code should give a (very dirty) indication of the sort of thing I was thinking of. After playing a little I'm not really sure it's a good solution though....
private void mouseWheelHandler (object sender, MouseEventArgs e)
{
slowTimer.Enabled = false;
slowTimer.Stop ();
slowTimer.Interval = 200;
slowTimer.Start();
slowTimer.Enabled = true;
m_counter++;
Trace.WriteLine(string.Format("counter={0}", m_counter));
if (fastTimer.Enabled==false)
{
fastTimer.Enabled = true;
fastTimer.Interval = 150;
fastTimer.Start ();
}
if (m_counter>5)
{
Trace.WriteLine("called method 2");
m_counter = 0;
fastTimer.Stop ();
slowTimer.Enabled = false;
slowCheckTimer.Stop ();
slowCheckTimer.Interval = 250;
slowCheckTimer.Start();
slowCheckTimer.Enabled = true;
}
}
private void slowTimer_Tick(object sender, EventArgs e)
{
Trace.WriteLine("slow timer ticked");
if (slowCheckTimer.Enabled==false)
{
Trace.WriteLine ("called method 1");
}
slowTimer.Enabled = false;
}
private void fastTimer_Tick(object sender, EventArgs e)
{
fastTimer.Enabled = false;
Trace.WriteLine("fast timer ticked");
m_counter = 0;
fastTimer.Stop ();
}
private void slowCheckTimer_Tick(object sender, EventArgs e)
{
Trace.WriteLine("slow check timer ticked");
slowCheckTimer.Stop ();
slowCheckTimer.Enabled = false;
}
Take a look at the Control.MouseWheel event.
As suggested by the Sam Holder i am posting here a modified verion of his advice to help other programmers facing the same problem.
public partial class Form1 : Form
{
int m_counter = 0;
public Form1()
{
InitializeComponent();
// Attach Mouse Wheel Event
this.MouseWheel += new MouseEventHandler(Form1_MouseWheel);
}
void Form1_MouseWheel(object sender, MouseEventArgs e)
{
// Refresh Slow Timer
slowTimer.Enabled = false;
slowTimer.Stop();
slowTimer.Interval = 150;
slowTimer.Start();
slowTimer.Enabled = true;
// Incremenet counter
m_counter++;
// Start Fast Timer
if (fastTimer.Enabled == false)
{
fastTimer.Enabled = true;
fastTimer.Interval = 50;
fastTimer.Start();
}
// If this returns true call
// the fast scroll implementation
if (m_counter > 4)
{
Console.WriteLine("Quick Method Called");
m_counter = 0;
fastTimer.Stop();
slowTimer.Enabled = false;
slowCheckTimer.Stop();
slowCheckTimer.Interval = 200;
slowCheckTimer.Start();
slowCheckTimer.Enabled = true;
}
}
private void slowTimer_Tick(object sender, EventArgs e)
{
if (slowCheckTimer.Enabled == false)
{
Console.WriteLine("Slow Method Called");
}
slowTimer.Enabled = false;
}
private void fastTimer_Tick(object sender, EventArgs e)
{
fastTimer.Enabled = false;
m_counter = 0;
fastTimer.Stop();
}
private void slowCheckTimer_Tick(object sender, EventArgs e)
{
slowCheckTimer.Stop();
slowCheckTimer.Enabled = false;
}
}

Categories

Resources