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 9namespace media { 10 11// Implement IEnumPins. 12class 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 114PinBase::PinBase(IBaseFilter* owner) 115 : owner_(owner) { 116 memset(¤t_media_type_, 0, sizeof(current_media_type_)); 117} 118 119PinBase::~PinBase() { 120} 121 122void PinBase::SetOwner(IBaseFilter* owner) { 123 owner_ = owner; 124} 125 126// Called on an output pin to and establish a 127// connection. 128STDMETHODIMP 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. 143STDMETHODIMP 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 154STDMETHODIMP PinBase::Disconnect() { 155 if (!connected_pin_) 156 return S_FALSE; 157 158 connected_pin_.Release(); 159 return S_OK; 160} 161 162STDMETHODIMP 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 171STDMETHODIMP 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 178STDMETHODIMP 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 188STDMETHODIMP PinBase::QueryDirection(PIN_DIRECTION* pin_dir) { 189 *pin_dir = PINDIR_INPUT; 190 return S_OK; 191} 192 193STDMETHODIMP PinBase::QueryId(LPWSTR* id) { 194 NOTREACHED(); 195 return E_OUTOFMEMORY; 196} 197 198STDMETHODIMP PinBase::QueryAccept(const AM_MEDIA_TYPE* media_type) { 199 return S_FALSE; 200} 201 202STDMETHODIMP PinBase::EnumMediaTypes(IEnumMediaTypes** types) { 203 *types = new TypeEnumerator(this); 204 (*types)->AddRef(); 205 return S_OK; 206} 207 208STDMETHODIMP PinBase::QueryInternalConnections(IPin** pins, ULONG* no_pins) { 209 return E_NOTIMPL; 210} 211 212STDMETHODIMP PinBase::EndOfStream() { 213 return S_OK; 214} 215 216STDMETHODIMP PinBase::BeginFlush() { 217 return S_OK; 218} 219 220STDMETHODIMP PinBase::EndFlush() { 221 return S_OK; 222} 223 224STDMETHODIMP PinBase::NewSegment(REFERENCE_TIME start, 225 REFERENCE_TIME stop, 226 double rate) { 227 NOTREACHED(); 228 return E_NOTIMPL; 229} 230 231// Inherited from IMemInputPin. 232STDMETHODIMP PinBase::GetAllocator(IMemAllocator** allocator) { 233 return VFW_E_NO_ALLOCATOR; 234} 235 236STDMETHODIMP PinBase::NotifyAllocator(IMemAllocator* allocator, 237 BOOL read_only) { 238 return S_OK; 239} 240 241STDMETHODIMP PinBase::GetAllocatorRequirements( 242 ALLOCATOR_PROPERTIES* properties) { 243 return E_NOTIMPL; 244} 245 246STDMETHODIMP 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 263STDMETHODIMP PinBase::ReceiveCanBlock() { 264 return S_FALSE; 265} 266 267// Inherited from IUnknown. 268STDMETHODIMP 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 280STDMETHODIMP_(ULONG) PinBase::AddRef() { 281 base::RefCounted<PinBase>::AddRef(); 282 return 1; 283} 284 285STDMETHODIMP_(ULONG) PinBase::Release() { 286 base::RefCounted<PinBase>::Release(); 287 return 1; 288} 289 290} // namespace media 291