Thread not exited after process/task completed - c#

Found problem in the code. It seem that the code or the thread(i think) is not properly closed. The WebDev.WebServer40.EXE still running and using all the memory of my computer. I can see the memory usage from task manager increasing even after i stopped the Visual Studio(stop debugging). I need to end task using task manager to stop the process. The code is executed whenever the page loaded, it suppose to terminate/close all the operation whenever the task completed but its not. How to solve the problem?? What should i add/remove??
namespace test
{
public partial class liveRecording : System.Web.UI.Page
{
//video codec
AVIWriter writer = new AVIWriter("MSVC");
protected void Page_Load(object sender, EventArgs e)
{
string streamingSource = "http://xxx.sample.com:85/snapshot.cgi";
string login = "login";
string password = "password";
JPEGStream JPEGSource = new JPEGStream(streamingSource);
JPEGSource.Login = login;
JPEGSource.Password = password;
JPEGSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
JPEGSource.Start();
}
public bool IsRecording = false;
int width = 0;
int height = 0;
Queue<Bitmap> frames = new Queue<Bitmap>(); //Queue that store frames to be written by the recorder thread
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs) //event handler for NewFrame
{
//get frame from JPEGStream source
//Bitmap image = eventArgs.Frame;
Bitmap image = (Bitmap)eventArgs.Frame.Clone(); //get a copy of the Bitmap from the source
width = image.Width;
height = image.Height;
if (IsRecording)
{
//enqueue the current frame to be encoded to a video file
frames.Enqueue((Bitmap)image.Clone());
}
if (!IsRecording)
{
IsRecording = true;
Thread th = new Thread(DoRecording);
th.Start();
}
}
private void DoRecording()
{
//writer.FrameRate = 5;
string SavingPath = (Server.MapPath("~\\video\\"));
string VideoName = "ICS_" + String.Format("{0:yyyyMMdd_hhmmss}", DateTime.Now) + ".avi";
writer.Open(SavingPath + VideoName, width, height);
DateTime start = DateTime.Now;
while (DateTime.Now.Subtract(start).Seconds < 30)
{
if (frames.Count > 0)
{
Bitmap bmp = frames.Dequeue();
writer.AddFrame(bmp);//add frames to AVI file
}
}
writer.Close();//close
}
}
}

Related

Why getting exception The process cannot access the file image0.gif' because it is being used by another process even if I dispose it first?

private void GenerateAnimatedGifs()
{
UnFreezWrapper unfreezWrapper = new UnFreezWrapper();
checkBoxGetImages = false;
checkBoxGetAllImages.Checked = false;
GetImagesFiles();
for (int i = 0; i < filesSatellite.Length; i++)
{
Image img = Image.FromFile(filesSatellite[i]);
img.Save(filesSatellite[i] + "ConvertedToGif.gif", System.Drawing.Imaging.ImageFormat.Gif);
img.Dispose();
File.Delete(filesSatellite[i]);
}
GetImagesFiles();
unfreezWrapper.MakeGIF(filesRadar.ToList(), #"d:\Downloaded Images\Animates Gifs\radanim.gif", 100, true);
unfreezWrapper.MakeGIF(filesSatellite.ToList(), #"d:\Downloaded Images\Animates Gifs\satanim.gif", 100, true);
}
In the loop I convert each image to gif save it in other name and then dispose the original image and then trying to delete the original image so only the ConvertedToGif images will left.
but I'm getting the exception is being used by another process on the delete line
File.Delete(filesSatellite[i]);
but isn't the file disposed already ?
The problem is that in the constructor I'm loading the images to a pictureBox using timer that is why the images are busy with another process.
If I'm not loading the images at the constructor everything will work fine.
But I want to display the images when running the application and also to be able to convert them to other formats and making other manipulations like creating animated gif of them.
I'm stuck here.
This is the constructor code
public Form1()
{
InitializeComponent();
CheckIfImagesExist();
}
And the code of the CheckIfImagesExist method
private void CheckIfImagesExist()
{
GetImagesFiles();
if (filesRadar != null)
{
if (filesRadar.Length > 1)
{
pictureBox1.Image = new Bitmap(filesRadar[0]);
trackBar1.Enabled = true;
timer1.Enabled = true;
}
if (filesRadar.Length == 1)
{
trackBar1.Enabled = false;
pictureBox1.Image = new Bitmap(filesRadar[0]);
}
}
if (filesSatellite != null)
{
if (filesSatellite.Length > 1)
{
pictureBox2.Image = new Bitmap(filesSatellite[0]);
trackBar1.Enabled = true;
timer2.Enabled = true;
}
if (filesSatellite.Length == 1)
{
trackBar1.Enabled = false;
pictureBox2.Image = new Bitmap(filesSatellite[0]);
}
}
}
The timer tick event
int satImagesCount = 0;
private void timer2_Tick(object sender, EventArgs e)
{
satImagesCount++;
if (satImagesCount == filesSatellite.Length)
{
satImagesCount = 0;
}
pictureBox2.Image = new Bitmap(filesSatellite[satImagesCount]);
if (isInsideSat)
{
pb.Image = new Bitmap(filesSatellite[satImagesCount]);
timer2.Interval = trackBar1.Value * 100;
}
}

Render to winforms picturebox over and over again

I have some bugs that need fixing, one of them involves an out of memory error.
Does anyone know how to do this properly? Thanks, I don't want it to be too messy, or too complicated. I just want to treat a new image as a buffer to render another image to (because of positional changes), and do it via a background thread. Not the UI thread (Too slow likely).
I get out of memory errors, and such. Also not able to access members of Form1 from within the thread function (images and the like throw access errors such as "Object already in use")
Here is my code:
System.Threading.Thread t;
public Image b;
public Bitmap c;
public Bitmap d;
public Bitmap e;
public Bitmap bg;
public Bitmap spr;
int spritex = 0;
int spritey = 0;
int spritedir = 1;
public Form1()
{
InitializeComponent();
Text = "Escape The Hypno Mansion!!".ToString();
t = new System.Threading.Thread(DoThisAllTheTime);
t.Start();
textBox1.Text = "Press Begin button to start!";
pictureBox1.Image = Image.FromFile(#"Images\introgirl.jpg");
b = new Bitmap(#"Images\introgirl.jpg");
c = new Bitmap(#"Images\sprite.png");
var graphics = Graphics.FromImage(b);
Pen blackpen = new Pen(Color.Black, 3);
graphics.DrawLine(blackpen, 0, 0, 100, 100);
graphics.DrawImage(c, new Point(500, 500));
pictureBox1.Image = b;
//pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
}
public void DoThisAllTheTime()
{
while (true)
{
Point p = new Point(spritex, spritey);
bg = new Bitmap(#"Images\test.bmp");
spr = new Bitmap(#"Images\sprite.png");
using (var graphics = Graphics.FromImage(bg))
{
graphics.DrawImage(spr, p);
}
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
}
pictureBox1.Image = bg;
pictureBox1.Invalidate();
if (spritedir == 1) { spritex += 5; }
if (spritedir == 2) { spritex -= 5; }
if (spritex < 0) { spritex = 0; spritedir = 1; }
if (spritex > 700) { spritex = 700; spritedir = 2; }
}
}
The reason you can't change the image in your picturebox is because the thread that created the image is not the thread that created the picturebox.
In a debugger you can check this by asking the picturebox for InvokeRequired (function Control.IsInvokeRequired) just before changing the function.
So let's rewrite your function and show that modern classes Like Task are much easier to use the your thread.
I'll start your task when the form is loading, and try to stop it when the form is closing.
private Task myTask = null;
private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
private void OnFormLoading(object sender, EventArgs e)
{
// Start the task
this.myTask = Task.Run( () => DoMyWork(this.cancellationTokenSource.Token));
}
private void OnFormClosing(object sender, FormClosingEventArgs e)
{
// if the Task is still running, ask it to stop itself:
if (myTask != null && !myTask.IsCompleted)
{ // ask the task to stop and wait until it is completed:
this.cancellationTokenSource.Cancel();
// all Tokens extractes from this source will get state CancellationRequested
// wait maximum 5 seconds until the task is completed:
this.UseWaitCursor = true;
this.myTask.Wait(TimeSpan.FromSeconds(5));
this.UseWaitCursor = false;
// cancel closing if the task is still not completed
e.Cancel = !this.myTask.Completed;
}
}
Now the function DoMyWork:
private void DoMyWork(CancellationToken cancellationToken)
{
// Do the same as in your DoThisAllTheTime
// except that you regularly check cancellationToken.IsCancelRequested:
while(!cancellationToken.IsCancelRequested)
{
// calculate the image to display
var imageToDisplay = ...
this.DisplayImage(imageToDisplay);
}
}
void DisplayImage(Image imageToDisplay)
{
if (this.pictureBox1.InvokeRequired)
{
this.Invoke(new MethodInvoker( () => this.DisplayImage(imageToDisplay)));
}
else
{
this.PictureBox1.Image = imageToDisplay;
}
}
See:
How to cancel a Task and its children
Use InvokeRequired with lambda expression
Dispose every disposable instances before the loop ends. Your memory leak is related with disposable items not being cleaned from memory, so you'll eventually run out of memory in your infinite loop.
At the very least, you'll want to dispose both bitmaps at the end of the loop:
bg = new Bitmap(#"Images\test.bmp");
spr = new Bitmap(#"Images\sprite.png");

C# WPF Thread accessed from a thread other than the

I'm trying to create a WPF application that takes a video and screenshots it every second while playing.
Code
public Form2(string url)
{
InitializeComponent();
axWindowsMediaPlayer1.URL = url;
new Thread(delegate(){
CheckFrame();
}).Start();
}
private void CheckFrame()
{
for (int i = 0; i < 100; i++)
{
Bitmap screenshot = new Bitmap(axWindowsMediaPlayer1.Bounds.Width, axWindowsMediaPlayer1.Bounds.Height);
Graphics g = Graphics.FromImage(screenshot);
g.CopyFromScreen(axWindowsMediaPlayer1.PointToScreen(
new System.Drawing.Point()).X,
axWindowsMediaPlayer1.PointToScreen(
new System.Drawing.Point()).Y, 0, 0, axWindowsMediaPlayer1.Bounds.Size);
pictureBox1.BackgroundImage = screenshot;
System.Threading.Thread.Sleep(1000);
}
}
When using the x y values of the media player itself I get the error
Additional information: Cross-thread operation not valid: Control 'axWindowsMediaPlayer1'
accessed from a thread other than the thread it was created on.
When using 0 as X/Y values so just 0px and 0px from the form point of view,it runs fine
In this case you can use Timer:
Timer tm = new Timer();
public Form2(string url)
{
InitializeComponent();
axWindowsMediaPlayer1.URL = url;
tm.Interval = 1000;
tm.Tick += tm_Tick;
tm.Start();
}
int i = -1;
void tm_Tick(object sender, EventArgs e)
{
if (++i < 100)
{
Bitmap screenshot = new Bitmap(axWindowsMediaPlayer1.Bounds.Width, axWindowsMediaPlayer1.Bounds.Height);
Graphics g = Graphics.FromImage(screenshot);
g.CopyFromScreen(axWindowsMediaPlayer1.PointToScreen(
new System.Drawing.Point()).X,
axWindowsMediaPlayer1.PointToScreen(
new System.Drawing.Point()).Y, 0, 0, axWindowsMediaPlayer1.Bounds.Size);
pictureBox1.BackgroundImage = screenshot;
}
else
{
i = -1;
tm.Stop();
}
}
Note: To take screenshot with your method, axWindowsMediaPlayer1 must visible on the screen.

Obtain full-page screenshot from WebBrower component

I am attempting to capture a full-page screenshot of any website a user is viewing using the WebBrowser component.
At present, I am able to only able to capture what a user is viewing from within the WebBrowser. However, the screenshot image created is the size of the webpage. For example, below is a (half-sized) screenshot of the BBC website, the black area is actually saved transparent but I've filled it black for visibility.
I have seen solutions where a new WebBrowser instance is used to fetch a fullpage snapshot. However, I need the screenshot to be exactly of the page as the user is viewing it at the time, much like how the full-page screenshot works in Firefox.
My code below that generated the above image:
private void button1_Click(object sender, EventArgs e)
{
while (webBrowser1.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
int scrollWidth = 0;
int scrollHeight = 0;
scrollHeight = webBrowser1.Document.Body.ScrollRectangle.Height;
scrollWidth = webBrowser1.Document.Body.ScrollRectangle.Width;
webBrowser1.Size = new Size(scrollWidth, scrollHeight);
Bitmap bm = new Bitmap(scrollWidth, scrollHeight);
webBrowser1.DrawToBitmap(bm, new Rectangle(0, 0, bm.Width, bm.Height));
bm.Save(#"D:\Screenshots\test.png", ImageFormat.Png);
}
I've got a good working one..
private void button1_Click(object sender, EventArgs e)
{
using (FileDialog fd = new SaveFileDialog())
{
fd.Filter = "Image (*.png)|*.png";
if (fd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
new WebPageSnap(webBrowser1.Url.ToString(), fd.FileName);
//might take 3 or 4 seconds to save cauz it has to load again.
}
}
}
class WebPageSnap
{
WebBrowser wb;
string outFile;
public WebPageSnap(string url, string outputFile)
{
wb = new WebBrowser();
wb.ProgressChanged += wb_ProgressChanged;
outFile = outputFile;
wb.ScriptErrorsSuppressed = true;
wb.ScrollBarsEnabled = false;
wb.Navigate(url);
}
void wb_ProgressChanged(object sender, WebBrowserProgressChangedEventArgs e)
{
if (e.CurrentProgress == e.MaximumProgress)
{
wb.ProgressChanged -= wb_ProgressChanged;
try
{
int scrollWidth = 0;
int scrollHeight = 0;
scrollHeight = wb.Document.Body.ScrollRectangle.Height;
scrollWidth = wb.Document.Body.ScrollRectangle.Width;
wb.Size = new Size(scrollWidth, scrollHeight);
Bitmap bitmap = new Bitmap(wb.Width, wb.Height);
for (int Xcount = 0; Xcount < bitmap.Width; Xcount++)
for (int Ycount = 0; Ycount < bitmap.Height; Ycount++)
bitmap.SetPixel(Xcount, Ycount, Color.Black);
wb.DrawToBitmap(bitmap, new Rectangle(0, 0, wb.Width, wb.Height));
bitmap.Save(outFile, ImageFormat.Png);
}
catch { }
}
}
}
.
;Here's the result
.

Webcam saving from camera without freezing application

Hey I am trying to save a video of a webcam and save it as uncompressed. However Anytime click on the save button the application freezes until the save is complete. I will be grateful for any advice given. I am using managed code for the webcam "FLea 3" (from Points grey)
private void button1_Click(object sender, EventArgs e)
{
uint k_numImages = 100;
// ManagedAVIRecorder aviRecorder = new ManagedAVIRecorder();
// List<ManagedImage> imageList = new List<ManagedImage>();
List<ManagedImage> imageList = new List<ManagedImage>();
ManagedImage rawImage = new ManagedImage(m_rawImage);
for (int imageCnt = 0; imageCnt < k_numImages; imageCnt++)
// while (m_grabImages == true)
{
m_camera.RetrieveBuffer(rawImage);
ManagedImage tempImage = new ManagedImage(rawImage);
imageList.Add(tempImage);
}
if (m_grabImages==true)
{
//Encoding bit
string aviFileName;
AviOption option = new AviOption();
option.frameRate = 24;
aviFileName = String.Format("SaveCSharp-aviuncompressed");
aviRecorder.AVIOpen(aviFileName, option);
// aviFileName = String.Format("SaveCSharp-h264");
// H264Option option = new H264Option();
// option.frameRate = 24;
// option.bitrate = 20000000;
// option.height = Convert.ToInt32(m_rawImage.rows);
// option.width = Convert.ToInt32(m_rawImage.cols);
// aviRecorder.AVIOpen(aviFileName, option);
for (int imageCnt = 0; imageCnt < imageList.Count; imageCnt++)
{
aviRecorder.AVIAppend(imageList[imageCnt]);
}
aviRecorder.AVIClose();
}
}
private void button2_Click(object sender, EventArgs e)
{
// aviRecorder.AVIClose();
}
}
}
You most likely want to run the record operation on another thread. However, that'll get slightly tricky as you have to pass messages back and forth to the recorder thread, to tell it when to stop, for example.

Categories