private void bgWorkerDualSave_DoWork(object sender, DoWorkEventArgs e) { // This is executed in Worker Thread space. (Do not call any UI methods) log.Debug("Saving side by side video."); int threadResult = 0; // Get first frame outside the loop to set up the saving context. long currentTime = 0; Bitmap composite = GetCompositeImage(currentTime); log.DebugFormat("Composite size: {0}.", composite.Size); VideoInfo info = new VideoInfo { ReferenceSize = composite.Size }; string formatString = FilenameHelper.GetFormatString(dualSaveFileName); SaveResult result = videoFileWriter.OpenSavingContext(dualSaveFileName, info, formatString, fileFrameInterval); if (result != SaveResult.Success) { e.Result = 2; return; } videoFileWriter.SaveFrame(composite); composite.Dispose(); while (currentTime < commonTimeline.LastTime && !dualSaveCancelled) { currentTime += commonTimeline.FrameTime; if (bgWorkerDualSave.CancellationPending) { threadResult = 1; dualSaveCancelled = true; break; } composite = GetCompositeImage(currentTime); videoFileWriter.SaveFrame(composite); composite.Dispose(); int percent = (int)((double)currentTime * 100 / commonTimeline.LastTime); bgWorkerDualSave.ReportProgress(percent); } if (!dualSaveCancelled) { threadResult = 0; } e.Result = threadResult; }
private void Work() { Thread.CurrentThread.Name = "Record"; while (!m_bCancelling) { Bitmap bmp = null; lock (m_Locker) { if (m_FrameQueue.Count > 0) { bmp = m_FrameQueue.Dequeue(); if (bmp == null) { log.Debug("Recording thread finished."); return; } } } if (bmp != null) { SaveResult res = m_VideoFileWriter.SaveFrame(bmp); if (res != SaveResult.Success) { // Start cancellation procedure // The producer should test for .Cancelling and stop queuing items at this point. // We don't try to save the outstanding frames, but the video file should be valid. log.Error("Error while saving frame to file."); m_bCancelling = true; m_CancelReason = res; bmp.Dispose(); lock (m_Locker) { while (m_FrameQueue.Count > 0) { Bitmap outstanding = m_FrameQueue.Dequeue(); if (outstanding != null) { outstanding.Dispose(); } } if (m_bInitialized) { try { m_VideoFileWriter.CloseSavingContext(true); } catch (Exception exp) { log.Error(exp.Message); log.Error(exp.StackTrace); } } } m_WaitHandle.Close(); return; } else { if (!m_bCaptureThumbSet) { m_CaptureThumb = bmp; m_bCaptureThumbSet = true; } else { bmp.Dispose(); } } } else { m_WaitHandle.WaitOne(); } } }
public void FrameGrabbed() { //---------------------------------------------- // NOTE : This method is in the GRABBING thread, // NO UI calls can be made directly from here. // must use BeginInvoke at some point. //---------------------------------------------- // The frame grabber has just pushed a new frame to the buffer. // Consolidate this real-time frame locally. Bitmap temp = m_FrameBuffer.ReadFrameAt(0); // Copy the frame over if size change is needed. if (!temp.Size.Equals(m_ImageSize)) { m_MostRecentImage = new Bitmap(m_ImageSize.Width, m_ImageSize.Height); Graphics g = Graphics.FromImage(m_MostRecentImage); Rectangle rDst = new Rectangle(0, 0, m_MostRecentImage.Width, m_MostRecentImage.Height); RectangleF rSrc = new Rectangle(0, 0, temp.Width, temp.Height); g.DrawImage(temp, rDst, rSrc, GraphicsUnit.Pixel); } else { m_MostRecentImage = temp; } // Ask a refresh. This could also be done with a timer, // but using the frame grabber event is convenient. if (!m_bPainting) { m_bPainting = true; m_Container.DoInvalidate(); } // We also use this event to commit frame to disk during saving. // However, it is what is drawn on screen that will be pushed to the file, // not the frame the device just grabbed. if (m_bIsRecording) { // Is it necessary to make another copy of the frame ? Bitmap bmp = GetFlushedImage(); SaveResult res = m_VideoFileWriter.SaveFrame(bmp); if (res != SaveResult.Success) { log.Error("Error while saving frame to file."); DisplayError(res); bmp.Dispose(); m_bIsRecording = false; m_VideoFileWriter.CloseSavingContext(true); // TODO: remove broken file. } else { if (!m_bCaptureThumbSet) { m_CurrentCaptureBitmap = bmp; m_bCaptureThumbSet = true; } else { bmp.Dispose(); } } } }