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(¤t_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