C# FFmpeg bitmap frames to picturebox - c#

I have an existing C# winforms app with live videostreams from 4 ip cameras via VLC.net (rtsp) and we take every 100ms a snapshot to analize. This is working fine. Now we like to do this instead of VLC.net with FFmpeg to have more possibilities with the (faster) captured frame. I have already a working ffmpeg wrapper sending every frame as bitmap via an event. Then I have a class "FmpegVideoWindow" inherits from PictureBox, here we listen for incoming frames and draw them on the picturebox. So instead of using the vlc-control in the form we use now a picturebox :
private void ffMpegWrapper_NewFrame1(object sender, NewFrameEventArgs e)
{
if (e != null)
{
try
{
using (Bitmap bm = new Bitmap(e.Frame))
{
frame = (Bitmap)bm.Clone();
}
}
catch
{
}
}
Invalidate();
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
if (frame != null)
{
pe.Graphics.DrawImage(frame, 0, 0, this.Width, this.Height);
//todo : disposing frame
}
}
This is working ok to see the cameras live, they have #25fps and a D1 resolution 704*576.
The problem is that every time we have other processing like opening a (settings)form, or analyzing the snapshot, the picture in the picturebox is freezing for a short time. The same program with VLC.net was never a problem.
The Ffmpeg process is done in another thread. Why does the VLC.net control running smooth in the GUI thread, and this new approach not? And what can we do to fix it? The analyzing is also done in another thread, writing the results from the analyzer to the database is done in the GUI thread. And I don't like to change that because with VLC.net it was also not needed to do that.
Thank you in advance.

Related

Failed to take photo with the webcam using the library AForge

I am making use of the AForge class library.
From this library I am using VideoSourcePlayer to take photos with the webcam.
My purpose is to create a function that allows the user to photograph images to establish them as company logo.
Not only can you choose images from the computer, but you can also capture images from the outside through the camera, since you may only want to transfer a logo of a physical support (paper) to the program.
As commented earlier in SO, (how to pause a video file played using videosourceplayer), VideoSourcePlayer does not have a Pause method or any function that allows to freeze the image.
Yes, it is true that it has the GetCurrentFrame() method, but that only gets a Bitmap from the current frame that must be passed to a PictureBox.
But I want that when the user clicks the button Capture the image of the VideoSourcePlayer simulate being frozen, and when the user presses the Delete button because he did not like the photo, then the image stops being frozen and recovers its movement.
Logic is like pausing or playing a video.
Well, there's no method for it, so I decided to look for another way to get this, and ...
If a picture is taken, use a PictureBox that contains the last frame and that is displayed on the VideoSourcePlayer, but if it is deleted, then the PictureBox is removed and the VideoSourcePlayer is returned with video.
private readonly Bitmap EmptyBitmap;
private void CaptureBtn_Click(object sender, EventArgs e)
{
Bitmap bitmap = this.VideoSource.GetCurrentVideoFrame();
ShowTakedFrame(bitmap, false);
}
private void ShowTakedFrame(Bitmap Frame, bool remove)
{
var picture = new System.Windows.Forms.PictureBox();
picture.Size = this.VideoSource.Size;
picture.Location = this.VideoSource.Location;
if (!remove)
{
this.VideoSource.Stop();
picture.Image = Frame;
this.Controls.Remove(VideoSource);
this.Controls.Add(picture);
}
else
{
this.Controls.Remove(picture);
this.Controls.Add(VideoSource);
this.VideoSource.VideoSource = this.CaptureDevice;
this.VideoSource.Start();
}
}
private void DeleteBtn_Click(object sender, EventArgs e)
{
ShowTakedFrame(EmptyBitmap, true);
}
My problem is that when capturing the photo, the image is a few seconds after the moment when you press the Capture button and when you delete the captured image, using the Delete button, the video of the VideoSourcePlayer is frozen.
Can someone help me with this?
The problem is that when you remove the PictureBox and add the VideoSourcePlayer, it creates a new object, that is, one that does not have the configuration properties of the previous one. My recommendation is that you create the capture in a different form.

C# Can I take screenshot of everything below active window

Is there any method / API allow calling something like CopyFromScreenAtDepth
I try to capture a preview of GUI below active window
then blur it to achieve something like Aero glass / OS X frosted glass blur effect
I have tried many workaround
Set the Form opacity to 0 then capture and setting back to 1, this cause my form blinking.
Make the Form background Blue with same transparent key, this will work at first time but GUI won't updating, so if I call this.Update() it will update the GUI, but cause blinking too.
My code:
private void MyForm_Load(object sender, EventArgs e) {
Timer timer1 = new Timer();
timer1.Tick += new EventHandler(UpdateBackground);
timer1.Interval = 100; // in miliseconds
timer1.Start();
}
private void UpdateBackground(object sender, EventArgs e)
{
this.BackgroundImage = null;
Bitmap myImage = new Bitmap(this.Width, this.Height);
using (Graphics g = Graphics.FromImage(myImage))
{
this.Update();
g.CopyFromScreen(new Point(this.Location.X, this.Location.Y), Point.Empty, new Size(this.Width, this.Height));
}
ImageTools.FastBlur(myImage, 4);
this.BackgroundImage = myImage;
}
There is no such CopyFromScreenAtDepth() method call for Windows.
The best you can do is to use the Windows Magnification API for C++.
There are a TONs of drawback using it, like not having control over the Window position and size, limited capabilities, to none at all, at having both copy of screen below form and being able to have other controls, and the WOW64 problem when using a 32bits application with the API under 64bits OS...
I know it's an old question, but since it's a valid question with no answer so far, I thought it would be fair to answer it.
There are also other questions like this one around (which doesn't have answer either, and may be called duplicates...)

Best way to refresh changes in an image

I have a winform c# app.
I am using Emgu for comparing the motion differences between 2 images.
I impose the changes detected onto the 1st image so in affect the first image now looks identical to the second image.
I am overriding the onpaint event of a user control to draw the image. I have to Invalidate the usercontrol to force the onpaint event.
This works well but the memory still 'spikes' a bit. Is there a way to invalidate only the pixels that have changed - like regions for instance?
This is my current code:
protected override void OnPaint(PaintEventArgs pe)
{
Graphics g = pe.Graphics;
if (CurrentFrame != null)
{
pe.Graphics.DrawImageUnscaled(CurrentFrame, 0, 0);
}
}
The CurrentFrame is a static Bitmap
Thanks

C# Photo Frame on Webcam winform

I'm developing a Winform application using c# to have something like photo kiosk that we can see in shopping mall.
I managed to find ways to capture image from webcam and store the captured image using easywebcam component. However, I want to have a photo frame around the webcam streaming video hence when the image is captured, the photo frame is included as well.
I have done research for days but still can't get any idea for this. Can any guru enlighten me for this?
I've used AForge library for working with web cam from C# and I've liked how clean it's API is.
Here the samples how to add timestamp to video, take snapshot, etc:
http://www.aforgenet.com/framework/samples/video.html
If I understand correctly, you need to have original frame when taking snapshot, so you make a copy of it before painting on frame:
Image lastUneditedFrame;
private void VideoSourcePlayer_NewFrame(object sender, ref Bitmap image)
{
if (lastUneditedFrame != null)
{
lastUneditedFrame.Dispose();
}
lastUneditedFrame = image.Clone(new Rectangle(0, 0, image.Width, image.Height), image.PixelFormat);
var graphics = Graphics.FromImage(image);
// do the drawing of photo frame
graphics.Dispose();
}
// on snapshot button click, simply call lastUneditedFrame.Save();
Thanks for your reply, I tested it with the _NewFrame event that you mentioned and add in the overlay method as below:
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap img = (Bitmap)eventArgs.Frame.Clone();
// Perform Overlay here
Graphics camImg = Graphics.FromImage(img);
Bitmap frame = new Bitmap(#"D:\PriusC1.png");
camImg.DrawImage(frame, new Point(100, 100));
camImg.Save();
pictureBox1.Image = img;
}
And it worked like a charm, thank you very much!

What might cause an ArgumentException when updating a PictureBox?

Having decided to try AForge for video and imaging stuff, I tried to implement this simple demo:
private void Main_Load(object sender, EventArgs e)
{
// enumerate video devices
FilterInfoCollection videoDevices = new FilterInfoCollection(
FilterCategory.VideoInputDevice);
// create video source
VideoCaptureDevice videoSource = new VideoCaptureDevice(
videoDevices[0].MonikerString);
// set NewFrame event handler
videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
// start the video source
videoSource.Start();
}
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
this.pictureBox1.Image = eventArgs.Frame;
}
The problem is that I always get an ArgumentException, though doesn't always happen right away. It pops up on Application.Run(new Main());, but the top of the stacktrace looks like this:
at System.Drawing.Image.get_Width() at System.Drawing.Image.get_Size()
at System.Windows.Forms.PictureBox.ImageRectangleFromSizeMode(PictureBoxSizeMode mode)
at System.Windows.Forms.PictureBox.OnPaint(PaintEventArgs pe)
Not sure if this is relevant, but the ParamName attribute of the exception is null. I've tried wrapping the image assignment in a try...catch block, but this didn't help. I've also checked to make sure that the image is not null before assignment. I've also checked for non-null, but 0x0 sized images.
What have I done wrong? Can anyone suggest a workaround?
I think the problem is that you do not make a copy
of the passed bitmap (frame) in your event handler.
The AForge documentation says:
Since video source may have multiple clients, each client is responsible
for making a copy (cloning) of the passed video frame, because the video source
disposes its own original copy after notifying of clients.
So, if you directly assign the frame to the picture box
the bitmap could be disposed by the AForge framework while the PictureBox
is trying to draw the bitmap.

Categories