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/capture/video/win/pin_base_win.h"
6
7 #include "base/logging.h"
8
9 namespace media {
10
11 // Implement IEnumPins.
12 class TypeEnumerator final : public IEnumMediaTypes,
13 public base::RefCounted<TypeEnumerator> {
14 public:
TypeEnumerator(PinBase * pin)15 explicit TypeEnumerator(PinBase* pin) : pin_(pin), index_(0) {}
16
17 // Implement from IUnknown.
QueryInterface(REFIID iid,void ** object_ptr)18 IFACEMETHODIMP QueryInterface(REFIID iid, void** object_ptr) override {
19 if (iid == IID_IEnumMediaTypes || iid == IID_IUnknown) {
20 AddRef();
21 *object_ptr = static_cast<IEnumMediaTypes*>(this);
22 return S_OK;
23 }
24 return E_NOINTERFACE;
25 }
26
AddRef()27 IFACEMETHODIMP_(ULONG) AddRef() override {
28 base::RefCounted<TypeEnumerator>::AddRef();
29 return 1;
30 }
31
Release()32 IFACEMETHODIMP_(ULONG) Release() override {
33 base::RefCounted<TypeEnumerator>::Release();
34 return 1;
35 }
36
37 // Implement IEnumMediaTypes.
Next(ULONG count,AM_MEDIA_TYPE ** types,ULONG * fetched)38 IFACEMETHODIMP Next(ULONG count,
39 AM_MEDIA_TYPE** types,
40 ULONG* fetched) override {
41 ULONG types_fetched = 0;
42
43 while (types_fetched < count) {
44 // Allocate AM_MEDIA_TYPE that we will store the media type in.
45 AM_MEDIA_TYPE* type = reinterpret_cast<AM_MEDIA_TYPE*>(
46 CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)));
47 if (!type) {
48 FreeAllocatedMediaTypes(types_fetched, types);
49 return E_OUTOFMEMORY;
50 }
51 ZeroMemory(type, sizeof(AM_MEDIA_TYPE));
52
53 // Allocate a VIDEOINFOHEADER and connect it to the AM_MEDIA_TYPE.
54 type->cbFormat = sizeof(VIDEOINFOHEADER);
55 BYTE* format =
56 reinterpret_cast<BYTE*>(CoTaskMemAlloc(sizeof(VIDEOINFOHEADER)));
57 if (!format) {
58 CoTaskMemFree(type);
59 FreeAllocatedMediaTypes(types_fetched, types);
60 return E_OUTOFMEMORY;
61 }
62 type->pbFormat = format;
63 // Get the media type from the pin.
64 if (pin_->GetValidMediaType(index_++, type)) {
65 types[types_fetched++] = type;
66 } else {
67 CoTaskMemFree(format);
68 CoTaskMemFree(type);
69 break;
70 }
71 }
72
73 if (fetched)
74 *fetched = types_fetched;
75
76 return types_fetched == count ? S_OK : S_FALSE;
77 }
78
Skip(ULONG count)79 IFACEMETHODIMP Skip(ULONG count) override {
80 index_ += count;
81 return S_OK;
82 }
83
Reset()84 IFACEMETHODIMP Reset() override {
85 index_ = 0;
86 return S_OK;
87 }
88
Clone(IEnumMediaTypes ** clone)89 IFACEMETHODIMP Clone(IEnumMediaTypes** clone) override {
90 TypeEnumerator* type_enum = new TypeEnumerator(pin_.get());
91 type_enum->AddRef();
92 type_enum->index_ = index_;
93 *clone = type_enum;
94 return S_OK;
95 }
96
97 private:
98 friend class base::RefCounted<TypeEnumerator>;
~TypeEnumerator()99 ~TypeEnumerator() {}
100
FreeAllocatedMediaTypes(ULONG allocated,AM_MEDIA_TYPE ** types)101 void FreeAllocatedMediaTypes(ULONG allocated, AM_MEDIA_TYPE** types) {
102 for (ULONG i = 0; i < allocated; ++i) {
103 CoTaskMemFree(types[i]->pbFormat);
104 CoTaskMemFree(types[i]);
105 }
106 }
107
108 scoped_refptr<PinBase> pin_;
109 int index_;
110 };
111
PinBase(IBaseFilter * owner)112 PinBase::PinBase(IBaseFilter* owner) : owner_(owner) {
113 memset(¤t_media_type_, 0, sizeof(current_media_type_));
114 }
115
SetOwner(IBaseFilter * owner)116 void PinBase::SetOwner(IBaseFilter* owner) {
117 owner_ = owner;
118 }
119
120 // Called on an output pin to and establish a
121 // connection.
Connect(IPin * receive_pin,const AM_MEDIA_TYPE * media_type)122 HRESULT PinBase::Connect(IPin* receive_pin, const AM_MEDIA_TYPE* media_type) {
123 if (!receive_pin || !media_type)
124 return E_POINTER;
125
126 current_media_type_ = *media_type;
127 receive_pin->AddRef();
128 connected_pin_.Attach(receive_pin);
129 HRESULT hr = receive_pin->ReceiveConnection(this, media_type);
130
131 return hr;
132 }
133
134 // Called from an output pin on an input pin to and establish a
135 // connection.
ReceiveConnection(IPin * connector,const AM_MEDIA_TYPE * media_type)136 HRESULT PinBase::ReceiveConnection(IPin* connector,
137 const AM_MEDIA_TYPE* media_type) {
138 if (!IsMediaTypeValid(media_type))
139 return VFW_E_TYPE_NOT_ACCEPTED;
140
141 current_media_type_ = *media_type;
142 connector->AddRef();
143 connected_pin_.Attach(connector);
144 return S_OK;
145 }
146
Disconnect()147 HRESULT PinBase::Disconnect() {
148 if (!connected_pin_.Get())
149 return S_FALSE;
150
151 connected_pin_.Reset();
152 return S_OK;
153 }
154
ConnectedTo(IPin ** pin)155 HRESULT PinBase::ConnectedTo(IPin** pin) {
156 *pin = connected_pin_.Get();
157 if (!connected_pin_.Get())
158 return VFW_E_NOT_CONNECTED;
159
160 connected_pin_.Get()->AddRef();
161 return S_OK;
162 }
163
ConnectionMediaType(AM_MEDIA_TYPE * media_type)164 HRESULT PinBase::ConnectionMediaType(AM_MEDIA_TYPE* media_type) {
165 if (!connected_pin_.Get())
166 return VFW_E_NOT_CONNECTED;
167 *media_type = current_media_type_;
168 return S_OK;
169 }
170
QueryPinInfo(PIN_INFO * info)171 HRESULT PinBase::QueryPinInfo(PIN_INFO* info) {
172 info->dir = PINDIR_INPUT;
173 info->pFilter = owner_;
174 if (owner_)
175 owner_->AddRef();
176 info->achName[0] = L'\0';
177
178 return S_OK;
179 }
180
QueryDirection(PIN_DIRECTION * pin_dir)181 HRESULT PinBase::QueryDirection(PIN_DIRECTION* pin_dir) {
182 *pin_dir = PINDIR_INPUT;
183 return S_OK;
184 }
185
QueryId(LPWSTR * id)186 HRESULT PinBase::QueryId(LPWSTR* id) {
187 NOTREACHED();
188 return E_OUTOFMEMORY;
189 }
190
QueryAccept(const AM_MEDIA_TYPE * media_type)191 HRESULT PinBase::QueryAccept(const AM_MEDIA_TYPE* media_type) {
192 return S_FALSE;
193 }
194
EnumMediaTypes(IEnumMediaTypes ** types)195 HRESULT PinBase::EnumMediaTypes(IEnumMediaTypes** types) {
196 *types = new TypeEnumerator(this);
197 (*types)->AddRef();
198 return S_OK;
199 }
200
QueryInternalConnections(IPin ** pins,ULONG * no_pins)201 HRESULT PinBase::QueryInternalConnections(IPin** pins, ULONG* no_pins) {
202 return E_NOTIMPL;
203 }
204
EndOfStream()205 HRESULT PinBase::EndOfStream() {
206 return S_OK;
207 }
208
BeginFlush()209 HRESULT PinBase::BeginFlush() {
210 return S_OK;
211 }
212
EndFlush()213 HRESULT PinBase::EndFlush() {
214 return S_OK;
215 }
216
NewSegment(REFERENCE_TIME start,REFERENCE_TIME stop,double rate)217 HRESULT PinBase::NewSegment(REFERENCE_TIME start,
218 REFERENCE_TIME stop,
219 double rate) {
220 NOTREACHED();
221 return E_NOTIMPL;
222 }
223
224 // Inherited from IMemInputPin.
GetAllocator(IMemAllocator ** allocator)225 HRESULT PinBase::GetAllocator(IMemAllocator** allocator) {
226 return VFW_E_NO_ALLOCATOR;
227 }
228
NotifyAllocator(IMemAllocator * allocator,BOOL read_only)229 HRESULT PinBase::NotifyAllocator(IMemAllocator* allocator, BOOL read_only) {
230 return S_OK;
231 }
232
GetAllocatorRequirements(ALLOCATOR_PROPERTIES * properties)233 HRESULT PinBase::GetAllocatorRequirements(ALLOCATOR_PROPERTIES* properties) {
234 return E_NOTIMPL;
235 }
236
ReceiveMultiple(IMediaSample ** samples,long sample_count,long * processed)237 HRESULT PinBase::ReceiveMultiple(IMediaSample** samples,
238 long sample_count,
239 long* processed) {
240 DCHECK(samples);
241
242 HRESULT hr = S_OK;
243 *processed = 0;
244 while (sample_count--) {
245 hr = Receive(samples[*processed]);
246 // S_FALSE means don't send any more.
247 if (hr != S_OK)
248 break;
249 ++(*processed);
250 }
251 return hr;
252 }
253
ReceiveCanBlock()254 HRESULT PinBase::ReceiveCanBlock() {
255 return S_FALSE;
256 }
257
258 // Inherited from IUnknown.
QueryInterface(REFIID id,void ** object_ptr)259 HRESULT PinBase::QueryInterface(REFIID id, void** object_ptr) {
260 if (id == IID_IPin || id == IID_IUnknown) {
261 *object_ptr = static_cast<IPin*>(this);
262 } else if (id == IID_IMemInputPin) {
263 *object_ptr = static_cast<IMemInputPin*>(this);
264 } else {
265 return E_NOINTERFACE;
266 }
267 AddRef();
268 return S_OK;
269 }
270
AddRef()271 ULONG PinBase::AddRef() {
272 base::RefCounted<PinBase>::AddRef();
273 return 1;
274 }
275
Release()276 ULONG PinBase::Release() {
277 base::RefCounted<PinBase>::Release();
278 return 1;
279 }
280
~PinBase()281 PinBase::~PinBase() {
282 }
283
284 } // namespace media
285