|
|
|
date: Sun, 20 Jul 2008 16:36:16 -0700 (PDT),
group: microsoft.public.win32.programmer.directx.video
back
Custom WMV source filter doesn't playback after WMT_EOF
Hi guys,
I'm trying to render WMV videos using DirectShow. I have it working,
but there's some edge cases that I'm having some problems with...
For various reasons we need to use our own networking to read files,
so we can't just use a standard WM ASF Reader filter to read videos. I
have implemented an IStream which uses our networking APIs and I have
a written a source filter which wraps a WMReaderAdvanced2 object
which opens and reads from the IStream and pushes audio and video
streams/samples downstream using COutputQueue. I can play WMVs fine
with this filter, except short WMVs. If I Start() the WMReader and let
it read the entire video (that is let it read until I get a WMT_EOF
delivered to OnStatus()), and if I then try to start playback in the
graph using IMediaControl::Run(), only the sound plays, no video
samples are delivered to my video renderer.
My theory is that because my WMV source filter is a push filter, when
EOF comes in, the thread in COutputQueue has no more samples to send
downstream, so the thread sleeps. Then when the graph runs there's no
thread to run the renderer, since the video stream is being "pushed"
from the WMV source filter's video-stream output pin, but it has no
more samples to push, so its thread doesn't run and doesn't service
the video-stream, and hence doesn't service the renderer and the video
stream doesn't render. Does that sound plausible?
My WMV source filter's audio stream connects downstream to a WMAudio
Decoder DMO, which connects to a Default DirectSoundDevice. My WMV
source filter's video stream connects to a WMVideo Decoder DMO, and
that connects to a VMR-7 renderer.
Do I need to rewrite my output pins on my WMV source to work in Pull
mode, so that the video rendering thread originates in the renderer?
Will the WM Decoder DMOs connect to upstream IAsyncReader pins? Or is
there some other way I can wake up the video stream's thread, or
something else I need to do?
Thanks,
Chris Pearce.
date: Sun, 20 Jul 2008 16:36:16 -0700 (PDT)
author: Chris Pearce
Re: Custom WMV source filter doesn't playback after WMT_EOF
From: "Chris Pearce"
[...]
> Do I need to rewrite my output pins on my WMV source to
> work in Pull mode, so that the video rendering thread
> originates in the renderer?
The stock renderers never spawn streaming threads. Streaming
threads are typically spawned by the push-side of sources,
like live push sources are pull-to-push parsers.
> Will the WM Decoder DMOs
> connect to upstream IAsyncReader pins?
No.
> Or is there some
> other way I can wake up the video stream's thread, or
> something else I need to do?
There is no such thing as a "video stream's thread". If you
are the "pusher", then the threads are yours. Actually, you
most likely own a few threads: the thread(s) spawned by the
WMReader to call you back and the thrwad spwned by the
COutputQueue.
From you description, it sounds like you are delivering
samples while the graph is in a stopped (inactive) state,
which is a error. You must deliver samples only when the
graph is in a paused/running (active) state. If you do, the
renderer will block your streaming thread (that is, the one
that delivers downstream) as needed. If you use a
COutputQueue, the streaming thread will be the queue's
worker thread, which seems unnecessary.
--
// Alessandro Angeli
// MVP :: DirectShow / MediaFoundation
// mvpnews at riseoftheants dot com
// http://www.riseoftheants.com/mmx/faq.htm
date: Mon, 21 Jul 2008 12:24:24 -0400
author: Alessandro Angeli
Re: Custom WMV source filter doesn't playback after WMT_EOF
On Jul 22, 4:24 am, "Alessandro Angeli"
wrote:
> [...]
> From you description, it sounds like you are delivering
> samples while the graph is in a stopped (inactive) state,
> which is a error. You must deliver samples only when the
> graph is in a paused/running (active) state. If you do, the
> renderer will block your streaming thread (that is, the one
> that delivers downstream) as needed.
Thanks for your insight Alessandro. This is happening when I've paused
the graph. When I load a WMV, I pause the graph straight away so that
I receive the "poster" frame to display. So unless the WMVideo Decoder
DMO is moving itself into stopped state if it's left too long, I don't
think that's the problem.
To my horror I've discovered that the WMVideo Decoder DMO is the
problem. If I load my WMV in GraphEdit, pause it, and wait for longer
than the duration of the movie before playing it, the video image
never updates, but sounds still plays. My WMV is a pretty simple one
produced by Windows Movie Maker on Vista SP1, and I can also reproduce
this problem with another WMV that I pulled of the 'net, so I don't
think this is caused by me playing a non-standard WMV.
When I run the graph, after it's been paused for longer than the
duration of the video, the WM Video Decoder DMO is still returning
success in its ReceiveMultiple() call, but there's no frames arriving
at the renderer. The GraphEdit doesn't report any frames dropped in
the renderer, and my NotifyPresentImage() isn't being called, so no
frames are coming in. I wonder if the WM Video Decoder DMO has a bug
in how it acts on sample time stamps.
Interestingly, I can't reproduce this problem in Windows Media Player,
so I guess they either work around it, or they don't use DirectShow to
render WMVs.
I'm not sure how I can work around this. I may try using Stop() the
graph instead of Pause()ing it, or I may have to get decompressed
frames from the WMReader and render the video using some other method.
Thanks,
Chris.
On Jul 22, 4:24 am, "Alessandro Angeli"
wrote:
> From: "Chris Pearce"
>
> [...]
>
> > Do I need to rewrite my output pins on my WMV source to
> > work in Pull mode, so that the video rendering thread
> > originates in the renderer?
>
> The stock renderers never spawn streaming threads. Streaming
> threads are typically spawned by the push-side of sources,
> like live push sources are pull-to-push parsers.
>
> > Will the WM Decoder DMOs
> > connect to upstream IAsyncReader pins?
>
> No.
>
> > Or is there some
> > other way I can wake up the video stream's thread, or
> > something else I need to do?
>
> There is no such thing as a "video stream's thread". If you
> are the "pusher", then the threads are yours. Actually, you
> most likely own a few threads: the thread(s) spawned by the
> WMReader to call you back and the thrwad spwned by the
> COutputQueue.
>
> From you description, it sounds like you are delivering
> samples while the graph is in a stopped (inactive) state,
> which is a error. You must deliver samples only when the
> graph is in a paused/running (active) state. If you do, the
> renderer will block your streaming thread (that is, the one
> that delivers downstream) as needed. If you use a
> COutputQueue, the streaming thread will be the queue's
> worker thread, which seems unnecessary.
>
> --
> // Alessandro Angeli
> // MVP :: DirectShow / MediaFoundation
> // mvpnews at riseoftheants dot com
> //http://www.riseoftheants.com/mmx/faq.htm
date: Wed, 23 Jul 2008 19:44:33 -0700 (PDT)
author: Chris Pearce
Re: Custom WMV source filter doesn't playback after WMT_EOF
From: "Chris Pearce"
> Interestingly, I can't reproduce this problem in Windows
> Media Player, so I guess they either work around it, or
> they don't use DirectShow to render WMVs.
WMP uses DirectShow and a custom WMV source filter (except
on Vista+, where it uses MF).
This is what's supposed to happen: you feed frames to the
decoder and the decoder feeds thems to the renderer. When
the renderer is paused, it blocks the thread that feeds it,
which in turn makes the decoder's buffer overflow so that
the decoder blocks your thread (depending on its buffer
size, that may happen after several frames). When the
decoder runs, it unblocks the thread and everything is
delivered and unblocked, without any loss.
On the other hand, if you feed the decoder frames that must
be dropped, nothing goes into its buffer and nothing reaches
the renderer, ever.
The WMV decoder (like most sensible decoders do) drops
frames that have the preroll flag set and frames that
follows a discontinuity and are not syncpoints, until the
first syncpoint. The beginning of a segment (the first frame
after a stop or seek or flush) is an implicit discontinuity.
Timestamps have nothing to do with this: they are only
really used by the renderer to keep the correct rendering
rate relative to the graph's clock. The renderer does not
drop frames based on the timestamps. The decoder instead may
drop frames if the renderer sends quality message because it
receives late samples (too slow), but that should never
happen when the graph is paused.
Of course, the stock renderers behave this way while custom
renderers can do what they want.
--
// Alessandro Angeli
// MVP :: DirectShow / MediaFoundation
// mvpnews at riseoftheants dot com
// http://www.riseoftheants.com/mmx/faq.htm
date: Thu, 24 Jul 2008 02:26:53 -0400
author: Alessandro Angeli
Re: Custom WMV source filter doesn't playback after WMT_EOF
Thanks again Alessandro.
On Jul 24, 6:26 pm, "Alessandro Angeli"
wrote:
> This is what's supposed to happen: you feed frames to the
> decoder and the decoder feeds thems to the renderer. When
> the renderer is paused, it blocks the thread that feeds it,
> which in turn makes the decoder's buffer overflow so that
> the decoder blocks your thread (depending on its buffer
> size, that may happen after several frames). When the
> decoder runs, it unblocks the thread and everything is
> delivered and unblocked, without any loss.
Here's what I'm seeing: when I first pause the graph, my filter pushes
a bunch of frames downstream, and the pushing thread blocks in a
ReceiveMultiple() call on the downstream pin. After 11 seconds (the
duration of the video) has passed, the ReceiveMultiple() call returns
S_OK, and the thread loops around and happily continues to push frames
downstream. Subsequent calls to ReceiveMultiple() return S_OK. The
source filter pushes the entire video downstream, but no samples/
frames pushed downstream ever arrive at the renderer when I unpause.
I have avoided this problem by doing a two-staged pause. Whenever I
want to pause the graph, I first pause the pins on the source filter.
When each pin's COutputQueue's thread returns from its next
ReceiveMultiple() call, the thread goes to sleep, and doesn't push
anything downstream. Once the pins' threads are safely asleep, I pause
the graph as usual using IMediaControl::Pause(). When I unpause the
graph I wake up the threads, and they can begin pushing downstream
again. Thus the graph is never paused when a queue's thread could
block in RecieveMultiple() call on the WMVideo Decoder DMO, so I avoid
the danger zone altogether. It's ugly, but it at least resolves this
issue for me. It means samples don't buffer in the decoder, but they
can still buffer on the COutputQueue's queue. At least they still
arrive at the renderer!
Thanks your help Alessandro.
All the best,
Chris Pearce.
date: Thu, 24 Jul 2008 19:56:06 -0700 (PDT)
author: Chris Pearce
Re: Custom WMV source filter doesn't playback after WMT_EOF
Thanks again Alessandro.
On Jul 24, 6:26 pm, "Alessandro Angeli"
wrote:
> This is what's supposed to happen: you feed frames to the
> decoder and the decoder feeds thems to the renderer. When
> the renderer is paused, it blocks the thread that feeds it,
> which in turn makes the decoder's buffer overflow so that
> the decoder blocks your thread (depending on its buffer
> size, that may happen after several frames). When the
> decoder runs, it unblocks the thread and everything is
> delivered and unblocked, without any loss.
Here's what I'm seeing: when I first pause the graph, my filter pushes
a bunch of frames downstream, and the pushing thread blocks in a
ReceiveMultiple() call on the downstream pin. After 11 seconds (the
duration of the video) has passed, the ReceiveMultiple() call returns
S_OK, and the thread loops around and happily continues to push frames
downstream. Subsequent calls to ReceiveMultiple() return S_OK. The
source filter pushes the entire video downstream, but no samples/
frames pushed downstream ever arrive at the renderer when I unpause.
I have avoided this problem by doing a two-staged pause. Whenever I
want to pause the graph, I first pause the pins on the source filter.
When each pin's COutputQueue's thread returns from its next
ReceiveMultiple() call, the thread goes to sleep, and doesn't push
anything downstream. Once the pins' threads are safely asleep, I pause
the graph as usual using IMediaControl::Pause(). When I unpause the
graph I wake up the threads, and they can begin pushing downstream
again. Thus the graph is never paused when a queue's thread could
block in RecieveMultiple() call on the WMVideo Decoder DMO, so I avoid
the danger zone altogether. It's ugly, but it at least resolves this
issue for me. It means samples don't buffer in the decoder, but they
can still buffer on the COutputQueue's queue. At least they still
arrive at the renderer!
Thanks your help Alessandro.
All the best,
Chris Pearce.
date: Thu, 24 Jul 2008 20:09:29 -0700 (PDT)
author: Chris Pearce
|
|