Dev Center - Desktop > Windows Desktop Development Forums > DirectShow Development > How to properly build a directshow graph to compress video...

Answered How to properly build a directshow graph to compress video...

  • Thursday, February 18, 2010 6:06 PM
     
     
    My graph is basically below (with audio muxed in)

    Capture Source --> XviD video compressor --> AVI Mux --> FileSink

    The problem is, in GraphEdit, I can bring up property page for XVid encoder, set them, run graph....and it works.

    I was trying to do this in c++, but because I could not programatically set the properties of the XVid encoder, I am looking for another way...

    I tried using WMVideo9 Encoder, but it would not let me connect it to AVI mux....

    I tried some others....and I ran into this issue (below)

    file source->avi splitter->decoder->encoder--->(WOULD NOT LET ME CONNECT DIRECTLY/INDIRECTLY TO AVI MUX ) --->avi mux-->file

    the only way to connect to AVI Mux would be to decode it again...which of course defeats the purpose...


    Can somebody provide a proper graph, for compressing a video, using (more or less) codecs guranteed to be on box, with normal windows installation?


Answers

  • Friday, February 19, 2010 1:41 PM
     
     Answered

    Well, the WMV encoder isn't usable with AVI files.

    If I read correctly, you were wanting to use XVid but couldn't because you couldn't configure it programmatically. Well, a work around is this:

    In GraphEdt, create a new graph. Add just the XVid encoder and manually configure it. Now save the graph to a .GRF file.

    Now, in your program, load the .grf file into your graph (I beleieve there is sample code in the SDK to do this) and then start adding the other components - Xvids settings are I believe persisted in the GRF files (this isn't true for all encoders, but most seem to). Thus XVid will be appropriately configured when you load the GRF file.

    Only warning is I'm not sure what might happen with different versions of the same codec e.g. if you create your .GRF files based on version 2 of a codec and the target system has version 3 of the codec then there is a risk it might not work. If your app is for your own use, or use by other techies this might not be an issue (in fact its an advantage as the other techies can create/modify profiles easilly), however I would avoid relying on GRF files if it is a general purpose commercial app.

    Alternatively, if you switch to using Ffdshow then there is an interface you can obtain from the filter that allows you to configure it , but the information is well hidden ( for the decoder, I had to get the source code and try and work it out from there as I couldn't find any documentation, and I think working out the interface to the encoder will be similarly painful). XVid may have its own configuration interface too but but I never found it).

    TTFN,

       Jon

All Replies

  • Friday, February 19, 2010 1:41 PM
     
     Answered

    Well, the WMV encoder isn't usable with AVI files.

    If I read correctly, you were wanting to use XVid but couldn't because you couldn't configure it programmatically. Well, a work around is this:

    In GraphEdt, create a new graph. Add just the XVid encoder and manually configure it. Now save the graph to a .GRF file.

    Now, in your program, load the .grf file into your graph (I beleieve there is sample code in the SDK to do this) and then start adding the other components - Xvids settings are I believe persisted in the GRF files (this isn't true for all encoders, but most seem to). Thus XVid will be appropriately configured when you load the GRF file.

    Only warning is I'm not sure what might happen with different versions of the same codec e.g. if you create your .GRF files based on version 2 of a codec and the target system has version 3 of the codec then there is a risk it might not work. If your app is for your own use, or use by other techies this might not be an issue (in fact its an advantage as the other techies can create/modify profiles easilly), however I would avoid relying on GRF files if it is a general purpose commercial app.

    Alternatively, if you switch to using Ffdshow then there is an interface you can obtain from the filter that allows you to configure it , but the information is well hidden ( for the decoder, I had to get the source code and try and work it out from there as I couldn't find any documentation, and I think working out the interface to the encoder will be similarly painful). XVid may have its own configuration interface too but but I never found it).

    TTFN,

       Jon

  • Friday, February 19, 2010 2:50 PM
     
     
    Thanks...very helpful information....

    I was not sure if the xvid settings were persisted in the GRF files so initially avoided that....will try that....

    Would you happen to know the ffdshow interface? I will open the dll up in OleView...maybe it will show them there.

    I was looking for a config interface on the XVid encoder, and could only find the one that presents a visually dialog box. (which I can present, but it is prefered not too, I suppose I could cheat and present it offscreen, and post a window message or something like that....that might or might not be a doable cheat)
  • Friday, February 19, 2010 4:45 PM
     
     
    Woohoo...

    It works....nice cheat, but it works.

  • Friday, February 19, 2010 6:50 PM
     
     
    One caveat though...

    Is there a way to "attach" to this filter?

    It's loaded, and I do a smart connect, but there is no guarantee that this is the first filter it will use in its search...

    I would like to load the grf file (which I do), and then attach to this loaded filter so I can manage the connections between filters manually.

    (otherwise it works)
  • Friday, February 19, 2010 7:06 PM
     
     
    Oh wait...I think I know...I just need to QueryInterface the stream...

    I tried below...didn't work....

    It works up to the QueryInterface part, I thought I read somewhere that's how you get the filter interface.


       HRESULT hr = StgOpenStorage(wszName, 0, STGM_TRANSACTED | STGM_READ | STGM_SHARE_DENY_WRITE, 0,0,&pStorage);

       if (SUCCEEDED(hr))
          hr = pGraph->QueryInterface(IID_IPersistStream, (void**)&pPersistStream);

       if (SUCCEEDED(hr))
          hr = pStorage->OpenStream(L"ActiveMovieGraph", 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);

       if(SUCCEEDED(hr))
          hr = pPersistStream->Load(pStream);

       hr = pStream->QueryInterface(IID_IBaseFilter, (void**)&pFilter);   <-- FAILS HERE

    pFilter = NULL after QueryInterface call

  • Friday, February 19, 2010 7:28 PM
     
     
    Ah found out how...

       pGraph->FindFilterByName(L"Xvid MPEG-4 Video Decoder", &pFilter); // gives me the filter just loaded
  • Monday, February 22, 2010 1:42 PM
     
     

    "Would you happen to know the ffdshow interface?"

    Fraid not. I've only be looking at the Ffdshow decoder though I think the encoder works muach the same way. It mostly uses two functions put_Param and get_Param, with a parameter ID number plus a value identifying what that item should be set to. Finding the ID numbers and the corresponding range of values is the tricky bit and I resorted to the source code plus looking at how params returned by GetParam varied as I changed codec settings in GraphEdt. However I used .NET which is not allowed here.

    "Ah found out how...

       pGraph->FindFilterByName(L"Xvid MPEG-4 Video Decoder", &pFilter); // gives me the filter just loaded"

    Yep, that'll work. However, if your graph only has one component then EnumFilters will result in only one filter being returned. Yes its a few more lines of code, however if you were to provide different GRF files for different profiles which might utilise different encoders then EnumFilters will always find your compressor regardless of which "profile" GRF file you decided to load.

    TTFN,
       Jon