This is a Push Source filter for DirectShow. It can be used for pushing
(uploading) data to DirectShow.

Requires DSPACK from www.progdigy.com (see DSPACK subdirectory)
Note that when compiled with V2.3.4 an error migth occur when
the graph is stopped. The included DSPACK files don't have this
problem and are of a more recent CVS version.
The only addition to this CVS code is a single line in BaseClass.pas:
     IInterface = IUnknown;

Requires INDY from www.indyproject.org (see INDY subdirectory)


Version history
20060115:  V1.00  - Initial release
20060119:  V1.00  - Added SAMPLE.GRF. The MPEG 2 demultiplexer has the PIDs
                    for the video/audio associated with the SAMPLE.TS file,
                    so you will at least see something when pushing SAMPLE.TS.
                    Note that you first need to render the output pins
                    of the MPEG2 demultiplexer (audio and video) before
                    starting the graph and pushing the file from the
                    property page.
20060922:  V2.00  - Added UDP receiver/listener
                    Data can now be 'uploaded' by means of the 'PushData'
                    method, or by means of the UDP connection (or both)
                    Note: I'm not too happy with the performance of the
                          UDP receiver. Tests with other implementations
                          (e.g. buffering data, different UDP servers)
                          were all the same (most of them were worse).
                  - Added option for synchronization of data (data is
                    synchronized with the packet sync byte $47)
                  - Settings are saved/retrieved (saved/restored in/from a
                    graph or in the registry)
                  - Compiled with 'Turbo Delphi 2006 Explorer'
                    (previous versions used Delphi 5 Personal, but since
                     the above version is also 'free' and more recent ....)


Settings are both retained in the registry and in a saved graph.
When the filter is created, settings are retrieved from the
registry. This also applies if a graph with the filter is loaded.
When a graph with the filter is loaded, the settings are also
retrieved from this saved graph.
If the filter is created by means of a loaded graph (in contrast
to a 'manually' added filter) then the settings will -not- be saved
to the registry.
Loading of the registry settings can be switched off by manually
editing the registry setting
  HKEY_CURRENT_USER\Software\Major\MajorPushSource\
    Modify the 'UseRegistrySettings' to either '0' (no) or '1' (yes).


Hints/Notes:
. After initialization/setup only one procedure of the filter is called
  for pushing data: PushData()
. The filter can be used without any application code from within GraphEdit.
  Make sure the buffer requirements and the media types are set before
  connecting (rendering) the output pin. Then render the whole graph.
  After starting the graph you can use 'Push file' for pushing data from a file.
. Setting SyncData on is not essential for a correct operation (eg. for getting
  video/audio), if data is not synchronized (asynchronized data seems to be
  handled correctly). However, setting SyncData on will make sure data
  IS synchronizised at the very start of the graph, and filters relying on
  synchronized data will have no problems.
  Keep in mind that synchronization assumes we are delaing with transport
  stream packets of 188 bytes which need to start with the sync byte $47.
  If this is not the data being pushed/uploaded then synchronization must
  be set off.


*******************************************************************************
Typical application code/steps (untested!), see SAMPLE directory for an
working implemenation:

1> Include the IMajorPushSource definition and the CLSID identifiers in you application:

         IID_MajorPushSource          = '{6D616A6F-7269-7479-6E6C-535243020200}';
         T_IID_MajorPushSource: TGUID = IID_MajorPushSource;

         IMajorPushSource = interface(IUnknown)
         [IID_MajorPushSource]
           function  GetVersionInformation(out Info: PChar): HRESULT; stdcall;        // Get version information
           function  GetInformation       (out Info: PChar): HRESULT; stdcall;        // Get next text information (debug)
           function  GetInformationCount  (out Count: Integer): HRESULT; stdcall;     // Get information count (debug)
           function  GetDeliveredCount    (out Count: Integer): HRESULT; stdcall;     // Get number of bytes delivered to output pin
           procedure SetLog               (OnOff: Boolean); stdcall;                  // (De)activate file log
           function  GetLog               (out OnOff: Boolean): HRESULT; stdcall;     // Get status activation log file
           procedure SetSyncData          (OnOff: Boolean); stdcall;                  // (De)activate synchronization on start packet syncbyte $47
           function  GetSyncData          (out OnOff: Boolean): HRESULT; stdcall;     // Get status synchronization
           procedure SetUdp               (Port: Integer; BufferSize: Integer); stdcall;                    // Set UDP port for listening (<=0 to deactivate), buffersize (0 for default)
           function  GetUdp               (out Port: Integer; out BufferSize: Integer): HRESULT; stdcall;   // Get UDP port setup for listening (<0 to deactivate)
           procedure SetAddTimestamps     (OnOff: Boolean); stdcall;                  // (De)activate timestamps in media samples
           function  GetAddTimestamps     (out OnOff: Boolean): HRESULT; stdcall;     // Get status timestamps
           procedure SetMediaType         (MajorType: PCLSID; MinorType: PCLSID; FormatType: PCLSID; CheckType: Boolean); stdcall;                // Set media types when pin (re)connects
           function  GetMediaType         (MajorType: PCLSID; MinorType: PCLSID; FormatType: PCLSID; out CheckType: Boolean): HRESULT; stdcall;   // Get media types to use when pin (re)connects
           procedure SetBufferSize        (BufferSize: Integer; BufferAlignment: Integer); stdcall;                           // Set (preferred) buffer requirements
           function  GetBufferSize        (out BufferSize: Integer; out BufferAlignment: Integer): HRESULT; stdcall;          // Get (decided) buffer requirements
           function  GetPushedData        (Buffer: PByte; Size: Integer): HRESULT; stdcall;                                   // Get first xx bytes of media sample of last pushed data (debug)
           procedure FlushData; stdcall;                                              // Flush data (assures next data is realigned)
           function  PushData             (Buffer: PByte; Size: Integer; out Delivered: Integer): HRESULT; stdcall;           // Push data
         end;

2> Define variables
         var
           FFilterPushSourceFilter   : IBaseFilter;
           FFilterPushSourceInterface: IMajorPushSource;
           FFilterGraph              : IFilterGraph2;

3> Create filter manager
         Hr := CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER, IID_IFilterGraph2, FFilterGraph);

4> Create push filter
         Hr := CoCreateInstance(CLSID_MajorPushSource, nil, CLSCTX_INPROC_SERVER, IID_IBaseFilter, FFilterPushSourceFilter);

   or load predefined graph and use the FindFilterByName for example to get the interface
         Hr := FFilterGraph.FindFilterByName('Major Push Source', FFilterPushSourceFilter);

5> Get the interface
         Hr := FFilterPushSource.QueryInterface(T_IID_MajorPushSource, FFilterPushSourceInterface);

   Note: Getting the interface can be omitted if we are using the
         "(FFilterPushSourceFilter as IMajorPushSource).XXXX" convention, which does an
         automatic QueryInterface. This is usefull if we only have to call some
         individual functions.

6> Change push source settings if appropriate (e.g. buffer size)
   This will not be possible when the graph is already complete, since the output pin of
   the filter is only set when the pin is being connected. In such a case, find
   the pin, disconnect it and reconnect it.
         (FFilterPushSourceFilter as IMajorPushSource).SetBufferSize(96256, 188, False);
   or
         FFilterPushSourceInterface.SetBufferSize(96256, 188, False);

7> Make sure the graph is rendered and the pins are connected (when a complete graph was loaded then
   this is already so).

8> Run the graph (pushing data when the graph is not in running state has little use)
         (FFilterGraph as IMediaControl).Run;

9> Push data
         (FFilterPushSourceFilter as IMajorPushSource).PushData(Buffer, BufferLength);
   or
         FFilterPushSourceInterface.PushData(Buffer, BufferLength);

10> Stop the graph when done pushing all data
         (FFilterGraph as IMediaControl).Stop;
         FFilterGraph.Abort;

11> Release the interfaces and such when completely done
         FFilterPushSourceInterface := nil;
         FFilterPushSourceFilter := nil;
         FFilterGraph := nil;