Lingering graphedit process

I tried to make a simple encoder avstream filter that just dumps some known data to the output pin (no matter what the input is). I plugged in a graphedit pipeline like this: avshws -> my_encoder -> dump.ax . This connected fine and when I press play, my output pin’s Process() gets called once, followed by 2 calls to my input pin’s Process(). (I use the same Process function for both pins, but I check the pin’s data flow direction and decide which one is being called). After this, there is no call, and if I press Stop on graphedit and close it off, I still see the process hanging around. It doesn’t get killed if I try end task (with process explorer / task manager). I’m new to this, and I’m pretty sure I didn’t understand how to write the Process() function and I’m not cleaning something up right. So could you give me some hints for the following:

  1. Right now, I’m not using any clone pointers because I’m merely sending a few fixed characters to the output buffer. Could someone give me a rough pseudo code of what I need to do to in Process() achieve the following : if there is data at the input pin, the output pin needs to send the exact same data at the output (something like a passthrough).

  2. In the above scenario, when exactly do I return STATUS_PENDING (for input and output pins), and when do I use KsStreamPointerUnlock(pLeading, TRUE) (as opposed to FALSE) ?

>and if I press Stop on graphedit and close it off, I still see the process hanging around. It doesn’t get

killed if I try end task

Some pending IRP is never completed and is not cancellable.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

Thanks Maxim. I see this happening only when I start playing the pipeline, so I’m guessing this has to do with my Process() function (that is the part I haven’t understood properly yet). Do you mind giving me a rough idea of how to write the Process() function to accomplish the task I mentioned earlier? Perhaps doing that right might help me fix this pending IRP problem.

xxxxx@gmail.com wrote:

I tried to make a simple encoder avstream filter that just dumps some known data to the output pin (no matter what the input is). I plugged in a graphedit pipeline like this: avshws -> my_encoder -> dump.ax . This connected fine and when I press play, my output pin’s Process() gets called once, followed by 2 calls to my input pin’s Process(). (I use the same Process function for both pins, but I check the pin’s data flow direction and decide which one is being called). After this, there is no call, and if I press Stop on graphedit and close it off, I still see the process hanging around. It doesn’t get killed if I try end task (with process explorer / task manager). I’m new to this, and I’m pretty sure I didn’t understand how to write the Process() function and I’m not cleaning something up right. So could you give me some hints for the following:

  1. Right now, I’m not using any clone pointers because I’m merely sending a few fixed characters to the output buffer. Could someone give me a rough pseudo code of what I need to do to in Process() achieve the following : if there is data at the input pin, the output pin needs to send the exact same data at the output (something like a passthrough).

You need to deal with the situation where the output Process is called
before you have input data to supply. If you have input data, then it’s
pretty easy to copy the data and advance the pointer. If not, you’ll
either have to return dummy data, or return pending.

If you DO return STATUS_PENDING, then it is up to YOU to make sure that
you eventually complete the request. One way to do that is to have the
input pin call KsPinAttemptProcessing on the output pin when it has data
ready. That will cause the output pin’s Process callback to be called
again, where it can do the copy.

You’ll also need to check for pending processing when you transition out
of RUN mode, to handle shutdown.

  1. In the above scenario, when exactly do I return STATUS_PENDING (for input and output pins), and when do I use KsStreamPointerUnlock(pLeading, TRUE) (as opposed to FALSE) ?

Your filter will not release a buffer until it is ejected. A buffer can
be ejected in two ways. You either use KsStreamPointerAdvance to
advance the pointer a little bit at a time until the buffer is filled,
or you use KsStreamPointerUnlock with eject TRUE to force the current
buffer to be passed along even if not completely filled. Video drivers
commonly use “unlock with eject” because, video frames come in a frame
at a time, and one frame == one buffer. Audio drivers commonly use the
“advance” method, because a single sample doesn’t fill the frame.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Tim, this was great help, thank you! I started out by doing what you suggested:

  1. I returned STATUS_SUCCESS from Process() (same function for both input and output)
  2. I now got a few more calls to output pin before input pin process was called. I returned a dummy byte and called KsStreamPointerUnlock with true.
  3. When the input pin’s process was called, I copied the frame data to a static array, called KsPinAttemptProcessing on the output pin (not sure if this was necessary), and then called KsStreamPointerUnlock with true. Again, STATUS_SUCCESS is always my return value from Process().

After I stopped and closed graphedit, I still saw that process lingering. You mentioned that I need to check for pending processing when transitioning out of RUN mode - can you explain this a bit? Assuming I don’t clone any stream pointers, how do I check and cancel anything that is pending? (I assume this goes into SetState with from = RUN and to = PAUSE).

xxxxx@gmail.com wrote:

Tim, this was great help, thank you! I started out by doing what you suggested:

  1. I returned STATUS_SUCCESS from Process() (same function for both input and output)
  2. I now got a few more calls to output pin before input pin process was called. I returned a dummy byte and called KsStreamPointerUnlock with true.

Are you setting StreamHeader->DataUsed in the PKSSTREAM_POINTER so that
the caller knows how much data you added?

After I stopped and closed graphedit, I still saw that process lingering. You mentioned that I need to check for pending processing when transitioning out of RUN mode - can you explain this a bit? Assuming I don’t clone any stream pointers, how do I check and cancel anything that is pending?

If you have not returned STATUS_PENDING, then there won’t be any
outstanding requests to complete.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Tim,

Yes I set DataUsed. My half-done Process function looks like this, could you please check -

PKSSTREAM_POINTER pLeading = NULL;
pLeading = KsPinGetLeadingEdgeStreamPointer(m_Pin, KSSTREAM_POINTER_STATE_LOCKED);
if( pLeading && m_Pin->DataFlow == KSPIN_DATAFLOW_IN ) // Input
{
PKSSTREAM_POINTER pClone = NULL;
PKSSTREAM_HEADER pHeader = pLeading->StreamHeader;
PBYTE pData = static_cast( pHeader->Data );
CMyEncPin::FrameDataSize = (pHeader->FrameExtent >= FRAME_DATA_SIZE) ? FRAME_DATA_SIZE : pHeader->FrameExtent;
// Make a copy of the frame (overwriting the previous copy)
RtlCopyMemory(CMyEncPin::FrameData, pHeader->Data, CMyEncPin::FrameDataSize);

//// Is there a better way to get the output pin handle?
//PKSFILTER pFilter = KsPinGetParentFilter(m_Pin);
//if( pFilter )
//{
// PKSPIN pOutputPin = KsFilterGetFirstChildPin(pFilter, 1);
// if( pOutputPin )
// {
// // Make the output pin’s process function be called
// KsPinAttemptProcessing(pOutputPin, TRUE);
// }
//}

}
else if( pLeading && m_Pin->DataFlow == KSPIN_DATAFLOW_OUT ) // Output
{
// TODO: Fill this
PKSSTREAM_HEADER pHeader = pLeading->StreamHeader;
PBYTE pData = static_cast( pHeader->Data );
if( CMyEncPin::FrameDataSize <= 0 ) // No valid data yet
{
// Just send one byte
RtlZeroMemory(pData, 1);
pHeader->DataUsed = 1;
}
else
{
// Valid data available, copy that
ULONG dataUsed = (pLeading->OffsetOut.Count >= CMyEncPin::FrameDataSize) ?
CMyEncPin::FrameDataSize : pLeading->OffsetOut.Count;
RtlCopyMemory(pData, CMyEncPin::FrameData, dataUsed);
pHeader->DataUsed = dataUsed;
RtlZeroMemory(CMyEncPin::FrameData, CMyEncPin::FrameDataSize);
CMyEncPin::FrameDataSize = 0; // Reset for next frame
}
}
if( pLeading )
{
KsStreamPointerUnlock(pLeading, TRUE);
}

return Status;

Forgot to mention that Status is always STATUS_SUCCESS.

xxxxx@gmail.com wrote:

Yes I set DataUsed. My half-done Process function looks like this, could you please check -

It shouldn’t take much more than that

//// Is there a better way to get the output pin handle?

If it were me, I’d probably have each pin’s constructor call a
registration function in the filter, so the filter can keep an array of
pin instances. Of course, that’s almost exactly what the code you
currently have does.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Thanks for the confirmation. I wonder what else might cause the lingering. If you happen to think of something, please do let me know!

Tim,

I found the problem. While modifying avshws, I seem to have removed a part that caused m_Clock handle to not be freed up. Once I released that handle, graphedit process disappeared just fine. Before I close, could I ask you what that “registration function in the filter” is that you mentioned? I couldn’t find it through googling.

xxxxx@gmail.com wrote:

I found the problem. While modifying avshws, I seem to have removed a part that caused m_Clock handle to not be freed up. Once I released that handle, graphedit process disappeared just fine. Before I close, could I ask you what that “registration function in the filter” is that you mentioned? I couldn’t find it through googling.

A DirectShow filter registers itself in the registry in a function
called DllRegisterServer, which usually calls AMovieDllRegisterServer2
in the DirectShow base classes. That doesn’t really apply to AVStream.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Thanks a lot. You’ve been great help.