[DirectShow]041 - The Streaming and Application Threads

<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:1; mso-generic-font-family:roman; mso-font-format:other; mso-font-pitch:variable; mso-font-signature:0 0 0 0 0 0;} @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} @font-face {font-family:Verdana; panose-1:2 11 6 4 3 5 4 4 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:536871559 0 0 0 415 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:宋体; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-font-kerning:1.0pt;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:15.6pt;} div.Section1 {page:Section1;} /* List Definitions */ @list l0 {mso-list-id:555705112; mso-list-template-ids:836042438;} @list l0:level1 {mso-level-number-format:bullet; mso-level-text:; mso-level-tab-stop:36.0pt; mso-level-number-position:left; text-indent:-18.0pt; mso-ansi-font-size:10.0pt; font-family:Symbol;} @list l1 {mso-list-id:1289508953; mso-list-template-ids:865506064;} @list l1:level1 {mso-level-number-format:bullet; mso-level-text:; mso-level-tab-stop:36.0pt; mso-level-number-position:left; text-indent:-18.0pt; mso-ansi-font-size:10.0pt; font-family:Symbol;} @list l2 {mso-list-id:1529290238; mso-list-template-ids:-1557518052;} @list l2:level1 {mso-level-number-format:bullet; mso-level-text:; mso-level-tab-stop:36.0pt; mso-level-number-position:left; text-indent:-18.0pt; mso-ansi-font-size:10.0pt; font-family:Symbol;} ol {margin-bottom:0cm;} ul {margin-bottom:0cm;} -->

Any DirectShow application contains at least two important threads: the application thread, and one or more streaming threads. Samples are delivered on the streaming threads, and state changes happen on the application thread. The main streaming thread is created by a source or parser filter. Other filters might create worker threads that deliver samples, and these are considered streaming threads as well.

大部分 DirectShow 应用程序包含至少两种重要的线程:应用程序线程和一个或者多个流线程。 Sample 在流线程中传递,状态改变发生在应用程序线程。主流线程由 source filter 或者 parser filter 创建。其他 filter 也可能创建工作线程来传递 sample ,这些线程也被当作是流线程。

Some methods are called on the application thread, while others are called on a streaming thread. For example:

一些方法在应用程序线程中调用,另外有一些在流线程上调用,例如:

·         Streaming thread(s): IMemInputPin::Receive , IMemInputPin::ReceiveMultiple , IPin::EndOfStream , IMemAllocator::GetBuffer .

·         Application thread: IMediaFilter::Pause , IMediaFilter::Run , IMediaFilter::Stop , IMediaSeeking::SetPositions , IPin::BeginFlush , IPin::EndFlush .

·         Either: IPin::NewSegment .

Having a separate streaming thread allows data to flow through the graph while the application thread waits for user input. The danger of multiple threads, however, is that a filter may create resources when it pauses (on the application thread), use them inside a streaming method, and destroy them when it stops (also on the application thread). If you are not careful, the streaming thread might try to use the resources after they are destroyed. The solution is to protect resources using critical sections, and synchronize streaming methods with state changes.

当应用程序线程等待用户输入的时候,有一个独立的线程允许数据流经 graph 。多线程的危险就在于一个 filter 在它暂停的时候创建资源(在应用程序线程),在 streaming method 内部使用资源,当它停止的时候销毁资源(也在应用程序线程)。如果不小心,流线程会在资源被销毁以后使用它们。解决方法是使用临界区保护资源,同步 streaming methods 状态改变。

A filter needs one critical section to protect the filter state. The CBaseFilter class has a member variable for this critical section, CBaseFilter::m_pLock . This critical section is called the filter lock . Also, each input pin needs a critical section to protect resources used by the streaming thread. These critical sections are called streaming locks ; you must declare them in your derived pin class. It is easiest to use the CCritSec class, which wraps a Windows CRITICAL_SECTION object and can be locked using the CAutoLock class. The CCritSec class also provides some useful debugging functions. For more information, see Critical Section Debugging Functions .

filter 需要一个临界区来保护 filter 状态。 CBaseFilter 类有一个临界区成员变量 CBaseFilter::m_pLock 。这个临界区称作 filter 锁。而且,每一个输入 pin 需要一个临界区来保护被流线程使用的资源。这些临界区称为流锁。在派生的 pin 类中必须声明它们。可以简单的使用 CCritSec 类,这个类封装了 windows CRITICAL_SECTION 对象和使用 CAutoLock 类。 CCritSec 类也提供了一些用来调试的函数。

When a filter stops or flushes, it must synchronize the application thread with the streaming thread. To avoid deadlocking, it must first unblock the streaming thread, which might be blocked for several reasons:

当一个 filter 停止或者刷新的时候,它必须同步应用程序线程和流线程。为了避免死锁,它必须首先激活流线程,下列几种情况可能出现阻塞:

·         It is waiting to get a sample inside the IMemAllocator::GetBuffer method, because all of the allocator's samples are in use.

·         IMemAllocator::GetBuffer 中等待获得一个 sample ,因为所有的 sample 都在使用。

·         It is waiting for another filter to return from a streaming method, such as Receive .

·         等待另一个 filter streaming method 中返回,例如 Receive

·         It is waiting inside one of its own streaming methods, for some resource to become available.

·         等待在它拥有的 streaming methods 中,以至于一些资源变得可用。

·         It is a renderer filter waiting for the presentation time of the next sample

·         它是一个 renderer filter ,等待下一帧的播放时间。

·         It is a renderer filter waiting inside the Receive method while paused.

·         它是一个 renderer filter 当暂停的时候等待在 Receive 函数中。

Therefore, when the filter stops or flushes, it must do the following:

因此,当 filter 停止或者刷新的时候,必须做下列的事情:

·         Release any sample it is holding for any reason. Doing so unblocks the GetBuffer method.

·         无条件释放它正在使用的全部 sample 。确保不会阻塞在 GetBuffer 中。

·         Return from any streaming method as quickly as possible. If a streaming method is waiting for a resource, it must stop waiting immediately.

·         尽快从 streaming method 中返回。如果 streaming method 正等待某个资源,立刻停止等待。

·         Start rejecting samples in Receive , so that the streaming thread does not access any more resources. (The CBaseInputPin class handles this automatically.)

·         Receive 中拒绝 sample ,以至于 streaming thread 不访问更多的资源。( CBaseInputPin 类自动处理)。

·         The Stop method must decommit all of the filter's allocators. (The CBaseInputPin class handles this automatically.)

·         Stop 函数必须释放所有的 filter 分配器。( CBaseInputPin 类自动处理)

Flushing and stopping both happen on the application thread. A filter stops in response to the IMediaControl::Stop method. The Filter Graph Manager issues the stop command in upstream order, starting from the renderers and working backward to the source filters. The stop command happens completely inside the filter's CBaseFilter::Stop method. When the method returns, the filter should be in a stopped state.

刷新和停止都是发生在应用程序线程。 filter IMediaControl::Stop 方法作出停止的反映。 Filter Graph Manager 按照从下到上的顺序发送停止命令,从 renderer 开始,向 source filter 发送。停止命令完全在 filter CBaseFilter::Stop 方法中发生。当方法返回时, filter 将处于停止状态。

Flushing typically occurs because of a seek command. A flush command starts from the source or parser filter, and travels downstream. Flushing happens in two stages: The IPin::BeginFlush method informs a filter to discard all pending and incoming data; the IPin::EndFlush method signals the filter to accept data again. Flushing requires two stages because the BeginFlush call is on the application thread, during which the streaming thread continues to deliver data. Therefore, some samples may arrive after the BeginFlush call. The filter should discard these. Any samples that arrive after the EndFlush call are guaranteed to be new, and should be delivered.

刷新发生通常是由于 seek 命令。一个刷新命令从 source filter parser filter 开始,然后向下游传递。刷新分两个阶段。 IPin::BeginFlush 通知 filter 丢掉所有未到达和正在达到的数据; IPin::EndFlush 通知 filter 再次接收数据。刷新需要两个阶段,因为 BeginFlush 在应用程序线程调用,在这个期间流线程一直都在传递数据。因此,一些 sample 会在 BeginFlush 之后到达。 filter 应该丢弃这些 sample 。在 EndFlush 之后到达的 sample 被保证是新的,必须传递这些 sample

 

你可能感兴趣的:([DirectShow]041 - The Streaming and Application Threads)