VideoHelp Forum




+ Reply to Thread
Results 1 to 8 of 8
  1. Member
    Join Date
    Jul 2007
    Location
    on your couch
    Search Comp PM
    I am attempting to create a DirectShow graph that loads a video from a file, and then displays it on the screen while at the same time transcoding it to a new output file.

    I can create this filter in the Graph Editor by starting with a file source filter. I connect that to the input of an infinite pin tee. Output 1 of the tee goes to a video renderer. Output 2 of the tee goes to an AVI mux filter which then goes to a file writer. Some intermediate filters are created as needed (to decode the data in the original file). When I create this filter in Graph Edit it works perfect.

    Now I create this filter in software, using code similar to the example here. My first test is to render both output pins of the tee using IGraphBuilder::Render(). This works perfect. I see two windows playing the video. The problems occur when I add the AVI muxer and the File Writer.

    These are the tasks I am completing in my test application, the order they are done in varies (I'll explain below) but is basically this:

    - Initialize COM.
    - Create and initialize graph builder, infinite pin tee, muxer, and file writer.
    - Add source filter for input file.
    - Add infinite pin tee.
    - Add muxer.
    - Add file writer.
    - Connect source filter to tee.
    - Render() tee output 0.
    - Connect tee output 1 to muxer.
    - Connect muxer output to file writer.
    - Run graph.
    - Wait for graph to finish (with IMediaEvent).

    I have noticed the following completely illogical behavior. I can't even attempt to explain it, and I'd love to figure out what I am doing wrong. So riddle me this... what is causing the following problems that I have observed, and how do I get it all working correctly?

    If I do the steps in the following order:
    - Add source filter.
    - Add tee.
    - Add muxer.
    - Add file writer.
    - Render tee output 0.
    - Tee output 1 -> muxer -> file writer.

    Connecting tee output 1 fails giving the error "intermediate filters could not be found".

    If I connect the tee this way instead:
    - Tee output 0 -> muxer -> file writer.
    - Render tee output 1.

    Then nothing fails. Yet the application ends immediately (with IMediaEvent reporting succesful completion of Run()), the renderer window does not even pop up, and the file is the correct size but is unplayable and corrupt.

    If I just render both tee outputs:
    - Render tee output 0.
    - Render tee output 1.

    The same thing happens. Ends immediately, no errors, but nothing happens.

    BUT, if I render to both outputs, but I do NOT add the AVI muxer to the graph, then it works fine. So regardless of whether or not I actually use the muxer, the mere action of adding it to the graph before rendering the tee output pins messes everything up.

    Weird? Well, if I render both tee outputs BEFORE adding the muxer, then the rendering works fine! So it's not the presence of the muxer per se, it's the fact that the muxer was present BEFORE connecting the tee output pins that broke it (and it's broken... like I said, no errors reported yet it clearly fails).

    Also, if I render tee output 0 BEFORE adding the muxer, and then add the muxer, and then connect tee output 1 to the muxer, no errors are generated. When I Run() this graph the video renderer works just fine. But the muxer -> file writer does nothing and the output file is corrupt.

    But it gets even stranger. If I go back to the original order... adding the muxer first, sending tee output 0 to the renderer and tee output 1 to the muxer then to the file writer, I can use Graph Edit to attach to my application and view the graph. When I do this I see the graph I expected. But when I run this graph in graph editor... it works -perfectly-, even though it does not work at all if I just call Run() from my application.

    So to sum up the weirdness:
    - If the muxer is present before the tee pins are connected (even if both are just being rendered), things "secretly" fail.
    - If pin 0 is rendered and pin 1 goes to the muxer, Connect() fails on pin 1.
    - If pin 0 is rendered before adding the muxer, and pin 1 goes to the muxer, the renderer works properly but the muxer -> file writer "secretly" fails.
    - If pin 0 goes to the muxer and pin 1 is rendered, things "secretly" fail.
    - When the graph is constructed from scratch in Graph Edit, it works.
    - When Graph Edit attaches to my process and runs the graph, it works.

    None of that makes any sense to me whatsoever, and my application is not working. I feel like there must be something simple that I'm doing wrong, perhaps a messed up reference count? But I'm using CComPtr's to manage everything and it seems to all be working OK; and it does work fine if I attach Graph Edit to my process and run it from there. I have no idea what the problem could be.

    Attached is the code that I have; this is the entire test app. The meat is down in main(), everything before it is just random little utility functions. I tried to keep it as minimal as possible but still useful for debugging. The application is a console application. The first command line parameter is the filename to play, the second is the output filename (but as long as infn and outfn contain valid wide-character filenames after that command line logic at the start, it'll all work).

    Any advice would be greatly appreciated; if anything is unclear please ask and I'll try to come up with a better explanation or example! Thanks a lot,

    - Jason

    Referenced source code: main.cpp

    This is a copy of a post I also made at the MSDN forum here. It's really boggling my mind; thought I'd see if any you guys over here had any DirectShow experience.
    Quote Quote  
  2. Check that you are identifying the correct input pins on the AVI Muxer. When you connect a pin, a new unconnected pin gets created. If you make assumptions about the pins (instead of enumerating them). you can end up in a weird place. It happened to me - I ended up with a fragment of a graph connected to nothing since I had attempted to connect it to a pin that already was connected. All because I assumed the pin order and names (e.g., Input 00, Input 01 etc). Once I did the right thing and enumerated them, checked their directions and connected statuses, the problem went away.

    Graph Edit likely does the right thing, too. After all, it displays a representation of the filter, so it has to query the filter to get at the pins.

    HTH,

    John.
    John Miller
    Quote Quote  
  3. Member
    Join Date
    Jul 2007
    Location
    on your couch
    Search Comp PM
    Thanks for your reply; that's a great point and eventually led to me "solving" (well, transforming) the problem. So I modified my code to attach to the first unconnected pin in a given direction instead of indexing things. Same problem, but because of that, the information I was printing led me to notice something really weird.

    Start up Graph Edit. Add to your graph a File Source with a valid AVI video attached, an Infinite Pin Tee, an AVI Muxer, and a File Writer. Add them all before making any connections. This represents what my application was doing (I guess I never actually set up the graph in Graph Edit in the exact same way as my code was). Now, connect the File Source output to the Tee input. Now remember, the goal is to render one output of the tee to a Video Renderer and send the other to the Muxer + File Writer. Well, right after connecting the source to the tee input, right click on the tee output and pick "Render".

    Surprise! It sees that the File Writer is already in the graph and, rather than creating a new Video Renderer, it takes it upon itself to use the File Writer instead! It also automatically uses the existing AVI Muxer as an intermediate between the tee and the file writer! Next my software, assuming that the IGraphBuilder::Render() had created a video renderer, connects the tee to the second AVI Muxer input, thus creating a duplicate connection. Things get all messed up. Now restart Graph Edit and follow the exact same steps except this time do not add an AVI Muxer and File Writer filter to the graph before Rendering the tee output pin. Here you'll notice that DirectShow automagically creates that Video Renderer filter and connects the tee output to it. This explains why the video renderer window worked when I Render()d the pin -before- adding the Muxer to the graph, but not after (because if you Render() the pin after adding the Muxer + File Writer but before connecting them, DirectShow uses those instead of a new Video Renderer). Weird, and slightly annoying.

    So I solved the problem by checking the connection status on pins as JohnnyMalaria suggested, and also by explicitly creating and connecting a Video Renderer filter rather than relying on IGraphBuilder::Render() to do what I want.

    If I had only run through Graph Edit exactly the way my app was doing it before I would've solved my problem a lot quicker. Lesson learned. It had always been working when I created the graph in Graph Edit because I always created and connected a Video Renderer explicitly instead of clicking "Render" on the output pins. I guess the "File Writer" is registered as some kind of "valid render target" or something, and DirectShow prefers to use already-created, and unconnected filters instead of creating new ones... and the presence of an unused AVI Muxer in the graph gave it the necessary bridge to the File Writer that Render() needed.

    Now I am having an entirely different problem that I can't figure out. The File Writer works correctly in Graph Edit, producing a playable output file. However in my software, when I run the graph the file is created, has the correct size with some data in it (glancing at it with a hex editor), but is corrupt and unplayable. Is there something I need to do in my software to somehow... "finalize" (or something) the output file? To commit header data or something to it? Right now I'm just calling Run() and then using IMediaEvent to wait for it to finish; then releasing the interfaces and exiting. It's leaving me with a corrupt file -- I can't figure out what Graph Edit is doing differently. Any ideas? One thing I noticed is if I create my graph, attach Graph Edit to my process, and view my graph, it looks OK. But if I save it as a GRF file then open it again, for some reason the Tee is no longer connected to the AVI Muxer, leaving the Muxer + File Writer isolated in the graph. But I think that might just be a bug in Graph Edit because 1) the Tee output pin IDs are different (possibly confusing Graph Edit) and 2) running this graph doesn't have the same effect as running my software (the output file remains 0 length instead of being filled with corrupt data), suggesting that it's not actually the same graph that my application is creating.

    Thanks again,
    Jason

    New source code (with new corrupt output file problem) attached here:
    main.cpp

    Sorry about the poor image quality below.

    What the graph should look like:


    Step 1 to recreate problem -- add filters:


    Step 2 -- connect input:


    Step 3 -- render tee output:


    Step 4 -- see how DirectShow uses free muxer + file writer instead of new video renderer:


    My app, assuming new video renderer was created, again connected next tee input to muxer input; producing the following graph (which, as you see, is not what I want at all):
    Quote Quote  
  4. Member
    Join Date
    Jul 2007
    Location
    on your couch
    Search Comp PM
    Fixed the last problem too.

    The reason the file was coming out corrupt is that I guess you have to call Stop() on the graph? Dunno why, guess some stuff gets flushed to disk on Stop() and Stop() isn't implied by Release(). It's not enough to Start() then wait for it to finish.

    Well cool, that fixes all the problems. Thanks for helping me out with that pin thing!

    Jason
    Quote Quote  
  5. Glad I was of help, albeit indirectly(!)

    The Stop() thing makes sense. You can't really do anything to a filter while the graph is in the run state. You can demonstrate this in GraphEdit - create a graph, make it run and try to disconnect pins or delete a filter. It won't let you do it.

    In our DV processor software, this would be a problem since we want to be able to dynamically change parts of the graph (such as the input) while it is running. I had an idea to write a special pair of filters that would bridge two graphs, allowing one to be stopped and changed, while the other runs. When searching for some pointers (no pun intended) on Google, I found that the very concept had already been implemented by Geraint Davies - the original architect of DirectShow, now a consultant. His GMFBridge Framework is free and, given his background, expertly implemented.
    John Miller
    Quote Quote  
  6. Member
    Join Date
    Jul 2007
    Location
    on your couch
    Search Comp PM
    Originally Posted by JohnnyMalaria
    I had an idea to write a special pair of filters that would bridge two graphs, allowing one to be stopped and changed, while the other runs. When searching for some pointers (no pun intended) on Google, I found that the very concept had already been implemented by Geraint Davies - the original architect of DirectShow, now a consultant. His GMFBridge Framework is free and, given his background, expertly implemented.
    Funny, I was thinking today, "is there a way to modify the output file settings without stopping the graph", so I decided to come back here and ask. Then I decided to check on this thread to see if there were any new replies. And lo and behold (and I forgot you mentioned this) here is my answer.

    Thanks for helping me with a problem that I didn't even have yet! Can I borrow your crystal ball some time? A PDF document describing GMFBridge along with links to download the source code can be found here.
    Quote Quote  
  7. Member
    Join Date
    Nov 2008
    Location
    Sri Lanka
    Search Comp PM
    Thank you so much you all. I accidentally came across this forum post and it was very helpful to me.

    I am writing an application which can receive RTP data streams from the network and write it to a file while rendering on the screen at the same time.
    I am using StreamCoders RTP AV Source filter to receive RTP data.

    Also I want to render RTP data to a specific IP/port (both video and audio) in my application. For the moment I am using Streamcoders RTP AV Renerer BETA version filter. It has no API/documentation provided still. So it can be used only in the Graph Edit for testing purposes and it can't be used in application programming.

    If you know about a filter that can be used for the above purpose please do let me know. It will be really helpful.
    Thank you.

    Hasini.
    Quote Quote  
  8. Our DV processor software has a pair of DirectShow filters to transmit/receive DV streams via TCP. They are fairly straightforward - well, as far as any Winsock-based code can be straightforward

    Please PM me if you'd like to discuss how create similar filters for your needs.
    John Miller
    Quote Quote  



Similar Threads

Visit our sponsor! Try DVDFab and backup Blu-rays!