/// <summary> /// Called on a new thread to process events from the graph. The thread /// exits when the graph finishes. /// </summary> private void EventWait() { // Returned when GetEvent is called but there are no events const int E_ABORT = unchecked ((int)0x80004004); int hr; IntPtr p1, p2; EventCode ec; EventCode exitCode = 0; IMediaEvent mediaEvent = (IMediaEvent)this.filterGraph; do { // Read the event for (hr = mediaEvent.GetEvent(out ec, out p1, out p2, 100); hr >= 0; hr = mediaEvent.GetEvent(out ec, out p1, out p2, 100)) { switch (ec) { // If the clip is finished playing case EventCode.EndOfSegment: case EventCode.StreamControlStopped: case EventCode.Complete: case EventCode.ErrorAbort: case EventCode.UserAbort: exitCode = ec; // Release any resources the message allocated hr = mediaEvent.FreeEventParams(ec, p1, p2); DsError.ThrowExceptionForHR(hr); break; default: // Release any resources the message allocated hr = mediaEvent.FreeEventParams(ec, p1, p2); DsError.ThrowExceptionForHR(hr); break; } } // If the error that exited the loop wasn't due to running out of events if (hr != E_ABORT) { DsError.ThrowExceptionForHR(hr); } }while (exitCode == 0); // Send an event saying we are complete if (this.Completed != null) { var ca = new DESCompletedArgs(exitCode); this.Completed(this, ca); } // Exit the thread }
/// <summary> /// Called on a new thread to process events from the graph. The thread /// exits when the graph finishes. /// </summary> private void EventWait() { // Returned when GetEvent is called but there are no events const int E_ABORT = unchecked ((int)0x80004004); int hr; IntPtr p1, p2; EventCode ec; EventCode exitCode = 0; IMediaEvent pEvent = (IMediaEvent)m_FilterGraph; do { // Read the event for ( hr = pEvent.GetEvent(out ec, out p1, out p2, 100); hr >= 0; hr = pEvent.GetEvent(out ec, out p1, out p2, 100) ) { Debug.WriteLine(ec); switch (ec) { // If the clip is finished playing case EventCode.Complete: case EventCode.ErrorAbort: case EventCode.UserAbort: exitCode = ec; // Release any resources the message allocated hr = pEvent.FreeEventParams(ec, p1, p2); DsError.ThrowExceptionForHR(hr); break; default: // Release any resources the message allocated hr = pEvent.FreeEventParams(ec, p1, p2); DsError.ThrowExceptionForHR(hr); break; } } // If the error that exited the loop wasn't due to running out of events if (hr != E_ABORT) { DsError.ThrowExceptionForHR(hr); } } while (exitCode == 0); // Send an event saying we are complete IsCompleted = true; } // Exit the thread
public void Run() { media_control = GraphBuilder as IMediaControl; media_event = GraphBuilder as IMediaEvent; Console.WriteLine("Started filter graph"); media_control.Run(); bool stop = false; while (!stop) { System.Threading.Thread.Sleep(500); Console.Write("."); EventCode ev; IntPtr p1, p2; if (media_event.GetEvent(out ev, out p1, out p2, 0) == 0) { if (ev == EventCode.Complete || ev == EventCode.UserAbort) { Console.WriteLine("Done"); stop = true; media_control.Stop(); } else if (ev == EventCode.ErrorAbort) { Console.WriteLine("An Error occurred: HRESULT={0:X}", p1); media_control.Stop(); stop = true; } media_event.FreeEventParams(ev, p1, p2); } } }
/// <summary> /// Thread which monitors events and raises them /// </summary> private void Monitor() { int eventCode, param1, param2; while (true) { try { // Check for an event iME.GetEvent(out eventCode, out param1, out param2, -1); // Raise the event if anyone is interested if (FgmEvent != null) { FgmEvent(this, new FgmEventArgs(eventCode, param1, param2)); } //ParseEvent(eventCode, param1, param2); iME.FreeEventParams(eventCode, param1, param2); } catch (COMException e) // Timedout waiting for event { Console.WriteLine(e.ToString()); } } }
/// <summary> /// Wait for direct show events to happen. This approach uses waiting on an event handle. /// The nice thing about doing it this way is that you aren't in the windows message /// loop, and don't have to worry about reentrancy or taking too long. Plus, being /// in a class as we are, we don't have access to the message loop. /// Alternately, you can receive your events as windows messages. See IMediaEventEx.SetNotifyWindow.</summary> private void MediaEventWait() { // Returned when GetEvent is called but there are no events const int E_ABORT = unchecked ((int)0x80004004); // Read the events for (;;) { lock (m_shutdown_lock) if (m_shutdown) { break; } // shutdown the thread when flagged IntPtr p1, p2; EventCode ec; int hr = m_media_event.GetEvent(out ec, out p1, out p2, 0); if (hr == E_ABORT) { m_event.WaitOne(-1, true); continue; } // Wait for an event else if (hr < 0) { DsError.ThrowExceptionForHR(hr); // If the error wasn't due to running out of events } //Debug.WriteLine("Video Event: " + ec); // Write the event name to the debug window // If the clip is finished playing if (ec == EventCode.Complete) { Stop(); // Call Stop() to set state } // Release any resources the message allocated DsError.ThrowExceptionForHR(m_media_event.FreeEventParams(ec, p1, p2)); } }
//TODO maybe we can replace this stuff with BaseDSGraph someday private void EventListener() { Debug.WriteLine("EventListener listening"); _eventListenerRunning = true; IntPtr param1, param2; while (_eventListenerRunning) { int hr; EventCode eventCode; hr = _mediaEvent.GetEvent(out eventCode, out param1, out param2, 3000); if (hr == 0) { Debug.WriteLine("EventListener got " + eventCode.ToString()); if (eventCode == EventCode.Complete) { Stop(); Run(); } _mediaEvent.FreeEventParams(eventCode, param1, param2); } } Debug.WriteLine("EventListener exit"); }
private void TestNotify() { int hr; IntPtr p1, p2; IntPtr p3 = IntPtr.Zero, p4 = IntPtr.Zero; EventCode ec; bool bPassed = false; bool bDone = false; IMediaEvent pEvent = (IMediaEvent)m_FilterGraph; hr = m_mes.Notify(EC_FileComplete, new IntPtr(1), new IntPtr(2)); DsError.ThrowExceptionForHR(hr); ((IMediaControl)m_FilterGraph).Run(); // Read the event for ( hr = pEvent.GetEvent(out ec, out p1, out p2, 5000); hr >= 0 && !bDone; hr = pEvent.GetEvent(out ec, out p1, out p2, 5000) ) { Debug.WriteLine(ec); if (ec == EC_FileComplete) { bPassed = true; p3 = p1; p4 = p2; } else if (ec == EventCode.Complete) { break; } else { hr = pEvent.FreeEventParams(ec, p1, p2); } } Debug.Assert(bPassed && p3.ToInt64() == 1 && p4.ToInt64() == 2, "Notify"); }
// FIXME this needs some work, to be completely in-tune with needs. public void MediaEventLoop(Action <double> UpdateProgress) { mediaEvent.CancelDefaultHandling(EventCode.StateChange); //mediaEvent.CancelDefaultHandling(EventCode.Starvation); while (stopMediaEventLoop == false) { try { EventCode ev; IntPtr p1, p2; if (mediaEvent.GetEvent(out ev, out p1, out p2, 0) == 0) { switch (ev) { case EventCode.Complete: Stopping.Fire(this, null); if (UpdateProgress != null) { UpdateProgress(source.PercentageCompleted); } return; case EventCode.StateChange: FilterState state = (FilterState)p1.ToInt32(); if (state == FilterState.Stopped || state == FilterState.Paused) { Stopping.Fire(this, null); } else if (state == FilterState.Running) { Starting.Fire(this, null); } break; // FIXME add abort and stuff, and propagate this. } // Trace.WriteLine(ev.ToString() + " " + p1.ToInt32()); mediaEvent.FreeEventParams(ev, p1, p2); } else { if (UpdateProgress != null) { UpdateProgress(source.PercentageCompleted); } // FiXME use AutoResetEvent Thread.Sleep(100); } } catch (Exception e) { Trace.WriteLine("MediaEventLoop: " + e); } } }
static void Main(string[] args) { try { IGraphBuilder pGraph = (IGraphBuilder) new FilterGraph(); Console.WriteLine("Building graph..."); BuildGraph(pGraph, @"bbb_360p_10sec.mp4"); Console.WriteLine("Running..."); IMediaControl pMediaControl = (IMediaControl)pGraph; IMediaEvent pMediaEvent = (IMediaEvent)pGraph; int hr = pMediaControl.Run(); checkHR(hr, "Can't run the graph"); bool stop = false; while (!stop) { System.Threading.Thread.Sleep(50); Console.Write("."); EventCode ev; IntPtr p1, p2; System.Windows.Forms.Application.DoEvents(); while (pMediaEvent.GetEvent(out ev, out p1, out p2, 0) == 0) { if (ev == EventCode.Complete || ev == EventCode.UserAbort) { Console.WriteLine("Done!"); stop = true; } else if (ev == EventCode.ErrorAbort) { Console.WriteLine("An error occured: HRESULT={0:X}", p1); pMediaControl.Stop(); stop = true; } pMediaEvent.FreeEventParams(ev, p1, p2); } } } catch (COMException ex) { Console.WriteLine("COM error: " + ex.ToString()); } catch (Exception ex) { Console.WriteLine("Error: " + ex.ToString()); } }
static void Main(string[] args) { try { IGraphBuilder graph = (IGraphBuilder) new FilterGraph(); Console.WriteLine("Building graph..."); BuildGraph(graph, @"J:\TORRENT\1. Фильмы\Mult.RU.320x240\03 Ежи и Петруччо\01 Когда-то.mp4"); Console.WriteLine("Running..."); IMediaControl mediaControl = (IMediaControl)graph; IMediaEvent mediaEvent = (IMediaEvent)graph; int hr = mediaControl.Run(); checkHR(hr, "Can't run the graph"); bool stop = false; while (!stop) { System.Threading.Thread.Sleep(500); Console.Write("."); EventCode ev; IntPtr p1, p2; System.Windows.Forms.Application.DoEvents(); while (mediaEvent.GetEvent(out ev, out p1, out p2, 0) == 0) { if (ev == EventCode.Complete || ev == EventCode.UserAbort) { Console.WriteLine("Done!"); stop = true; } else if (ev == EventCode.ErrorAbort) { Console.WriteLine("An error occured: HRESULT={0:X}", p1); mediaControl.Stop(); stop = true; } mediaEvent.FreeEventParams(ev, p1, p2); } } } catch (COMException ex) { Console.WriteLine("COM error: " + ex.ToString()); } catch (Exception ex) { Console.WriteLine("Error: " + ex.ToString()); } }
public void OnGraphEvent() { try { IntPtr evpar1; IntPtr evpar2; // = Marshal.AllocHGlobal(4); EventCode ev; if (mediaEvent.GetEvent(out ev, out evpar1, out evpar2, 10) == 0) //got event { int ip1 = (int)evpar1; //Marshal.ReadInt32(evpar1); int ip2 = (int)evpar2; //Marshal.ReadInt32(evpar2); lock (eventlog) { eventlog.AddLast(new GraphEvent(ev, ip1, ip2)); } if (ev == EventCode.Complete || ev == EventCode.UserAbort) { mediaControl.Stop(); } if (ev == EventCode.ErrorAbort) { int hr = ip1; DsError.ThrowExceptionForHR(hr); } if (ev == EventCode.DeviceLost) { Program.mainform.filterz.RefreshCategories(); } } mediaEvent.FreeEventParams(ev, evpar1, evpar2); } catch (COMException ex) { if (ex.ErrorCode != unchecked ((int)0x80070006)) //E_HANDLE { ShowCOMException(ex, "An error occured in the graph"); } } catch (Exception e) { MessageBox.Show(e.Message, "Exception caught while getting a graph event"); } }
/// <summary> /// Test all methods /// </summary> public void DoTests() { int hr; IntPtr hEvent; IntPtr p1, p2; EventCode ec; BuildGraph(); hr = m_mediaEvent.GetEventHandle(out hEvent); DsError.ThrowExceptionForHR(hr); ManualResetEvent mre = new ManualResetEvent(false); mre.SafeWaitHandle = new Microsoft.Win32.SafeHandles.SafeWaitHandle(hEvent, true); // Should get an event before this bool b = mre.WaitOne(5000, true); Debug.Assert(b, "GetEventHandle"); // I don't know what event I may get, so I don't know how to check it hr = m_mediaEvent.GetEvent(out ec, out p1, out p2, 0); DsError.ThrowExceptionForHR(hr); hr = m_mediaEvent.FreeEventParams(ec, p1, p2); DsError.ThrowExceptionForHR(hr); hr = m_mediaEvent.CancelDefaultHandling(EventCode.Repaint); DsError.ThrowExceptionForHR(hr); hr = m_mediaEvent.RestoreDefaultHandling(EventCode.Repaint); DsError.ThrowExceptionForHR(hr); // The clip is 4 seconds long, so timeout in 5 hr = m_mediaEvent.WaitForCompletion(5000, out ec); DsError.ThrowExceptionForHR(hr); // The video should have successfully played Debug.Assert(ec == EventCode.Complete, "WaitForCompletion"); }
private void button1_Click(object sender, EventArgs e) { try { IGraphBuilder graph = (IGraphBuilder) new FilterGraph(); BuildGraph(graph); IMediaControl mediaControl = (IMediaControl)graph; IMediaEvent mediaEvent = (IMediaEvent)graph; int hr = mediaControl.Run(); bool stop = false; while (!stop) { System.Threading.Thread.Sleep(500); EventCode ev; IntPtr p1, p2; System.Windows.Forms.Application.DoEvents(); while (mediaEvent.GetEvent(out ev, out p1, out p2, 0) == 0) { if (ev == EventCode.Complete || ev == EventCode.UserAbort) { stop = true; } else if (ev == EventCode.ErrorAbort) { mediaControl.Stop(); stop = true; } mediaEvent.FreeEventParams(ev, p1, p2); } } } catch (COMException ex) { MessageBox.Show("COM Error" + ex.ToString()); } catch (Exception ex) { MessageBox.Show("Error:" + ex.ToString()); } }
private bool CheckGraphConversion(ref IMediaSeeking mediaSeeking) { int hr; IMediaEvent mediaEvent = (IMediaEvent)currentFilterGraph; // Check the graph / conversion is going ok, and raise any progress events EventCode statusCode; hr = mediaEvent.WaitForCompletion(100, out statusCode); switch (statusCode) { case EventCode.Complete: return(true); case 0: // Still going - fire event with an update on where we are if (mediaSeeking != null) { long curPos; mediaSeeking.GetCurrentPosition(out curPos); long length; mediaSeeking.GetDuration(out length); double progress = curPos * 100.0 / (double)length; if (ConversionProgressChanged != null) { ConversionProgressChanged(new object(), new ProgressChangedEventArgs(progress)); } } return(false); default: // Error EventCode tryCode; IntPtr lp1, lp2; hr = mediaEvent.GetEvent(out tryCode, out lp1, out lp2, 200); DsError.ThrowExceptionForHR(hr); throw new Exception(statusCode.ToString()); } }
// Wait for events to happen. This approach uses waiting on an event handle. // The nice thing about doing it this way is that you aren't in the windows message // loop, and don't have to worry about re-entrency or taking too long. Plus, being // in a class as we are, we don't have access to the message loop. // Alternately, you can receive your events as windows messages. See // IMediaEventEx.SetNotifyWindow. private void EventWait() { // Returned when GetEvent is called but there are no events const int E_ABORT = unchecked ((int)0x80004004); int hr; IntPtr p1, p2; EventCode ec; do { // Wait for an event m_mre.WaitOne(-1, true); // Avoid contention for m_State lock (this) { // If we are not shutting down if (m_State != GraphState.Exiting) { // Read the event for ( hr = m_mediaEvent.GetEvent(out ec, out p1, out p2, 0); hr >= 0; hr = m_mediaEvent.GetEvent(out ec, out p1, out p2, 0) ) { // Write the event name to the debug window Debug.WriteLine(ec.ToString()); // If the clip is finished playing if (ec == EventCode.Complete) { // Call Stop() to set state Stop(); // Throw event if (StopPlay != null) { StopPlay(this); } } // Release any resources the message allocated hr = m_mediaEvent.FreeEventParams(ec, p1, p2); DsError.ThrowExceptionForHR(hr); } // If the error that exited the loop wasn't due to running out of events if (hr != E_ABORT) { DsError.ThrowExceptionForHR(hr); } } else { // We are shutting down break; } } } while (true); }
//void eventListener_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) //{ // this.CloseAudioFile(); //} /// <summary> /// Called on a new thread to process events from the graph. The thread /// exits when the graph finishes. Cancelling is done here. /// </summary> private void EventWait() { // Returned when GetEvent is called but there are no events const int E_ABORT = unchecked ((int)0x80004004); int hr; IntPtr p1, p2; EventCode ec; EventCode exitCode = 0; IMediaEvent pEvent = (IMediaEvent)this.filterGraph; do { // Read the event for ( hr = pEvent.GetEvent(out ec, out p1, out p2, 100); hr >= 0 && this.currentState == PlayState.Running; hr = pEvent.GetEvent(out ec, out p1, out p2, 100) ) { switch (ec) { // If all files finished playing case EventCode.Complete: case EventCode.ErrorAbort: case EventCode.UserAbort: ChangeState(PlayState.Exiting); exitCode = ec; break; } // Release any resources the message allocated hr = pEvent.FreeEventParams(ec, p1, p2); DsError.ThrowExceptionForHR(hr); } // If the error that exited the loop wasn't due to running out of events if (hr != E_ABORT) { DsError.ThrowExceptionForHR(hr); } } while (this.currentState == PlayState.Running); // If the user cancelled if (this.currentState == PlayState.Cancelling) { // Stop the graph, send an appropriate exit code hr = this.mediaControl.Stop(); exitCode = EventCode.UserAbort; } // Send an event saying we are complete if (exitCode == EventCode.Complete && Completed != null) { CompletedArgs ca = new CompletedArgs(exitCode); Completed(this, ca); } //threadCompleted = true; } // Exit the thread
/// <summary> /// Called on a new thread to process events from the graph. The thread /// exits when the graph finishes. /// </summary> private void EventWait() { // Returned when GetEvent is called but there are no events const int E_ABORT = unchecked ((int)0x80004004); int hr; IntPtr p1, p2; EventCode ec; EventCode exitCode = 0; IMediaEvent pEvent = (IMediaEvent)m_FilterGraph; do { // Read the event for ( hr = pEvent.GetEvent(out ec, out p1, out p2, 100); hr >= 0; hr = pEvent.GetEvent(out ec, out p1, out p2, 100) ) { Debug.WriteLine(ec); switch (ec) { // If the clip is finished playing case EventCode.Complete: case EventCode.ErrorAbort: case EventCode.UserAbort: exitCode = ec; // Release any resources the message allocated hr = pEvent.FreeEventParams(ec, p1, p2); DsError.ThrowExceptionForHR(hr); break; case EventCode.OleEvent: string s1 = Marshal.PtrToStringBSTR(p1); string s2 = Marshal.PtrToStringBSTR(p2); string s3 = s2.Remove(s2.Length - 1, 1); Debug.WriteLine(string.Format("OleEvent Parms: {0} | {1}", s1, s3)); hr = pEvent.FreeEventParams(ec, p1, p2); break; default: // Release any resources the message allocated hr = pEvent.FreeEventParams(ec, p1, p2); DsError.ThrowExceptionForHR(hr); break; } } // If the error that exited the loop wasn't due to running out of events if (hr != E_ABORT) { DsError.ThrowExceptionForHR(hr); } } while (exitCode == 0); pEvent = null; // Send an event saying we are complete if (Completed != null) { CompletedArgs ca = new CompletedArgs(exitCode); Completed(this, ca); } } // Exit the thread
/// <summary>Runs the graph</summary> /// <param name="graphBuilder">The graph to be run.</param> /// <param name="seekableFilter">The filter to use for computing percent complete. Must implement IMediaSeeking.</param> protected void RunGraph(IGraphBuilder graphBuilder, IBaseFilter seekableFilter) { // Get the necessary control and event interfaces IMediaControl mediaControl = (IMediaControl)graphBuilder; IMediaEvent mediaEvent = (IMediaEvent)graphBuilder; // Get the media seeking interface to use for computing status and progress updates IMediaSeeking mediaSeeking = seekableFilter as IMediaSeeking; if (!CanGetPositionAndDuration(mediaSeeking)) { mediaSeeking = graphBuilder as IMediaSeeking; if (!CanGetPositionAndDuration(mediaSeeking)) { mediaSeeking = null; } } // Publish the graph to the running object table and to a temporary file for examination/debugging purposes //using (new GraphPublisher(graphBuilder, "C:\\vidtests\\grf\\" + Guid.NewGuid().ToString("N") + ".grf")) { // Run the graph int hr = 0; hr = mediaControl.Pause(); hr = mediaControl.Run(); DsError.ThrowExceptionForHR(hr); try { ProgressChanged(new object(), new ProgressChangedEventArgs(0.0)); // initial progress update stating 0% done bool done = false; while (!CancellationPending && !done) // continue until we're done/cancelled { // Poll to see how we're doing EventCode statusCode; hr = mediaEvent.WaitForCompletion(200, out statusCode); Console.Write(" <" + statusCode.ToString() + ">,"); switch (statusCode) { case EventCode.Complete: done = true; break; case 0: // Get an update on where we are with the conversion if (mediaSeeking != null) { long curPos; mediaSeeking.GetCurrentPosition(out curPos); long length; mediaSeeking.GetDuration(out length); double progress = curPos * 100.0 / (double)length; if (progress > 0) { ProgressChanged(new object(), new ProgressChangedEventArgs(progress)); } } break; default: // Error, so throw exception EventCode tryCode; IntPtr lp1, lp2; hr = mediaEvent.GetEvent(out tryCode, out lp1, out lp2, 200); DsError.ThrowExceptionForHR(hr); throw new Exception(statusCode.ToString()); } } ProgressChanged(new object(), new ProgressChangedEventArgs(100)); // final progress update stating 100% done } finally { // We're done converting, so stop the graph FilterState graphState; mediaControl.GetState(100, out graphState); if (graphState == FilterState.Running) { mediaControl.Pause(); } mediaControl.Stop(); // Return done Completed(new object(), new EventArgs()); } } }
/// <summary> /// Called on a new thread to process events from the graph. The thread /// exits when the graph finishes. Cancelling is done here. /// </summary> private void EventWait() { // Returned when GetEvent is called but there are no events const int E_ABORT = unchecked ((int)0x80004004); int hr; IntPtr p1, p2; EventCode ec; EventCode exitCode = 0; IMediaEvent pEvent = (IMediaEvent)m_pGraph; do { // Read the event for ( hr = pEvent.GetEvent(out ec, out p1, out p2, 100); hr >= 0 && m_State < ClassState.GraphCompleted; hr = pEvent.GetEvent(out ec, out p1, out p2, 100) ) { switch (ec) { case EventCode.UserAbort: ChangeState(ClassState.Cancelling); exitCode = ec; // Release any resources the message allocated hr = pEvent.FreeEventParams(ec, p1, p2); DESError.ThrowExceptionForHR(hr); break; // If the clip is finished playing case EventCode.Complete: case EventCode.ErrorAbort: ChangeState(ClassState.GraphCompleting); exitCode = ec; // Release any resources the message allocated hr = pEvent.FreeEventParams(ec, p1, p2); DESError.ThrowExceptionForHR(hr); break; // Walked past the end of a video file, send an event case EC_VideoFileComplete: if (FileCompleted != null) { MediaFile mf = m_Video.File(p1.ToInt32()); FileCompletedArgs ca = new FileCompletedArgs(mf.FileName, FileCompletedArgs.FileType.Video); FileCompleted(this, ca); } break; // Walked past the end of a video file, send an event case EC_AudioFileComplete: if (FileCompleted != null) { MediaFile mf = m_Audio.File(p1.ToInt32()); FileCompletedArgs ca = new FileCompletedArgs(mf.FileName, FileCompletedArgs.FileType.Audio); FileCompleted(this, ca); } break; default: // Release any resources the message allocated hr = pEvent.FreeEventParams(ec, p1, p2); DESError.ThrowExceptionForHR(hr); break; } } // If the error that exited the loop wasn't due to running out of events if (hr != E_ABORT) { DESError.ThrowExceptionForHR(hr); } //FilterState fs; //m_pControl.GetState(200, out fs); ////DESError.ThrowExceptionForHR(hr); } while (m_State < ClassState.GraphCompleting); // If the user cancelled if (m_State == ClassState.Cancelling && m_pControl != null) { // Stop the graph, send an appropriate exit code hr = m_pControl.Stop(); exitCode = EventCode.UserAbort; } if (m_State == ClassState.GraphCompleting) { m_State = ClassState.GraphCompleted; } else { m_State = ClassState.Cancelled; } threadCompleted = true; // Send an event saying we are complete if (this.ThreadFinished != null) { DESCompletedArgs ca = new DESCompletedArgs(exitCode); this.ThreadFinished(this, ca); } } // Exit the thread
public void RunGraph() { DateTime lastTick = DateTime.Now; int hangPeriod = MCEBuddyConf.GlobalMCEConfig.GeneralOptions.hangTimeout; long lastVideoSize = 0, lastAudioSize = 0, lastSubtitleSize = 0; long totalPartsSize = 0, sourceSize = 0; bool AbortError = false; int hr = 0; IMediaControl mediaControl = (IMediaControl)_fg; IMediaEvent mediaEvent = (IMediaEvent)_fg; hr = mediaControl.Run(); checkHR(hr); // Change the priority temporarily (need to reset it back after Dumping Streams) ProcessPriorityClass lastPriority = GlobalDefs.Priority; // Set it up Process.GetCurrentProcess().PriorityClass = GlobalDefs.Priority; // Set the CPU Priority IOPriority.SetPriority(GlobalDefs.IOPriority); // First set the CPU priority // Get filesize of source file sourceSize = Util.FileIO.FileSize(_SourceFile); // Sanity checking if (sourceSize <= 0) { _jobLog.WriteEntry(this, "Unable to get source file size, disabling infinite loop checking.", Log.LogEntryType.Warning); hangPeriod = 0; } bool stop = false, isSuspended = false; while (!stop) { System.Threading.Thread.Sleep(100); if (_jobStatus.Cancelled) { // Received a shutdown command external to the filter extraction _jobLog.WriteEntry(this, "Stream extraction cancelled, aborting graph.", Log.LogEntryType.Warning); stop = true; AbortError = true; mediaControl.Stop(); break; } if (isSuspended) { lastTick = DateTime.Now; // Since during suspension there will be no output it shouldn't terminate the process } if (!isSuspended && GlobalDefs.Pause) // Check if process has to be suspended (if not already) { _jobLog.WriteEntry(this, "Stream extraction paused", Log.LogEntryType.Information); mediaControl.Pause(); isSuspended = true; } if (isSuspended && !GlobalDefs.Pause) // Check if we need to resume the process { _jobLog.WriteEntry(this, "Stream extraction resumed", Log.LogEntryType.Information); isSuspended = false; mediaControl.Run(); } if (lastPriority != GlobalDefs.Priority) // Check if the priority was changed and if so update it { _jobLog.WriteEntry(this, "Stream extraction priority changed", Log.LogEntryType.Information); lastPriority = GlobalDefs.Priority; Process.GetCurrentProcess().PriorityClass = GlobalDefs.Priority; // Set the CPU Priority IOPriority.SetPriority(GlobalDefs.IOPriority); // First set the CPU priority } EventCode ev; IntPtr p1, p2; if (mediaEvent.GetEvent(out ev, out p1, out p2, 0) == 0) { if (ev == EventCode.Complete) { mediaControl.Stop(); stop = true; } else if (ev == EventCode.ErrorAbort || ev == EventCode.UserAbort || ev == EventCode.StErrStopped || ev == EventCode.ErrorAbortEx) { mediaControl.Stop(); stop = true; //AbortError = true; - some partial/corrupted files are errored out, we'll handle extraction errors later } mediaEvent.FreeEventParams(ev, p1, p2); } // Sanity checking to prevent infinite loop for extraction (sometimes steams extracts infinitely) // Check if the filesize exceed the initial file size and if so abort the operation if (sourceSize > 0) { totalPartsSize = 0; // Video file check if ((_extractMediaType & ExtractMediaType.Video) != 0) { long videoSize = Util.FileIO.FileSize(_VideoPart); if (videoSize < 0) { _jobLog.WriteEntry(this, "Unable to get extracted video stream file size for infinite loop detection.", Log.LogEntryType.Warning); } else if (videoSize > (sourceSize * INFINITE_LOOP_CHECK_THRESHOLD)) { _jobLog.WriteEntry(this, "Extracted video stream is greater than " + INFINITE_LOOP_CHECK_THRESHOLD.ToString(CultureInfo.InvariantCulture) + " times the source file size " + (sourceSize / 1024).ToString("N", CultureInfo.InvariantCulture) + " [KB].\r\nExtraction likely hung, terminating streams extraction.", Log.LogEntryType.Error); stop = true; AbortError = true; mediaControl.Stop(); break; } if (hangPeriod > 0) { if (videoSize > lastVideoSize) // If we have progress { lastTick = DateTime.Now; } } totalPartsSize += videoSize; lastVideoSize = videoSize; } // Audio file check if ((_extractMediaType & ExtractMediaType.Audio) != 0) { foreach (string audioPart in _AudioParts) { long audioSize = Util.FileIO.FileSize(audioPart); if (audioSize < 0) { _jobLog.WriteEntry(this, "Unable to get extracted audio stream file size for infinite loop detection.", Log.LogEntryType.Warning); } else if (audioSize > (sourceSize * INFINITE_LOOP_CHECK_THRESHOLD)) { _jobLog.WriteEntry(this, "Extracted audio stream is greater than " + INFINITE_LOOP_CHECK_THRESHOLD.ToString(CultureInfo.InvariantCulture) + " times the source file size " + (sourceSize / 1024).ToString("N", CultureInfo.InvariantCulture) + " [KB].\r\nExtraction likely hung, terminating streams extraction.", Log.LogEntryType.Error); stop = true; AbortError = true; mediaControl.Stop(); break; } if (hangPeriod > 0) { if (audioSize > lastAudioSize) // If we have progress { lastTick = DateTime.Now; } } totalPartsSize += audioSize; lastAudioSize = audioSize; } } // Subtitle file check if ((_extractMediaType & ExtractMediaType.Subtitle) != 0) { foreach (string subtitlePart in _SubtitleParts) { long subtitleSize = Util.FileIO.FileSize(subtitlePart); if (subtitleSize < 0) { _jobLog.WriteEntry(this, "Unable to get extracted subtitle stream file size for infinite loop detection.", Log.LogEntryType.Warning); } else if (subtitleSize > (sourceSize * INFINITE_LOOP_CHECK_THRESHOLD)) { _jobLog.WriteEntry(this, "Extracted subtitle stream is greater than " + INFINITE_LOOP_CHECK_THRESHOLD.ToString(CultureInfo.InvariantCulture) + " times the source file size " + (sourceSize / 1024).ToString("N", CultureInfo.InvariantCulture) + " [KB].\r\nExtraction likely hung, terminating streams extraction.", Log.LogEntryType.Error); stop = true; AbortError = true; mediaControl.Stop(); break; } if (hangPeriod > 0) { if (subtitleSize > lastSubtitleSize) // If we have progress { lastTick = DateTime.Now; } } totalPartsSize += subtitleSize; lastSubtitleSize = subtitleSize; } } if (totalPartsSize < 0) { totalPartsSize = 0; // Incase we get -ve numbers } _jobStatus.PercentageComplete = (((float)totalPartsSize / (float)sourceSize) > 1 ? 100 : ((float)totalPartsSize / (float)sourceSize) * 100); // Calculate % complete from size estimation (since no recoding is happening) and cap at 100% _jobLog.WriteEntry(this, "Percentage complete : " + _jobStatus.PercentageComplete.ToString("0.00", CultureInfo.InvariantCulture) + " %", Log.LogEntryType.Debug); // Write to file } // Check if we have reached the end of the file or runs out of disk space, sometime windows just loops endlessly without any incremental output // TODO: Should we treat this as an error or normal processing if ((hangPeriod > 0) && (DateTime.Now > lastTick.AddSeconds(hangPeriod))) { _jobLog.WriteEntry("No response from stream extraction for " + hangPeriod + " seconds, process likely finished, continuing.", Log.LogEntryType.Warning); // Don't treat as an error for now stop = true; // AbortError = true; // Don't treat as an error for now mediaControl.Stop(); break; } } // Reset Priority to Normal IOPriority.SetPriority(GlobalDefs.EngineIOPriority); // Set CPU priority after restoring the scheduling priority Process.GetCurrentProcess().PriorityClass = GlobalDefs.EnginePriority; // Set the CPU Priority back to Above Normal (engine always runs above normal) List <string> parts = _AudioParts.Concat(_SubtitleParts).ToList(); // Create a list of all subtitle, audio parts if (!String.IsNullOrWhiteSpace(_VideoPart)) { parts.Add(_VideoPart); // add video part } _jobLog.WriteEntry(this, "Source " + _SourceFile + " filesize [KB] : " + (sourceSize / 1024).ToString("N", CultureInfo.InvariantCulture), Log.LogEntryType.Debug); // Write to file foreach (string part in parts) { _jobLog.WriteEntry(this, part + " extracted filesize [KB] : " + (FileIO.FileSize(part) / 1024).ToString("N", CultureInfo.InvariantCulture), Log.LogEntryType.Debug); // Write to file } _jobLog.WriteEntry(this, "Total extracted parts size [KB] : " + (totalPartsSize / 1024).ToString("N", CultureInfo.InvariantCulture), Log.LogEntryType.Debug); // Write to file if (!AbortError) { _SuccessfulExtraction = true; } }
/// <summary> /// Called on a new thread to process events from the graph. The thread /// exits when the graph finishes. Cancelling is done here. /// </summary> private void EventWait() { try { // Returned when GetEvent is called but there are no events const int E_ABORT = unchecked ((int)0x80004004); int hr; int p1, p2; EventCode ec; EventCode exitCode = 0; IMediaEvent pEvent = (IMediaEvent)_graph; do { // Read the event for ( hr = pEvent.GetEvent(out ec, out p1, out p2, 100); hr >= 0 && _state < RendererState.GraphCompleted; hr = pEvent.GetEvent(out ec, out p1, out p2, 100) ) { switch (ec) { // If the clip is finished playing case EventCode.Complete: case EventCode.ErrorAbort: ChangeState(RendererState.GraphStarted, RendererState.GraphCompleting); exitCode = ec; // Release any resources the message allocated hr = pEvent.FreeEventParams(ec, p1, p2); DESError.ThrowExceptionForHR(hr); break; default: // Release any resources the message allocated hr = pEvent.FreeEventParams(ec, p1, p2); DESError.ThrowExceptionForHR(hr); break; } } // If the error that exited the loop wasn't due to running out of events if (hr != E_ABORT) { DESError.ThrowExceptionForHR(hr); } } while (_state < RendererState.GraphCompleting); // If the user cancelled if (_state == RendererState.Cancelling) { // Stop the graph, send an appropriate exit code hr = _mediaControl.Stop(); exitCode = EventCode.UserAbort; } if (_state == RendererState.GraphCompleting) { ChangeState(RendererState.GraphCompleted); OnRenderCompleted(); if (_renderResult != null) { _renderResult.Complete(false); } if (_cancelResult != null) { _cancelResult.Complete(false); } } else { ChangeState(RendererState.Cancelled); OnRenderCompleted(); if (_renderResult != null) { _renderResult.Complete(true); } if (_cancelResult != null) { _cancelResult.Complete(false); } } } catch (Exception ex) { if (_renderResult != null) { _renderResult.Complete(ex); } if (_cancelResult != null) { _cancelResult.Complete(ex); } } }