Hi,
I'm using C#.net 3.0. I have use the frameGrabber class to grab the frames from the video file and to convert the frames into bitmap format.The code is giving error in the "foreach (FrameGrabber.Frame f in fg)line of the code" highlighting "in" giving error---"InvalidCastException was unhandled by user"(Unable to cast COM object of type'DirectShowLib.DES.MediaDet' to interface type 'DirectShowLib.DES.IMediaDet'.This operation failed because the QueryInterface call on the COM component for the interface with IID '{65BD0710-24D2-4FF7-9324-ED2E5D3ABAFA}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).).I use this background worker so that I can stop the extraction of frame in middle of execution,but if i don't use this Background worker the code is running properly.

private void button43_Click(object sender, EventArgs e)//Extract Button
        {
            backgroundWorker1.RunWorkerAsync();
        }

        private void button44_Click(object sender, EventArgs e)//Stop Button
        {
            backgroundWorker1.CancelAsync();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            string outPath = txtExtBitmap.Text;
            System.IO.Directory.CreateDirectory(outPath);

            if (fg != null)
            {
                foreach (FrameGrabber.Frame f in fg)//error in this line highlighting "in"
                {
                    using (f)
                    {
                        picBoxFrame.Image = (Bitmap)f.Image.Clone();
                        f.Image.Save(System.IO.Path.Combine(outPath, "frame" + f.FrameIndex + ".bmp"), System.Drawing.Imaging.ImageFormat.Bmp);
                        //Application.DoEvents();
                    }

                    if (fg == null)
                    {
                        return;
                    }
                }
            }
            if (backgroundWorker1.CancellationPending)
            {
                e.Cancel = true;
                return;
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                MessageBox.Show("Operation Cancelled");
            }
            else
            {
                MessageBox.Show("OperationCompleted");
            }
        }

Recommended Answers

All 13 Replies

You mean when you don't use BackgroundWorker component everything runs well?

You mean when you don't use BackgroundWorker component everything runs well?

yes everything runs fine but I'm not able to stop the extraction of frames in the middle of execution (to stop it i have to shutdown the application).so for the the purpose of stopping the execution in middle I have to use this background worker.

Just I need to make sure of something but I'll tell you to work with multithreading without using BackgroundWorker component

Thread thrd;
Extract_ButtonHandler_Click(object sender, EventArgs e)
{
thrd = new Thread(new ThreadStart(ExtractFrames));
}
string outPath = "you path";
///Extracts frames and saves them in directory
void ExtractFrames()
{
foreach (FrameGrabber.Frame f in fg)//error in this line highlighting "in"
{
using (f)
{
picBoxFrame.Image = (Bitmap)f.Image.Clone();
f.Image.Save(System.IO.Path.Combine(outPath, "frame" + f.FrameIndex + ".bmp"), System.Drawing.Imaging.ImageFormat.Bmp);
//Application.DoEvents();
}
}
Cancel_ButtonHandler_Click(object sender, EventArgs e)
{
thrd.Suspend();
}

Try above code and tell me if you got an error, you may need to customize the code but I expect you'll understand the idea.

Just I need to make sure of something but I'll tell you to work with multithreading without using BackgroundWorker component

Thread thrd;
Extract_ButtonHandler_Click(object sender, EventArgs e)
{
thrd = new Thread(new ThreadStart(ExtractFrames));
}
string outPath = "you path";
///Extracts frames and saves them in directory
void ExtractFrames()
{
foreach (FrameGrabber.Frame f in fg)//error in this line highlighting "in"
{
using (f)
{
picBoxFrame.Image = (Bitmap)f.Image.Clone();
f.Image.Save(System.IO.Path.Combine(outPath, "frame" + f.FrameIndex + ".bmp"), System.Drawing.Imaging.ImageFormat.Bmp);
//Application.DoEvents();
}
}
Cancel_ButtonHandler_Click(object sender, EventArgs e)
{
thrd.Suspend();
}

Try above code and tell me if you got an error, you may need to customize the code but I expect you'll understand the idea.

hi,
thanks for your reply.I use the code given below but this time i got error when i press the stop button that --"ThreadStateException was Unhandled"(Thread is not running; it cannot be suspended.)

Thread fThread;
void frameExtract()
        {
            string outPath = txtExtBitmap.Text;
            System.IO.Directory.CreateDirectory(outPath);

            if (fg != null)
            {
                foreach (FrameGrabber.Frame f in fg)
                {
                    using (f)
                    {
                        picBoxFrame.Image = (Bitmap)f.Image.Clone();
                        f.Image.Save(System.IO.Path.Combine(outPath, "frame" + f.FrameIndex + ".bmp"), System.Drawing.Imaging.ImageFormat.Bmp);
                        Application.DoEvents();
                    }

                    if (fg == null)
                    {
                        return;
                    }
                }
            }
        }

private void button43_Click(object sender, EventArgs e)//Extract Button
        {
            fThread = new Thread(new ThreadStart(frameExtract));
        }

        private void button44_Click(object sender, EventArgs e)//Stop Button
        {
            fThread.Suspend();
        }

please help!!

Sorry I forgot something try this

Extract_ButtonHandler_Click(object sender, EventArgs e)
{
thrd = new Thread(new ThreadStart(ExtractFrames));
thrd.Start();
}

If Ramy's way works for you, then best of luck, but as for the original post. The problem with using the background worker was probably that whatever dll control you were using expects a drawing surface and you weren't supplying one, possible, In not familiar with this frame grabber, which makes it harder to help, more importantly the objects you were using in the background worker would have to be passed to the background workers dowork event handler via an object in the DoWorkEventArgs. So the code for your background worker is not correct.

What ever the control famegrabber is needs to be instantiated inside the dowork event handler, or a function that the event hander calls, all the code must not interact with anything from the original code. so essentially the code in the dowork event handler needs to be complete, as in like it was its own stand alone style application, so it would instantiate a new object of the control, pass to that whatever collection or file name you needed, then add that data to a new collection, or a save it to a file, then pass that info back to the work completed event via the e.Result property.

many programmers think one day they are just going to hop into multithreading applications and don't' realize how much trouble it can cause. Its actually difficult. and the .net threading class makes it almost too easy. making it seem that less is going on that actually is.

a good way to understand backgroundworker would be to write a console app that does what you want without accepting any information. hard code what info and paths you need, and make an app that does an example of it just by running it.

Then take all the data from the Main function, and plop it into the dowork method.

then edit it to accept the "details" about what it should be doing via the DoWorkEventArgs. They will allow you to pass that informatin in as an object. say you needed serveral strings, you could pass a string array, or even an array of arrays.

If you still can't figure it out. Either throw me a link to the "frame grabber" control so I can find out what it does. or just ask for a example. I will post a simple background worker task example. like a file downloader or something if you need it. just so you see how it goes.

Sorry for the verbatim.

Diamonddrake, I understand multithreading well but the asker didn't mention if they use usercontrol or just call a method, if they say drag and drop this control on form it means usercontrol initiated in a thread which is different than the thread inteact with this usercontrol and we need to customize the code. but all in all in many cases I don't exactly answer the question well because I'm not with the developer who faces the problem, in my entire life if someone face a problem I meet them and stay to solve the problem together.

i was just saying, in that code,
FrameGrabber.Frame and picBoxFrame.Image
both refer to objects from the originating thread. you can't access them directly from the worker thread. that's a cross thread exception.

These classes would need to be instantiated in the worker thread, or at least that is my understanding of threading. which I have used recently on 2 projects.

I know both restrictions but I've no exact information about their project.

ok, I have edited the example that comes with the download you linked me to to support a background thread that supports cancellation. It works perfect. Turns out with that code several things had to be done, the whole framegrabber object needed to be created in the new thread,(which is what I was trying to get at before) also the paths needed to be passed to the thread by and object. the preview image needed to be passed as a progress object argument and set via the progressed changed event. a check had to be added to the loop that extracts the frames to check for a cancellation. and since cancel and grab will never need to be pused at the same time, I simply added a switch to make them the same button.

This is the entire class from the project edited. replace the entire class in your project with this one, or just edit it to match. If you have any questions just ask. remember to add a background worker and set its event handers to the ones I added to the class.

This code is tested and effective, if you need a VS2008 Example. I have it and can post the finished working code if need be.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using User.DirectShow;

namespace FrameGrabberTester
{
	public partial class Form1 : Form
	{
		//private FrameGrabber fg;
        private string pathFILE;

		public Form1()
		{
			InitializeComponent();
		}

		private void button1_Click(object sender, EventArgs e)
		{
			if(openFileDialog1.ShowDialog() == DialogResult.OK)
			{
                pathFILE = openFileDialog1.FileName;
			}
		}

		private void button3_Click(object sender, EventArgs e)
		{
			folderBrowserDialog1.ShowDialog();
		}

		private void button2_Click(object sender, EventArgs e)
		{

            if (button2.Text == "Cancel")
            {
                backgroundWorker1.CancelAsync();
                return;
            }
            else
            {

                button1.Enabled = false;
                button3.Enabled = false;

                button2.Text = "Cancel";

                string outPath = (folderBrowserDialog1.SelectedPath == "" ? System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test") : folderBrowserDialog1.SelectedPath);
                System.IO.Directory.CreateDirectory(outPath);

                try
                {
                    string[] A = { pathFILE, outPath };
                    backgroundWorker1.WorkerReportsProgress = true;
                    backgroundWorker1.WorkerSupportsCancellation = true;
                    backgroundWorker1.RunWorkerAsync(A);


                }
                catch (Exception ex)
                {
                    MessageBox.Show("{Error: " + ex.ToString());
                }

            }
		}

		protected override void OnClosed(EventArgs e)
		{
			base.OnClosed(e);
			//fg = null;
		}

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            //lets get back our paths
            string[] S = (string[])e.Argument;

            // the source video path

            string sourcePATH = S[0];

            // the path to write the file to

            string destPATH = S[1];

            //keep track of out background worker

            BackgroundWorker bwAsync = sender as BackgroundWorker;

            //now lets initiate an instance of the class that proccesses the video.

             FrameGrabber fg = new FrameGrabber(sourcePATH);
             Image PREVIEW;

             if (fg != null)
             {
                 foreach (FrameGrabber.Frame f in fg)
                 {
                     using (f)
                     {
                         PREVIEW = (Bitmap)f.Image.Clone();
                         f.Image.Save(System.IO.Path.Combine(destPATH, "frame" + f.FrameIndex + ".bmp"), System.Drawing.Imaging.ImageFormat.Bmp);
                         Application.DoEvents();
                         int IProgressPercentage = fg.FrameCount / fg.FrameCount; //doesn't report which frame its on, so couldn't proccess this, could have edited the library to do so, but that's outside the scope of this example.
                         backgroundWorker1.ReportProgress(IProgressPercentage, PREVIEW);
                         //check if we have been canceled
                         if (bwAsync.CancellationPending)
                         {
                             e.Cancel = true;
                             return;
                         }

                     }

                     if (fg == null)
                     {
                         return;
                     }
                 }
             }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            pictureBox1.Image = (Image)e.UserState;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            

            if (e.Error == null)
            {
                if (e.Cancelled == true)
                {
                    MessageBox.Show("Canceled");
                    button2.Text = "grab all!";
                    button1.Enabled = true;
                    button3.Enabled = true;
                    return;
                }
                else
                {
                    MessageBox.Show("Finished");
                    button2.Text = "grab all!";
                    button1.Enabled = true;
                    button3.Enabled = true;
                }
            }
            else
            {
                MessageBox.Show("ERROR " + e.Error.ToString());
                button2.Text = "grab all!";
                button1.Enabled = true;
                button3.Enabled = true;
            }
        }
	}
}

Best of luck friend. and I hope you learn much from this.
commented: Done well! perfect. +7

ok, I have edited the example that comes with the download you linked me to to support a background thread that supports cancellation. It works perfect. Turns out with that code several things had to be done, the whole framegrabber object needed to be created in the new thread,(which is what I was trying to get at before) also the paths needed to be passed to the thread by and object. the preview image needed to be passed as a progress object argument and set via the progressed changed event. a check had to be added to the loop that extracts the frames to check for a cancellation. and since cancel and grab will never need to be pused at the same time, I simply added a switch to make them the same button.

This is the entire class from the project edited. replace the entire class in your project with this one, or just edit it to match. If you have any questions just ask. remember to add a background worker and set its event handers to the ones I added to the class.

This code is tested and effective, if you need a VS2008 Example. I have it and can post the finished working code if need be.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using User.DirectShow;

namespace FrameGrabberTester
{
	public partial class Form1 : Form
	{
		//private FrameGrabber fg;
        private string pathFILE;

		public Form1()
		{
			InitializeComponent();
		}

		private void button1_Click(object sender, EventArgs e)
		{
			if(openFileDialog1.ShowDialog() == DialogResult.OK)
			{
                pathFILE = openFileDialog1.FileName;
			}
		}

		private void button3_Click(object sender, EventArgs e)
		{
			folderBrowserDialog1.ShowDialog();
		}

		private void button2_Click(object sender, EventArgs e)
		{

            if (button2.Text == "Cancel")
            {
                backgroundWorker1.CancelAsync();
                return;
            }
            else
            {

                button1.Enabled = false;
                button3.Enabled = false;

                button2.Text = "Cancel";

                string outPath = (folderBrowserDialog1.SelectedPath == "" ? System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test") : folderBrowserDialog1.SelectedPath);
                System.IO.Directory.CreateDirectory(outPath);

                try
                {
                    string[] A = { pathFILE, outPath };
                    backgroundWorker1.WorkerReportsProgress = true;
                    backgroundWorker1.WorkerSupportsCancellation = true;
                    backgroundWorker1.RunWorkerAsync(A);


                }
                catch (Exception ex)
                {
                    MessageBox.Show("{Error: " + ex.ToString());
                }

            }
		}

		protected override void OnClosed(EventArgs e)
		{
			base.OnClosed(e);
			//fg = null;
		}

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            //lets get back our paths
            string[] S = (string[])e.Argument;

            // the source video path

            string sourcePATH = S[0];

            // the path to write the file to

            string destPATH = S[1];

            //keep track of out background worker

            BackgroundWorker bwAsync = sender as BackgroundWorker;

            //now lets initiate an instance of the class that proccesses the video.

             FrameGrabber fg = new FrameGrabber(sourcePATH);
             Image PREVIEW;

             if (fg != null)
             {
                 foreach (FrameGrabber.Frame f in fg)
                 {
                     using (f)
                     {
                         PREVIEW = (Bitmap)f.Image.Clone();
                         f.Image.Save(System.IO.Path.Combine(destPATH, "frame" + f.FrameIndex + ".bmp"), System.Drawing.Imaging.ImageFormat.Bmp);
                         Application.DoEvents();
                         int IProgressPercentage = fg.FrameCount / fg.FrameCount; //doesn't report which frame its on, so couldn't proccess this, could have edited the library to do so, but that's outside the scope of this example.
                         backgroundWorker1.ReportProgress(IProgressPercentage, PREVIEW);
                         //check if we have been canceled
                         if (bwAsync.CancellationPending)
                         {
                             e.Cancel = true;
                             return;
                         }

                     }

                     if (fg == null)
                     {
                         return;
                     }
                 }
             }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            pictureBox1.Image = (Image)e.UserState;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            

            if (e.Error == null)
            {
                if (e.Cancelled == true)
                {
                    MessageBox.Show("Canceled");
                    button2.Text = "grab all!";
                    button1.Enabled = true;
                    button3.Enabled = true;
                    return;
                }
                else
                {
                    MessageBox.Show("Finished");
                    button2.Text = "grab all!";
                    button1.Enabled = true;
                    button3.Enabled = true;
                }
            }
            else
            {
                MessageBox.Show("ERROR " + e.Error.ToString());
                button2.Text = "grab all!";
                button1.Enabled = true;
                button3.Enabled = true;
            }
        }
	}
}

Best of luck friend. and I hope you learn much from this.

hi,
Thanks a lot Sir. Would you please provide me VS2008 Example so that I can easily learn from that and Once again so much thanks to you.

here it is, this, being a modified version of a code project has only the original license, I choose not to add any additional licenses.

I wish you the best in your programing endeavors, and please do remember to mark this thread as solved when you are satisfied.

Happy coding

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.