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(&current_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