Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / capture / video / win / pin_base_win.cc
blob3f521948e201f566e74cedc5df8b3b2feb7ab67f
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.
5 #include "media/capture/video/win/pin_base_win.h"
7 #include "base/logging.h"
9 namespace media {
11 // Implement IEnumPins.
12 class TypeEnumerator final : public IEnumMediaTypes,
13 public base::RefCounted<TypeEnumerator> {
14 public:
15 explicit TypeEnumerator(PinBase* pin) : pin_(pin), index_(0) {}
17 // Implement from IUnknown.
18 STDMETHOD(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;
24 return E_NOINTERFACE;
27 STDMETHOD_(ULONG, AddRef)() override {
28 base::RefCounted<TypeEnumerator>::AddRef();
29 return 1;
32 STDMETHOD_(ULONG, Release)() override {
33 base::RefCounted<TypeEnumerator>::Release();
34 return 1;
37 // Implement IEnumMediaTypes.
38 STDMETHOD(Next)(ULONG count, AM_MEDIA_TYPE** types, ULONG* fetched) override {
39 ULONG types_fetched = 0;
41 while (types_fetched < count) {
42 // Allocate AM_MEDIA_TYPE that we will store the media type in.
43 AM_MEDIA_TYPE* type = reinterpret_cast<AM_MEDIA_TYPE*>(
44 CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)));
45 if (!type) {
46 FreeAllocatedMediaTypes(types_fetched, types);
47 return E_OUTOFMEMORY;
49 ZeroMemory(type, sizeof(AM_MEDIA_TYPE));
51 // Allocate a VIDEOINFOHEADER and connect it to the AM_MEDIA_TYPE.
52 type->cbFormat = sizeof(VIDEOINFOHEADER);
53 BYTE* format =
54 reinterpret_cast<BYTE*>(CoTaskMemAlloc(sizeof(VIDEOINFOHEADER)));
55 if (!format) {
56 CoTaskMemFree(type);
57 FreeAllocatedMediaTypes(types_fetched, types);
58 return E_OUTOFMEMORY;
60 type->pbFormat = format;
61 // Get the media type from the pin.
62 if (pin_->GetValidMediaType(index_++, type)) {
63 types[types_fetched++] = type;
64 } else {
65 CoTaskMemFree(format);
66 CoTaskMemFree(type);
67 break;
71 if (fetched)
72 *fetched = types_fetched;
74 return types_fetched == count ? S_OK : S_FALSE;
77 STDMETHOD(Skip)(ULONG count) override {
78 index_ += count;
79 return S_OK;
82 STDMETHOD(Reset)() override {
83 index_ = 0;
84 return S_OK;
87 STDMETHOD(Clone)(IEnumMediaTypes** clone) override {
88 TypeEnumerator* type_enum = new TypeEnumerator(pin_.get());
89 type_enum->AddRef();
90 type_enum->index_ = index_;
91 *clone = type_enum;
92 return S_OK;
95 private:
96 friend class base::RefCounted<TypeEnumerator>;
97 ~TypeEnumerator() {}
99 void FreeAllocatedMediaTypes(ULONG allocated, AM_MEDIA_TYPE** types) {
100 for (ULONG i = 0; i < allocated; ++i) {
101 CoTaskMemFree(types[i]->pbFormat);
102 CoTaskMemFree(types[i]);
106 scoped_refptr<PinBase> pin_;
107 int index_;
110 PinBase::PinBase(IBaseFilter* owner) : owner_(owner) {
111 memset(&current_media_type_, 0, sizeof(current_media_type_));
114 void PinBase::SetOwner(IBaseFilter* owner) {
115 owner_ = owner;
118 // Called on an output pin to and establish a
119 // connection.
120 STDMETHODIMP PinBase::Connect(IPin* receive_pin,
121 const AM_MEDIA_TYPE* media_type) {
122 if (!receive_pin || !media_type)
123 return E_POINTER;
125 current_media_type_ = *media_type;
126 receive_pin->AddRef();
127 connected_pin_.Attach(receive_pin);
128 HRESULT hr = receive_pin->ReceiveConnection(this, media_type);
130 return hr;
133 // Called from an output pin on an input pin to and establish a
134 // connection.
135 STDMETHODIMP PinBase::ReceiveConnection(IPin* connector,
136 const AM_MEDIA_TYPE* media_type) {
137 if (!IsMediaTypeValid(media_type))
138 return VFW_E_TYPE_NOT_ACCEPTED;
140 current_media_type_ = *media_type;
141 connector->AddRef();
142 connected_pin_.Attach(connector);
143 return S_OK;
146 STDMETHODIMP PinBase::Disconnect() {
147 if (!connected_pin_.get())
148 return S_FALSE;
150 connected_pin_.Release();
151 return S_OK;
154 STDMETHODIMP PinBase::ConnectedTo(IPin** pin) {
155 *pin = connected_pin_.get();
156 if (!connected_pin_.get())
157 return VFW_E_NOT_CONNECTED;
159 connected_pin_.get()->AddRef();
160 return S_OK;
163 STDMETHODIMP PinBase::ConnectionMediaType(AM_MEDIA_TYPE* media_type) {
164 if (!connected_pin_.get())
165 return VFW_E_NOT_CONNECTED;
166 *media_type = current_media_type_;
167 return S_OK;
170 STDMETHODIMP PinBase::QueryPinInfo(PIN_INFO* info) {
171 info->dir = PINDIR_INPUT;
172 info->pFilter = owner_;
173 if (owner_)
174 owner_->AddRef();
175 info->achName[0] = L'\0';
177 return S_OK;
180 STDMETHODIMP PinBase::QueryDirection(PIN_DIRECTION* pin_dir) {
181 *pin_dir = PINDIR_INPUT;
182 return S_OK;
185 STDMETHODIMP PinBase::QueryId(LPWSTR* id) {
186 NOTREACHED();
187 return E_OUTOFMEMORY;
190 STDMETHODIMP PinBase::QueryAccept(const AM_MEDIA_TYPE* media_type) {
191 return S_FALSE;
194 STDMETHODIMP PinBase::EnumMediaTypes(IEnumMediaTypes** types) {
195 *types = new TypeEnumerator(this);
196 (*types)->AddRef();
197 return S_OK;
200 STDMETHODIMP PinBase::QueryInternalConnections(IPin** pins, ULONG* no_pins) {
201 return E_NOTIMPL;
204 STDMETHODIMP PinBase::EndOfStream() {
205 return S_OK;
208 STDMETHODIMP PinBase::BeginFlush() {
209 return S_OK;
212 STDMETHODIMP PinBase::EndFlush() {
213 return S_OK;
216 STDMETHODIMP PinBase::NewSegment(REFERENCE_TIME start,
217 REFERENCE_TIME stop,
218 double rate) {
219 NOTREACHED();
220 return E_NOTIMPL;
223 // Inherited from IMemInputPin.
224 STDMETHODIMP PinBase::GetAllocator(IMemAllocator** allocator) {
225 return VFW_E_NO_ALLOCATOR;
228 STDMETHODIMP PinBase::NotifyAllocator(IMemAllocator* allocator,
229 BOOL read_only) {
230 return S_OK;
233 STDMETHODIMP PinBase::GetAllocatorRequirements(
234 ALLOCATOR_PROPERTIES* properties) {
235 return E_NOTIMPL;
238 STDMETHODIMP PinBase::ReceiveMultiple(IMediaSample** samples,
239 long sample_count,
240 long* processed) {
241 DCHECK(samples);
243 HRESULT hr = S_OK;
244 *processed = 0;
245 while (sample_count--) {
246 hr = Receive(samples[*processed]);
247 // S_FALSE means don't send any more.
248 if (hr != S_OK)
249 break;
250 ++(*processed);
252 return hr;
255 STDMETHODIMP PinBase::ReceiveCanBlock() {
256 return S_FALSE;
259 // Inherited from IUnknown.
260 STDMETHODIMP PinBase::QueryInterface(REFIID id, void** object_ptr) {
261 if (id == IID_IPin || id == IID_IUnknown) {
262 *object_ptr = static_cast<IPin*>(this);
263 } else if (id == IID_IMemInputPin) {
264 *object_ptr = static_cast<IMemInputPin*>(this);
265 } else {
266 return E_NOINTERFACE;
268 AddRef();
269 return S_OK;
272 STDMETHODIMP_(ULONG) PinBase::AddRef() {
273 base::RefCounted<PinBase>::AddRef();
274 return 1;
277 STDMETHODIMP_(ULONG) PinBase::Release() {
278 base::RefCounted<PinBase>::Release();
279 return 1;
282 PinBase::~PinBase() {
285 } // namespace media