в нем асинхронно вызывается метод OnCaptureDone, в котором полученный кадр отображается в PictureBox и помещается в очередь picBuffer
void OnCaptureDone()
{
int hr = 0;
if (sampGrabber == null) return;
try
{
hr = sampGrabber.SetCallback(null, 0);
DsError.ThrowExceptionForHR(hr);
int w = videoInfoHeader.BmiHeader.Width;
int h = videoInfoHeader.BmiHeader.Height;
if (((w & 0x03) != 0) || (w < 32) || (w > 4096) || (h < 32) || (h > 4096))
return;
int stride = w * 3;
try
{
GCHandle handle = GCHandle.Alloc(savedArray, GCHandleType.Pinned);
int scan0 = handle.AddrOfPinnedObject().ToInt32();
handle.Free();
scan0 += (h - 1) * stride;
IntPtr scan = (IntPtr)scan0;
Bitmap b = new Bitmap(w, h, -stride, PixelFormat.Format24bppRgb, scan);
scan = IntPtr.Zero;
savedArray = null;
picPreview.Image = (Image)b.Clone();
if (picBuffer.Count == bufLength)
picBuffer.Dequeue();
picBuffer.Enqueue((Bitmap)picPreview.Image);
WaitForSave.Set();
b.Dispose();
}
catch (Exception exc)
{
throw;
}
}
catch (Exception ee)
{
MessageBox.Show(this, ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
В определенный момент все кадры из picBuffer должны сохраняться на диск, процесс происходит в отдельном потоке, в который передается массив Bitmap[].
В этом месте начинаются проблемы: при сохранении картинки случается такой эксепшн:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
При этом в полях испорченного битмапа возникает такое исключение:
Object is currently in use elsewhere.
Однако массив передается в метод с "неиспорченным" содержимым.
Подскажите - в чем тут может быть дело?
Кроме того даже без сохранения очереди, в событии OnPaint PictureBox'а (при перемещении формы, при перекрытии формы другой формой программы) возникает первое исключение.
Подскажите пожалуйста - куда копать для решения проблемы?
Спасибо!
aleks.dev,
Особенно не вникал в код, но мне кажется, что у вас получается нарушение доступа к памяти - один буфер используется в разных нитях одновременно. Может быть в этом месте:
picBuffer.Enqueue((Bitmap)picPreview.Image);
надо создать копию картинки и поместить эту копию в очередь, чтобы она не была связана с исходным буфером.
at System.Drawing.SafeNativeMethods.Gdip.GdipSaveImageToFile(HandleRef image, String filename, Guid& classId, HandleRef encoderParams)
at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
at Train_Portal_Monitor.Camera.picWorker_DoWork(Object sender, DoWorkEventArgs e) in C:\Documents and Settings\Antonov_jr.ATOMTEX\Мои документы\Visual Studio 2005\Projects\Train Portal Monitor\Train Portal Monitor\Camera.cs:line 613
at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
добавлено спустя 5 часа(ов) 24 Минут
проблема решилась, спасибо за внимание =)
вот код измененных методов для заинтересованных:
void OnCaptureDone()
{
int hr = 0;
if (sampGrabber == null) return;
try
{
hr = sampGrabber.SetCallback(null, 0);
DsError.ThrowExceptionForHR(hr);
int w = videoInfoHeader.BmiHeader.Width;
int h = videoInfoHeader.BmiHeader.Height;
if (((w & 0x03) != 0) || (w < 32) || (w > 4096) || (h < 32) || (h > 4096))
return;
int stride = w * 3;
GCHandle handle = GCHandle.Alloc(savedArray, GCHandleType.Pinned);
int scan0 = handle.AddrOfPinnedObject().ToInt32();
handle.Free();
scan0 += (h - 1) * stride;
IntPtr scan = (IntPtr)scan0;
Image b = new Bitmap(w, h, -stride, PixelFormat.Format24bppRgb, scan);
Image oPic = new Bitmap(m_videoWidth, m_videoHeight);
Graphics g = Graphics.FromImage(oPic);
g.DrawImage(b, 0, 0);
string date = DateTime.Now.ToString();
SizeF d = g.MeasureString(date, transparentFont);
float sLeft = (m_videoWidth - d.Width) / 2;
float sTop = m_videoHeight - d.Height - fSize;
g.DrawString(date, transparentFont, transparentBrush, sLeft, sTop);
b.Dispose();
g.Dispose();
scan = IntPtr.Zero;
savedArray = null;
picPreview.Image = oPic;
if (picBuffer.Count == bufLength)
picBuffer.Dequeue();
picBuffer.Enqueue((Bitmap)oPic);
WaitForSave.Set();
}
catch (Exception ee)
{
MessageBox.Show(this, ee.Message, "DirectShow.NET", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}