Synchronous sound playback from video source in VideoSourcePlayer control - c#

I'm using the Video Source Player control from AForge.Controls to play a few video clips within a winforms application.
The code is something like this.
string fileName = #"C:\path\to\file.example";
videoSourcePlayer.VideoSource = new AForge.Video.AsyncVideoSource(new FileVideoSource(fileName), true);
videoSourcePlayer.Start();
The video file includes both audio and video streams, however as far I'm aware the control only handles video and not audio.
How can I then play the audio stream in a synchronous fashion with the video source player control?
Thank you.
EDIT:
The Video Source Player control has a event named NewFrame, which allows to determine the precise video position which could be useful to keep the audio being played synchronized with the video.

Since you mentioned:
I'm only looking for other alternative in which is possible to
reproduce the audio contained the video file and somehow keep it
synchronized with the video player control...
Maybe you can have a better luck by using a ElementHost and using WPF media control.
If this solution is eligible for you follow this steps:
Create a new WPF UserControl and add to your WindowsForms app.
In this UserControl add a media element and configure the way you want.
Build the solution.
Now in the toolbox must appear YourSolutionName Controls and you controls must be there.
Just drag it to your WindowsForms app and it must create an ElementHost.
I've created the UserControl as follow:
<MediaElement Name="VideoMediaElement"
Source="Media/Wildlife.wmv"
LoadedBehavior="Manual"/>
Just remember in this example this file must be side-by-side with your app in a Media folder. If you miss this step it will give you the strange and not helpful error 0xC00D11B1.
The loaded behavior Manual will give you the chance to control de video more freely.
After that you can do whathever you want in this UserControl like create Play and Pause:
internal void Play()
{
this.VideoMediaElement.Play();
}
And to access them in WindowsForms do this:
private void WindowsFormsButton_Click(object sender, EventArgs e)
{
var videoControl = this.MyElementHost.Child as VideoUserControl;
videoControl.Pause();
}
Hope this helps. WPF MediaElement is much more easy to seach for than other libs.

Related

Is there any default time interval for mediaended event to be fired?

I have a WPF application which dynamically loads video or image files(depending on user's choice, to a MediaElement control.
It is working fine when it is a video and gets the MediaEnded event fired on ending the video.
But when I load an image, the MediaEndedevent is fired within 5 seconds.
Is it a default value? or can I change it programmatically?
Is there any property to change this interval or disable such an option?
Is it possible to make it paused until a specific action?
I have set the following properties as follows
MediaControl1.LoadedBehavior = MediaState.Manual;
MediaControl1.UnloadedBehavior = MediaState.Manual;
MediaElement is a (very thin) wrapper around Windows Media Player (or rather - uses the same framework which is used by Windows Media Player). If you open an image in Windows Media Player - you will see it will "play" it like a slideshow (even for 1 image), for about 5 seconds. That's why you get MediaEnded event in 5 seconds - Windows Media Player plays slideshow with your image for that duration. I doubt there is a way to change this from WPF (because it's behavior of external program\framework, not related to MediaElement itself) and I'm not aware of the way to change this for Windows Media Player (and even if there is such a way - it will have global effect and you probably don't want to modify your clients computer in such a way).
To solve your problem - just don't use MediaElement for displaying images - use something like Image control. If you have really strong reasons to do that - you can pause MediaElement with Pause method after your "slideshow" has been loaded, then it will not fire MediaEnded event. All in all - I cannot imagine any use case where you really have to use MediaElement for images.
You can repeat the media when you load image. Handle MediaEnded event like this:
void me_MediaEnded(object sender, EventArgs e)
{
//play video again
mediaElement.Position = new TimeSpan(0, 0, 1);
mediaElement.Play();
}
Additionally see this. It may help:
https://stackoverflow.com/a/3406857/5675763

UWP Windows.Media.Playback - Stop/Unload Clip

I'm writing a UWP application which contains the MediaPlayer object. I am wanting to program a stop button which stops the media and sets the media to black however I can't find an approach to do it short of loading a short 'black' clip as an internal asset or hiding the element via the compositor.
The MediaPlayer does not have a function for stop, only play/pause and further, setting the media source to null simply pauses playback and freezes on the last frame shown rather than dropping to black.
Any suggestions would be much appreciated.
I recently had a related problem that boiled down to unloading media from a MediaPlayerElement.
If you navigate away from a page when playback is active, the MediaPlayerElement would not suspend or unload a playback in progress so the user would keep hearing the audio. If you re-open player's page, a new instance of a player control will be created and user may hear multiple audio tracks at once (although this requires different media sources). So it was essential to unload the media at some place like player's Unloaded event handler, page Unloaded handler, or OnNavigatingFrom/OnNavigatedFrom overrides.
Anyway, the code below stops and unloads a video/clip/media from the MediaPlayerElement.
MyMediaPlayerElement.MediaPlayer.Pause();
MyMediaPlayerElement.Source = null;
Actually, a null assignment line works just fine as a stop-and-unload, but since as of now (3/19/2018), MS documentation doesn't seem to cover how nullifying the source supposed to work, I prefer to keep an otherwise unnecessary call to Pause() here as well.
The MediaPlayer does not have a function for stop, only play/pause
As you known, MediaPlayerElement doesn't have stop method at default. Since MediaPlayerElement is newly for version 1607, for earlier version of Windows 10 we use MediaElement instead, so you can simply use MediaElement instead. MediaElement has Stop method, and after you invoke the stop method, the MediaElement will show black and set the media to begin which is just what you want. Code as follows:
<MediaElement x:Name="mediaelement" AreTransportControlsEnabled="True" Height="400" Width="400" AutoPlay="True" Source="http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4"></MediaElement>
<Button x:Name="btnstop" Click='btnstop_Click' Content="stop"></Button>
Code behind:
private void btnstop_Click(object sender, RoutedEventArgs e)
{
mediaelement.Stop();
}

Is there a way of using ffmpeg in c# app?

I'm using the ffmpeg.org and when I run ffmpeg -y -f vfwcap -r 25 -i 0 out.mp4 in command line I can grab the video from my webcam and write it to the out.mp4 file. However, I can't see that stream anywhere. I thought about writing some simple wrapper in c# that is built on ffmpeg functionality, so far I found post mentioned on Stack before, but there's nothing about displaying the data live (instead of saving it into the file). Does anyone have any experience with it? Can I for example 'draw' the received data from webcam on a picture box or on some other component?
Thanks!
One of the comments in your linked post says this:
How about writing a C++/CLI wrapper around ffmpeg's native interface
and then calling your wrapper interface from your application?
I think this is exactly what you want to do. (Note that FFmpeg has worked fine for years in recent versions of Visual Studio, so the response in the linked post to this comment doesn't apply.)
You would basically create a camera input (this lives in libavdevice), and then you would encode this to h264 in a mp4 container (see output_example.c). To get a live display, you would take the data generated from the vfwcap source, decode it (using the "rawvideo" decoder in libavcodec). This gives you a AVFrame, which has the data pointers to display the image in any native UI element in your application, typically using direct3d or opengl. Read the documentation to learn more about all of this.
You could use a MediaElement or MediaPlayer control.
MediaElement is a UIElement that is supported by the Layout and can be
consumed as the content of many controls. It is also usable in
Extensible Application Markup Language (XAML) as well as code.
MediaPlayer, on the other hand, is designed for Drawing objects and
lacks layout support. Media loaded using a MediaPlayer can only be
presented using a VideoDrawing or by directly interacting with a
DrawingContext. MediaPlayer cannot be used in XAML.
MediaElement
Sample XAML:
<MediaElement Source="path\to\out.mp4" Name="myMediaElement"
Width="450" Height="250" LoadedBehavior="Manual" UnloadedBehavior="Stop" Stretch="Fill"
MediaOpened="Element_MediaOpened" MediaEnded="Element_MediaEnded"/>
MediaPlayer
//
// Create a VideoDrawing.
//
MediaPlayer player = new MediaPlayer();
player.Open(new Uri(#"sampleMedia\xbox.wmv", UriKind.Relative));
VideoDrawing aVideoDrawing = new VideoDrawing();
aVideoDrawing.Rect = new Rect(0, 0, 100, 100);
aVideoDrawing.Player = player;
// Play the video once.
player.Play();
Multimedia Overview on MSDN

Import frames from a video

I'm using MediaPlayer to open a video and DrawingContext.DrawVideo() to get a specific frame from a video source.
The problem is that I can't know if the MediaPlayer is positioned at the right place.
Therad.Sleep(500) is a hack.
Is there another easy way of getting frames from a video source? Or should I start looking for a DirectShow solution?
There's a somewhat elderly but potentially useful implementation of frame grabbing with a MediaPlayer here:
dlaa.me/blog/post/8921665
Here is the simple structure of the media grabber:
LoadVideo();
//Add event handler to the Changed event.
GetFirstFrame();
//Change video Position.
//When the Changed event fires:
GetCurrentFrame();

Drawing on Video within C#

I am making an application that will allow users to apply certain tools to analyse videos & images. I need help with how i actaully draw/write on the video loaded into windows media player within my form and being able to save it on. It needs to be able to lert the user draw freehand and shapes on it.
Thanks in Advance,
Chris :)
This is a non-trivial, if not impossible task to accomplish with the wmp control in winforms.
I don't know of any way to actually draw on the wmp but you could draw on a transparent panel overlaid over the wmp. This will not work will the video is playing but you can show the drawing while it is paused. I have used this technique to draw over a 3rd party video control that works similarly to wmp.(Edit - this does not seem to work with the wmp control)
However, as real transparent panels are also rather tricky in winforms, another way would be to grab an image from the video and draw on the overlaid image. Again, only when it is paused.
This commercial control does enable drawing over the video. It has an event that fires every frame that you can use to do the drawing. The big downside, though is that you can't really do anything too fancy as your drawing routine needs to finish before the next frame is drawn.
I would strongly encourage you to use WPF(even if its a wpf control hosted within a winforms app) to show your video. It is a whole lot easier to draw on video(including playing video) in wpf.
EDIT
I just tested drawing over the wmp using a transparent panel and its doesn't behave as my 3rd party control did,so I suggest you do the video playing bit in WPF and host that in your winforms app. (I just tested that too using #Callums inkcanvas suggestion and it works like a charm)
If you are using WPF, try placing an InkCanvas on top of your video and setting the Background to transparent. You can then save and load up the shapes the users draw on top of the video.
A little proof-of-concept with a picture instead of a video:
I suspect you may be using WinForms though, where this may be more difficult. If so, a good excuse to learn WPF!
EDIT: With WinForms, you would have to make your own custom control that acts as a transparent overlay and add brush strokes to it. It would be extremely hard to implement well (with transparent background, which doesn't play well with
WinForms). I would recommend using WPF if you are still at a stage you can change your application's UI. WPF works on XP and up.
EDIT2: After googling, there are some InkCanvas equivalents that people have made for WinForms, but I have no idea how good they are and may not support transparent backgrounds.
You could always have the video that you want annotated in a new WPF window and the rest of your application in WinForms.
I have found how to do this.
Here is one way in WPF using Canvas
private void buttonPlayVideo_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.Filter = "All Files|*.*";
Nullable<bool> result = dlg.ShowDialog();
if (result == true) {
MediaPlayer mp = new MediaPlayer();
mp.Open(new Uri(filename));
VideoDrawing vd = new VideoDrawing();
vd.Player = mp;
vd.Rect = new Rect(0, 0, 960, 540);
DrawingBrush db = new DrawingBrush(vd);
canvas.Background = db;
mp.Play();
}
}
then create mouse events for Canvas and draw with it
Point startPoint, endPoint;
private void canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(canvas);
}
private void canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
endPoint = e.GetPosition(canvas);
Line myLine = new Line();
myLine.Stroke = System.Windows.Media.Brushes.LightSteelBlue;
myLine.X1 = startPoint.X;
myLine.Y1 = startPoint.Y;
myLine.X2 = endPoint.X;
myLine.Y2 = endPoint.Y;
myLine.HorizontalAlignment = HorizontalAlignment.Left;
myLine.VerticalAlignment = VerticalAlignment.Center;
myLine.StrokeThickness = 2;
canvas.Children.Add(myLine);
}
This can be done in WinForms but it is not easy. There is transparent form support with alpha blending in WinForms. Use the following CreateParams for the transparent overlay form: WS_EX_LAYERED, WS_EX_TRANSPARENT. Check the MSDN references for this type of window: http://msdn.microsoft.com/en-us/library/ms997507.aspx, http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#layered.
Put a transparent form above your video control and you can draw anything you want on it. Move and resize events need to be coordinated between your video window and the transparent form above it. Redrawing the overlay needs to use UpdateLayeredWindow() in user32.dll.
I learned quite a bit from this example: http://www.codeproject.com/Articles/13558/AlphaGradientPanel-an-extended-panel.
You might look at XNA (www.xna.com) from Microsoft. It is made for managed languages like c# and should support video.
I've only used it for drawing in c#, but it gets the job done.
I should also note that XNA will function as part of a regular Windows Forms app. For what it's worth, I have also prototyped something like this with Flash; Flash allows you to import each frame of the movie file into the editor and create a SWF that can respond to user interaction.
However, this approach is useless if you need to update the movie in real-time. Flash (last I checked) could only import the movie at design time.
Ok, by far and away the best way of doing this is to use Silverlight. Silverlight supports all of the major streaming formats and also provides complete access to the framebuffer.
Easy :-)

Categories