Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / media / video / capture / win / pin_base_win.cc
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(&current_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