Jump to content
  • Advertisement
Sign in to follow this  
AyaKoshigaya

Playing AVI Files using DirectShow

This topic is 4456 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I need to Playblack AVI Videos in my Application and need support to step trough the Movie Frame by Frame. Currently I'm using the VFW-API for this, works very well but doesn't support all Codecs (i.E. xVid videos doesn't work).. so I thought I could switch over to DirectX for this. But, I now searched the whole web I think.. how can I step trough an Video like I can in VFW??! I have no problems Playing the AVI Video and grav the Frames via SampleGrabber, but FrameStepping.. - no chance :( I tried using the IVideoFrameStep Interface, but it seems like it doesn't work. The best thing would be, if I could call "getFrame(int frame)" and would get the data for this Frame, like in VFW. (This can be done using this Poster-Frame Interface, but that's way to slow) So, if anyone have any Idea how to do this.. please help me :) Au'revoir, Aya~

Share this post


Link to post
Share on other sites
Advertisement
IVideoFrameStep seems to be exactly what you want to use, so I would search out any documentation/samples/forum posts related to that. Alternatively, you could try IMediaSeeking. Here is an MSDN post that kind of sounds like your problem.

Share this post


Link to post
Share on other sites
Hi,

I don't know what I am doing wrong, but when I try to seek the Video with the IMediaSeeking Interface it allways jumps back to Frame 0.

This is my Initialisation:

  CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC, IID_IGraphBuilder, pGraph);
CoCreateInstance(CLSID_SampleGrabber, nil, CLSCTX_INPROC_SERVER, IID_IBaseFilter, pGrabberF);
CoCreateInstance(CLSID_NullRenderer, nil, CLSCTX_INPROC_SERVER, IID_IBaseFilter, pNull);
pGraph.QueryInterface(IID_IMediaControl, pControl);
pGraph.QueryInterface(IID_IMediaEvent, pEvent);
pGraph.QueryInterface(IID_IMediaSeeking, pSeeking);
pGraph.QueryInterface(IID_IMediaFilter, pFilter);

pSeeking.SetTimeFormat(TIME_FORMAT_FRAME);

pFilter.SetSyncSource(nil);

pGraph.AddFilter(pGrabberF, 'Sample Grabber');
pGraph.AddFilter(pNull, 'Null Render');
pGrabberF.QueryInterface(IID_ISampleGrabber, pGrabber);

ZeroMemory(@mType, SizeOf(AM_MEDIA_TYPE));
mType.majortype := MEDIATYPE_Video;
mType.subtype := MEDIASUBTYPE_RGB24;
pGrabber.SetMediaType(mType);

pGraph.AddSourceFilter(Filename, 'Source', pSrc);

ConnectFilters(pGraph, pSrc, pGrabberF);
ConnectFilters(pGraph, pGrabberF, pNull);

pGrabber.SetOneShot(false);
pGrabber.SetBufferSamples(true);

GrabberCB:=TSampleGrabberCB.Create;
GrabberCB.Parent:=Self;
pGrabber.SetCallback(GrabberCB, 1);



When I now use:
  pControl.Run;

the Video is Played back.

But when I call
  pSeeking.SetPositions(XXX, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning);

where XXX is any number you want, it just jumps back to Frame 0.

Does anyone know, why?

Aya~

Share this post


Link to post
Share on other sites
As Circlesoft says, you could use IVideoFrameStep for this. However, I don't recommend that for two reasons:

1. It only supports forward stepping

2. It isn't necessarily consistent in stepping. For example, one step may jump 1001 reference time units. The next step would jump around 300,000 time units (which, in my case, was actually close to the number of reference time units representing one frame).

Regarding your code, there are two problems I see:

1. You don't query the seeking interface to see whether it supports TIME_FORMAT_FRAME. Many filters don't--for example, WMV filters on my PC don't.

2. Even if TIME_FORMAT_FRAME is supported, some filters always return 0 as the current position, as well as silently fail to seek to any position as you have encountered (that is, returning S_OK even though they didn't seek).

In conclusion, use manual seeking instead:

void MediaPlayer::StepFrames(int numFrames)
{
if(m_state != MediaPlayerState::Paused)
Pause();

LONGLONG timePerFrame = ReferenceTimePerSecond / FrameRate();

LONGLONG currentPos;
DSE(m_mediaSeeking->GetCurrentPosition(&currentPos));

LONGLONG timeDelta = timePerFrame * abs(numFrames);

if(numFrames > 0)
{
currentPos += timeDelta;

if(currentPos > Duration())
currentPos = Duration();
}
else
{
currentPos -= timeDelta;

if(currentPos < 0)
currentPos = 0;
}

DSE(m_mediaSeeking->SetPositions(&currentPos, AM_SEEKING_AbsolutePositioning,
0, AM_SEEKING_NoPositioning));
}




In the above code, DSE is simply a macro that checks for failure and throws an exception.

Share this post


Link to post
Share on other sites
I know this is not an answer to your question, but I have been trying very very hard to playback videos in my game with DirectShow.
It never really worked as it should have. I mean: SLOW SLOW SLOW!
Even when you give the video stream enough time to work, it still skips frames, because of its internal low priority threads which you can 't change in a normal way.

I've tried using VFW (Video For Windows), of course this only works on windows, but it works much better. Only problem there is codecs, it doesn't play everything and if it plays, it sometimes doesn't really work as it should.

The final and really successful try was: FFMpeg, and this is REALLY good! I don't say it's flawless, but after including the libraries and compiling the example you see on the website, I had enough info to play back video's of lots of supported video formats, even without their codecs. Plus: it's fast!

Don't know if you needed this info, but if you're trying to implement videos in your game and want them to be smooth... don't go with DirectShow.

Share this post


Link to post
Share on other sites
Hi,

thanks a lot for your answers! :)

Muhammad Haggag: What is "ReferenceTimePerSecond" in your code example?? ^^

scippie: Sound's cool, I'll take a look at it :)

Aya~

Share this post


Link to post
Share on other sites
Quote:
Muhammad Haggag: What is "ReferenceTimePerSecond" in your code example?? ^^


// Constant: ReferenceTimePerSecond
// The number of reference time units per second. DirectShow uses a time unit where each
// corresponds to 100 nanoseconds. The media player uses the same units.
//
static const LONGLONG ReferenceTimePerSecond = 1e7;


Quote:
I know this is not an answer to your question, but I have been trying very very hard to playback videos in my game with DirectShow.
It never really worked as it should have. I mean: SLOW SLOW SLOW!

I'm curious--how do you use DirectShow in your game? Do you use it to play cutscenes, or are you using it to render to textures mid-game?

If it's for cutscenes, it should be fast enough--there should be nothing else working in the background. As far as rendering-to-texture using VMR, I recall that there was a D3D sample that did this, and was fast as well.

Share this post


Link to post
Share on other sites
Quote:
Original post by AyaKoshigaya
Hi,

thanks, Seeking works now. But.. it's not Frame by Frame.. more like 20 Frame Jumps or something :(

The time delta jumped per-frame depends on your frame rate. Are you sure the frame rate value you use is correct?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!