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:
TypeEnumerator(PinBase * pin)16 explicit TypeEnumerator(PinBase* pin)
17 : pin_(pin),
18 index_(0) {
19 }
20
~TypeEnumerator()21 ~TypeEnumerator() {
22 }
23
24 // Implement from IUnknown.
STDMETHOD(QueryInterface)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
STDMETHOD_(ULONG,AddRef)34 STDMETHOD_(ULONG, AddRef)() {
35 base::RefCounted<TypeEnumerator>::AddRef();
36 return 1;
37 }
38
STDMETHOD_(ULONG,Release)39 STDMETHOD_(ULONG, Release)() {
40 base::RefCounted<TypeEnumerator>::Release();
41 return 1;
42 }
43
44 // Implement IEnumMediaTypes.
STDMETHOD(Next)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
STDMETHOD(Skip)84 STDMETHOD(Skip)(ULONG count) {
85 index_ += count;
86 return S_OK;
87 }
88
STDMETHOD(Reset)89 STDMETHOD(Reset)() {
90 index_ = 0;
91 return S_OK;
92 }
93
STDMETHOD(Clone)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:
FreeAllocatedMediaTypes(ULONG allocated,AM_MEDIA_TYPE ** types)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
PinBase(IBaseFilter * owner)114 PinBase::PinBase(IBaseFilter* owner)
115 : owner_(owner) {
116 memset(¤t_media_type_, 0, sizeof(current_media_type_));
117 }
118
~PinBase()119 PinBase::~PinBase() {
120 }
121
SetOwner(IBaseFilter * owner)122 void PinBase::SetOwner(IBaseFilter* owner) {
123 owner_ = owner;
124 }
125
126 // Called on an output pin to and establish a
127 // connection.
Connect(IPin * receive_pin,const AM_MEDIA_TYPE * media_type)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.
ReceiveConnection(IPin * connector,const AM_MEDIA_TYPE * media_type)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
Disconnect()154 STDMETHODIMP PinBase::Disconnect() {
155 if (!connected_pin_)
156 return S_FALSE;
157
158 connected_pin_.Release();
159 return S_OK;
160 }
161
ConnectedTo(IPin ** pin)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
ConnectionMediaType(AM_MEDIA_TYPE * media_type)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
QueryPinInfo(PIN_INFO * info)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
QueryDirection(PIN_DIRECTION * pin_dir)188 STDMETHODIMP PinBase::QueryDirection(PIN_DIRECTION* pin_dir) {
189 *pin_dir = PINDIR_INPUT;
190 return S_OK;
191 }
192
QueryId(LPWSTR * id)193 STDMETHODIMP PinBase::QueryId(LPWSTR* id) {
194 NOTREACHED();
195 return E_OUTOFMEMORY;
196 }
197
QueryAccept(const AM_MEDIA_TYPE * media_type)198 STDMETHODIMP PinBase::QueryAccept(const AM_MEDIA_TYPE* media_type) {
199 return S_FALSE;
200 }
201
EnumMediaTypes(IEnumMediaTypes ** types)202 STDMETHODIMP PinBase::EnumMediaTypes(IEnumMediaTypes** types) {
203 *types = new TypeEnumerator(this);
204 (*types)->AddRef();
205 return S_OK;
206 }
207
QueryInternalConnections(IPin ** pins,ULONG * no_pins)208 STDMETHODIMP PinBase::QueryInternalConnections(IPin** pins, ULONG* no_pins) {
209 return E_NOTIMPL;
210 }
211
EndOfStream()212 STDMETHODIMP PinBase::EndOfStream() {
213 return S_OK;
214 }
215
BeginFlush()216 STDMETHODIMP PinBase::BeginFlush() {
217 return S_OK;
218 }
219
EndFlush()220 STDMETHODIMP PinBase::EndFlush() {
221 return S_OK;
222 }
223
NewSegment(REFERENCE_TIME start,REFERENCE_TIME stop,double rate)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.
GetAllocator(IMemAllocator ** allocator)232 STDMETHODIMP PinBase::GetAllocator(IMemAllocator** allocator) {
233 return VFW_E_NO_ALLOCATOR;
234 }
235
NotifyAllocator(IMemAllocator * allocator,BOOL read_only)236 STDMETHODIMP PinBase::NotifyAllocator(IMemAllocator* allocator,
237 BOOL read_only) {
238 return S_OK;
239 }
240
GetAllocatorRequirements(ALLOCATOR_PROPERTIES * properties)241 STDMETHODIMP PinBase::GetAllocatorRequirements(
242 ALLOCATOR_PROPERTIES* properties) {
243 return E_NOTIMPL;
244 }
245
ReceiveMultiple(IMediaSample ** samples,long sample_count,long * processed)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
ReceiveCanBlock()263 STDMETHODIMP PinBase::ReceiveCanBlock() {
264 return S_FALSE;
265 }
266
267 // Inherited from IUnknown.
QueryInterface(REFIID id,void ** object_ptr)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
STDMETHODIMP_(ULONG)280 STDMETHODIMP_(ULONG) PinBase::AddRef() {
281 base::RefCounted<PinBase>::AddRef();
282 return 1;
283 }
284
STDMETHODIMP_(ULONG)285 STDMETHODIMP_(ULONG) PinBase::Release() {
286 base::RefCounted<PinBase>::Release();
287 return 1;
288 }
289
290 } // namespace media
291