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