Home | History | Annotate | Download | only in win
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media/video/capture/win/pin_base_win.h"
      6 
      7 #include "base/logging.h"
      8 
      9 namespace media {
     10 
     11 // Implement IEnumPins.
     12 class TypeEnumerator
     13     : public IEnumMediaTypes,
     14       public base::RefCounted<TypeEnumerator> {
     15  public:
     16   explicit TypeEnumerator(PinBase* pin)
     17       : pin_(pin),
     18         index_(0) {
     19   }
     20 
     21   ~TypeEnumerator() {
     22   }
     23 
     24   // Implement from IUnknown.
     25   STDMETHOD(QueryInterface)(REFIID iid, void** object_ptr) {
     26     if (iid == IID_IEnumMediaTypes || iid == IID_IUnknown) {
     27       AddRef();
     28       *object_ptr = static_cast<IEnumMediaTypes*>(this);
     29       return S_OK;
     30     }
     31     return E_NOINTERFACE;
     32   }
     33 
     34   STDMETHOD_(ULONG, AddRef)() {
     35     base::RefCounted<TypeEnumerator>::AddRef();
     36     return 1;
     37   }
     38 
     39   STDMETHOD_(ULONG, Release)() {
     40     base::RefCounted<TypeEnumerator>::Release();
     41     return 1;
     42   }
     43 
     44   // Implement IEnumMediaTypes.
     45   STDMETHOD(Next)(ULONG count, AM_MEDIA_TYPE** types, ULONG* fetched) {
     46     ULONG types_fetched = 0;
     47 
     48     while (types_fetched < count) {
     49       // Allocate AM_MEDIA_TYPE that we will store the media type in.
     50       AM_MEDIA_TYPE* type = reinterpret_cast<AM_MEDIA_TYPE*>(CoTaskMemAlloc(
     51           sizeof(AM_MEDIA_TYPE)));
     52       if (!type) {
     53         FreeAllocatedMediaTypes(types_fetched, types);
     54         return E_OUTOFMEMORY;
     55       }
     56       ZeroMemory(type, sizeof(AM_MEDIA_TYPE));
     57 
     58       // Allocate a VIDEOINFOHEADER and connect it to the AM_MEDIA_TYPE.
     59       type->cbFormat = sizeof(VIDEOINFOHEADER);
     60       BYTE *format = reinterpret_cast<BYTE*>(CoTaskMemAlloc(
     61           sizeof(VIDEOINFOHEADER)));
     62       if (!format) {
     63         CoTaskMemFree(type);
     64         FreeAllocatedMediaTypes(types_fetched, types);
     65         return E_OUTOFMEMORY;
     66       }
     67       type->pbFormat = format;
     68       // Get the media type from the pin.
     69       if (pin_->GetValidMediaType(index_++, type)) {
     70         types[types_fetched++] = type;
     71       } else {
     72         CoTaskMemFree(format);
     73         CoTaskMemFree(type);
     74         break;
     75       }
     76     }
     77 
     78     if (fetched)
     79       *fetched = types_fetched;
     80 
     81     return types_fetched == count ? S_OK : S_FALSE;
     82   }
     83 
     84   STDMETHOD(Skip)(ULONG count) {
     85     index_ += count;
     86     return S_OK;
     87   }
     88 
     89   STDMETHOD(Reset)() {
     90     index_ = 0;
     91     return S_OK;
     92   }
     93 
     94   STDMETHOD(Clone)(IEnumMediaTypes** clone) {
     95     TypeEnumerator* type_enum = new TypeEnumerator(pin_);
     96     if (!type_enum)
     97       return E_OUTOFMEMORY;
     98     type_enum->AddRef();
     99     type_enum->index_ = index_;
    100     *clone = type_enum;
    101     return S_OK;
    102   }
    103 
    104  private:
    105   void FreeAllocatedMediaTypes(ULONG allocated, AM_MEDIA_TYPE** types) {
    106     for (ULONG i = 0; i < allocated; ++i) {
    107       CoTaskMemFree(types[i]->pbFormat);
    108       CoTaskMemFree(types[i]);
    109     }
    110   }
    111 
    112   scoped_refptr<PinBase> pin_;
    113   int index_;
    114 };
    115 
    116 PinBase::PinBase(IBaseFilter* owner)
    117     : owner_(owner) {
    118   memset(&current_media_type_, 0, sizeof(current_media_type_));
    119 }
    120 
    121 PinBase::~PinBase() {
    122 }
    123 
    124 void PinBase::SetOwner(IBaseFilter* owner) {
    125   owner_ = owner;
    126 }
    127 
    128 // Called on an output pin to and establish a
    129 //   connection.
    130 STDMETHODIMP PinBase::Connect(IPin* receive_pin,
    131                               const AM_MEDIA_TYPE* media_type) {
    132   if (!receive_pin || !media_type)
    133     return E_POINTER;
    134 
    135   current_media_type_ = *media_type;
    136   receive_pin->AddRef();
    137   connected_pin_.Attach(receive_pin);
    138   HRESULT hr = receive_pin->ReceiveConnection(this, media_type);
    139 
    140   return hr;
    141 }
    142 
    143 // Called from an output pin on an input pin to and establish a
    144 // connection.
    145 STDMETHODIMP PinBase::ReceiveConnection(IPin* connector,
    146                                         const AM_MEDIA_TYPE* media_type) {
    147   if (!IsMediaTypeValid(media_type))
    148     return VFW_E_TYPE_NOT_ACCEPTED;
    149 
    150   current_media_type_ = *media_type;
    151   connector->AddRef();
    152   connected_pin_.Attach(connector);
    153   return S_OK;
    154 }
    155 
    156 STDMETHODIMP PinBase::Disconnect() {
    157   if (!connected_pin_)
    158     return S_FALSE;
    159 
    160   connected_pin_.Release();
    161   return S_OK;
    162 }
    163 
    164 STDMETHODIMP PinBase::ConnectedTo(IPin** pin) {
    165   *pin = connected_pin_;
    166   if (!connected_pin_)
    167     return VFW_E_NOT_CONNECTED;
    168 
    169   connected_pin_.get()->AddRef();
    170   return S_OK;
    171 }
    172 
    173 STDMETHODIMP PinBase::ConnectionMediaType(AM_MEDIA_TYPE* media_type) {
    174   if (!connected_pin_)
    175     return VFW_E_NOT_CONNECTED;
    176   *media_type = current_media_type_;
    177   return S_OK;
    178 }
    179 
    180 STDMETHODIMP PinBase::QueryPinInfo(PIN_INFO* info) {
    181   info->dir = PINDIR_INPUT;
    182   info->pFilter = owner_;
    183   if (owner_)
    184     owner_->AddRef();
    185   info->achName[0] = L'\0';
    186 
    187   return S_OK;
    188 }
    189 
    190 STDMETHODIMP PinBase::QueryDirection(PIN_DIRECTION* pin_dir) {
    191   *pin_dir = PINDIR_INPUT;
    192   return S_OK;
    193 }
    194 
    195 STDMETHODIMP PinBase::QueryId(LPWSTR* id) {
    196   NOTREACHED();
    197   return E_OUTOFMEMORY;
    198 }
    199 
    200 STDMETHODIMP PinBase::QueryAccept(const AM_MEDIA_TYPE* media_type) {
    201   return S_FALSE;
    202 }
    203 
    204 STDMETHODIMP PinBase::EnumMediaTypes(IEnumMediaTypes** types) {
    205   *types = new TypeEnumerator(this);
    206   (*types)->AddRef();
    207   return S_OK;
    208 }
    209 
    210 STDMETHODIMP PinBase::QueryInternalConnections(IPin** pins, ULONG* no_pins) {
    211   return E_NOTIMPL;
    212 }
    213 
    214 STDMETHODIMP PinBase::EndOfStream() {
    215   return S_OK;
    216 }
    217 
    218 STDMETHODIMP PinBase::BeginFlush() {
    219   return S_OK;
    220 }
    221 
    222 STDMETHODIMP PinBase::EndFlush() {
    223   return S_OK;
    224 }
    225 
    226 STDMETHODIMP PinBase::NewSegment(REFERENCE_TIME start,
    227                                  REFERENCE_TIME stop,
    228                                  double rate) {
    229   NOTREACHED();
    230   return E_NOTIMPL;
    231 }
    232 
    233 // Inherited from IMemInputPin.
    234 STDMETHODIMP PinBase::GetAllocator(IMemAllocator** allocator) {
    235   return VFW_E_NO_ALLOCATOR;
    236 }
    237 
    238 STDMETHODIMP PinBase::NotifyAllocator(IMemAllocator* allocator,
    239                                       BOOL read_only) {
    240   return S_OK;
    241 }
    242 
    243 STDMETHODIMP PinBase::GetAllocatorRequirements(
    244     ALLOCATOR_PROPERTIES* properties) {
    245   return E_NOTIMPL;
    246 }
    247 
    248 STDMETHODIMP PinBase::ReceiveMultiple(IMediaSample** samples,
    249                                       long sample_count,
    250                                       long* processed) {
    251   NOTREACHED();
    252   return VFW_E_INVALIDMEDIATYPE;
    253 }
    254 
    255 STDMETHODIMP PinBase::ReceiveCanBlock() {
    256   return S_FALSE;
    257 }
    258 
    259 // Inherited from IUnknown.
    260 STDMETHODIMP PinBase::QueryInterface(REFIID id, void** object_ptr) {
    261   if (id == IID_IPin || id == IID_IUnknown) {
    262     *object_ptr = static_cast<IPin*>(this);
    263   } else if (id == IID_IMemInputPin) {
    264     *object_ptr = static_cast<IMemInputPin*>(this);
    265   } else {
    266     return E_NOINTERFACE;
    267   }
    268   AddRef();
    269   return S_OK;
    270 }
    271 
    272 STDMETHODIMP_(ULONG) PinBase::AddRef() {
    273   base::RefCounted<PinBase>::AddRef();
    274   return 1;
    275 }
    276 
    277 STDMETHODIMP_(ULONG) PinBase::Release() {
    278   base::RefCounted<PinBase>::Release();
    279   return 1;
    280 }
    281 
    282 }  // namespace media
    283