/* GStreamer
 * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net>
 *
 * gstdshow.cpp:
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include <atlbase.h>
#include <dmodshow.h>
#include <dmoreg.h>

#include "gstdshowutil.h"
#include "gstdshowfakesrc.h"

IPin * 
gst_dshow_get_pin_from_filter (IBaseFilter *filter, PIN_DIRECTION pindir)
{
  CComPtr<IEnumPins> enumpins;
  CComPtr<IPin> pin;
  HRESULT hres; 

  hres = filter->EnumPins (&enumpins);
  if (FAILED(hres)) {
    return NULL;
  }

  while (enumpins->Next (1, &pin, NULL) == S_OK)
  {
    PIN_DIRECTION pindirtmp;
    hres = pin->QueryDirection (&pindirtmp);
    if (hres == S_OK && pindir == pindirtmp) {
      return pin;
    }
    pin.Release();
  }

  return NULL;
}

IBaseFilter * 
gst_dshow_find_filter(CLSID input_majortype, CLSID input_subtype, 
                      CLSID output_majortype, CLSID output_subtype, 
                      PreferredFilter *preferred_filters)
{
  HRESULT hres;
  GUID inTypes[2];
  GUID outTypes[2];
  CComPtr<IFilterMapper2> mapper;
  CComPtr<IEnumMoniker> enum_moniker;
  CComPtr<IMoniker> moniker;
  ULONG fetched;
  IBaseFilter *filter;

  /* First, see if any of our preferred filters is available.
   * If not, we fall back to the highest-ranked installed filter */
  if (preferred_filters) {
    while (preferred_filters->filter_guid) 
    {
      /* If the filter is a DMO, we need to do this a bit differently */
      if (preferred_filters->dmo_category) 
      {
        CComPtr<IDMOWrapperFilter> wrapper;

        hres = CoCreateInstance (CLSID_DMOWrapperFilter, NULL, 
          CLSCTX_INPROC,
          IID_IBaseFilter, (void **)&filter);
        if (SUCCEEDED(hres)) {
          hres = filter->QueryInterface (&wrapper);
          if (SUCCEEDED(hres)) {
            hres = wrapper->Init (*preferred_filters->filter_guid, 
                *preferred_filters->dmo_category);
            if (SUCCEEDED(hres))
              return filter;
          }
          filter->Release();
        }
      }
      else 
      {
        hres = CoCreateInstance (*preferred_filters->filter_guid, 
          NULL, CLSCTX_INPROC,
          IID_IBaseFilter, (void **)&filter);
        if (SUCCEEDED(hres))
          return filter;
      }

      /* Continue to the next filter */
      preferred_filters++;
    }
  }

  hres = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC, 
      IID_IFilterMapper2, (void **) &mapper);
  if (FAILED(hres))
    return NULL;
  
  inTypes[0] = input_majortype;
  inTypes[1] = input_subtype;
  outTypes[0] = output_majortype;
  outTypes[1] = output_subtype;

  hres = mapper->EnumMatchingFilters (&enum_moniker, 0, 
          FALSE, MERIT_DO_NOT_USE+1, 
          TRUE, 1, inTypes, NULL, NULL, FALSE, 
          TRUE, 1, outTypes, NULL, NULL);
  if (FAILED(hres))
    return NULL;
  
  enum_moniker->Reset ();

  while(enum_moniker->Next (1, &moniker, &fetched) == S_OK)
  {
    hres = moniker->BindToObject(NULL, NULL, 
          IID_IBaseFilter, (void**)&filter);
    if(SUCCEEDED(hres)) {
      return filter;
    }
    moniker.Release ();
  }

  return NULL;
}