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     type_enum->AddRef();
     97     type_enum->index_ = index_;
     98     *clone = type_enum;
     99     return S_OK;
    100   }
    101 
    102  private:
    103   void FreeAllocatedMediaTypes(ULONG allocated, AM_MEDIA_TYPE** types) {
    104     for (ULONG i = 0; i < allocated; ++i) {
    105       CoTaskMemFree(types[i]->pbFormat);
    106       CoTaskMemFree(types[i]);
    107     }
    108   }
    109 
    110   scoped_refptr<PinBase> pin_;
    111   int index_;
    112 };
    113 
    114 PinBase::PinBase(IBaseFilter* owner)
    115     : owner_(owner) {
    116   memset(&current_media_type_, 0, sizeof(current_media_type_));
    117 }
    118 
    119 PinBase::~PinBase() {
    120 }
    121 
    122 void PinBase::SetOwner(IBaseFilter* owner) {
    123   owner_ = owner;
    124 }
    125 
    126 // Called on an output pin to and establish a
    127 //   connection.
    128 STDMETHODIMP PinBase::Connect(IPin* receive_pin,
    129                               const AM_MEDIA_TYPE* media_type) {
    130   if (!receive_pin || !media_type)
    131     return E_POINTER;
    132 
    133   current_media_type_ = *media_type;
    134   receive_pin->AddRef();
    135   connected_pin_.Attach(receive_pin);
    136   HRESULT hr = receive_pin->ReceiveConnection(this, media_type);
    137 
    138   return hr;
    139 }
    140 
    141 // Called from an output pin on an input pin to and establish a
    142 // connection.
    143 STDMETHODIMP PinBase::ReceiveConnection(IPin* connector,
    144                                         const AM_MEDIA_TYPE* media_type) {
    145   if (!IsMediaTypeValid(media_type))
    146     return VFW_E_TYPE_NOT_ACCEPTED;
    147 
    148   current_media_type_ = *media_type;
    149   connector->AddRef();
    150   connected_pin_.Attach(connector);
    151   return S_OK;
    152 }
    153 
    154 STDMETHODIMP PinBase::Disconnect() {
    155   if (!connected_pin_)
    156     return S_FALSE;
    157 
    158   connected_pin_.Release();
    159   return S_OK;
    160 }
    161 
    162 STDMETHODIMP PinBase::ConnectedTo(IPin** pin) {
    163   *pin = connected_pin_;
    164   if (!connected_pin_)
    165     return VFW_E_NOT_CONNECTED;
    166 
    167   connected_pin_.get()->AddRef();
    168   return S_OK;
    169 }
    170 
    171 STDMETHODIMP PinBase::ConnectionMediaType(AM_MEDIA_TYPE* media_type) {
    172   if (!connected_pin_)
    173     return VFW_E_NOT_CONNECTED;
    174   *media_type = current_media_type_;
    175   return S_OK;
    176 }
    177 
    178 STDMETHODIMP PinBase::QueryPinInfo(PIN_INFO* info) {
    179   info->dir = PINDIR_INPUT;
    180   info->pFilter = owner_;
    181   if (owner_)
    182     owner_->AddRef();
    183   info->achName[0] = L'\0';
    184 
    185   return S_OK;
    186 }
    187 
    188 STDMETHODIMP PinBase::QueryDirection(PIN_DIRECTION* pin_dir) {
    189   *pin_dir = PINDIR_INPUT;
    190   return S_OK;
    191 }
    192 
    193 STDMETHODIMP PinBase::QueryId(LPWSTR* id) {
    194   NOTREACHED();
    195   return E_OUTOFMEMORY;
    196 }
    197 
    198 STDMETHODIMP PinBase::QueryAccept(const AM_MEDIA_TYPE* media_type) {
    199   return S_FALSE;
    200 }
    201 
    202 STDMETHODIMP PinBase::EnumMediaTypes(IEnumMediaTypes** types) {
    203   *types = new TypeEnumerator(this);
    204   (*types)->AddRef();
    205   return S_OK;
    206 }
    207 
    208 STDMETHODIMP PinBase::QueryInternalConnections(IPin** pins, ULONG* no_pins) {
    209   return E_NOTIMPL;
    210 }
    211 
    212 STDMETHODIMP PinBase::EndOfStream() {
    213   return S_OK;
    214 }
    215 
    216 STDMETHODIMP PinBase::BeginFlush() {
    217   return S_OK;
    218 }
    219 
    220 STDMETHODIMP PinBase::EndFlush() {
    221   return S_OK;
    222 }
    223 
    224 STDMETHODIMP PinBase::NewSegment(REFERENCE_TIME start,
    225                                  REFERENCE_TIME stop,
    226                                  double rate) {
    227   NOTREACHED();
    228   return E_NOTIMPL;
    229 }
    230 
    231 // Inherited from IMemInputPin.
    232 STDMETHODIMP PinBase::GetAllocator(IMemAllocator** allocator) {
    233   return VFW_E_NO_ALLOCATOR;
    234 }
    235 
    236 STDMETHODIMP PinBase::NotifyAllocator(IMemAllocator* allocator,
    237                                       BOOL read_only) {
    238   return S_OK;
    239 }
    240 
    241 STDMETHODIMP PinBase::GetAllocatorRequirements(
    242     ALLOCATOR_PROPERTIES* properties) {
    243   return E_NOTIMPL;
    244 }
    245 
    246 STDMETHODIMP PinBase::ReceiveMultiple(IMediaSample** samples,
    247                                       long sample_count,
    248                                       long* processed) {
    249   DCHECK(samples);
    250 
    251   HRESULT hr = S_OK;
    252   *processed = 0;
    253   while (sample_count--) {
    254     hr = Receive(samples[*processed]);
    255     // S_FALSE means don't send any more.
    256     if (hr != S_OK)
    257       break;
    258     ++(*processed);
    259   }
    260   return hr;
    261 }
    262 
    263 STDMETHODIMP PinBase::ReceiveCanBlock() {
    264   return S_FALSE;
    265 }
    266 
    267 // Inherited from IUnknown.
    268 STDMETHODIMP PinBase::QueryInterface(REFIID id, void** object_ptr) {
    269   if (id == IID_IPin || id == IID_IUnknown) {
    270     *object_ptr = static_cast<IPin*>(this);
    271   } else if (id == IID_IMemInputPin) {
    272     *object_ptr = static_cast<IMemInputPin*>(this);
    273   } else {
    274     return E_NOINTERFACE;
    275   }
    276   AddRef();
    277   return S_OK;
    278 }
    279 
    280 STDMETHODIMP_(ULONG) PinBase::AddRef() {
    281   base::RefCounted<PinBase>::AddRef();
    282   return 1;
    283 }
    284 
    285 STDMETHODIMP_(ULONG) PinBase::Release() {
    286   base::RefCounted<PinBase>::Release();
    287   return 1;
    288 }
    289 
    290 }  // namespace media
    291