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"
11 // Implement IEnumPins.
12 class TypeEnumerator final
: public IEnumMediaTypes
,
13 public base::RefCounted
<TypeEnumerator
> {
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
) {
21 *object_ptr
= static_cast<IEnumMediaTypes
*>(this);
27 STDMETHOD_(ULONG
, AddRef
)() override
{
28 base::RefCounted
<TypeEnumerator
>::AddRef();
32 STDMETHOD_(ULONG
, Release
)() override
{
33 base::RefCounted
<TypeEnumerator
>::Release();
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
)));
46 FreeAllocatedMediaTypes(types_fetched
, types
);
49 ZeroMemory(type
, sizeof(AM_MEDIA_TYPE
));
51 // Allocate a VIDEOINFOHEADER and connect it to the AM_MEDIA_TYPE.
52 type
->cbFormat
= sizeof(VIDEOINFOHEADER
);
54 reinterpret_cast<BYTE
*>(CoTaskMemAlloc(sizeof(VIDEOINFOHEADER
)));
57 FreeAllocatedMediaTypes(types_fetched
, types
);
60 type
->pbFormat
= format
;
61 // Get the media type from the pin.
62 if (pin_
->GetValidMediaType(index_
++, type
)) {
63 types
[types_fetched
++] = type
;
65 CoTaskMemFree(format
);
72 *fetched
= types_fetched
;
74 return types_fetched
== count
? S_OK
: S_FALSE
;
77 STDMETHOD(Skip
)(ULONG count
) override
{
82 STDMETHOD(Reset
)() override
{
87 STDMETHOD(Clone
)(IEnumMediaTypes
** clone
) override
{
88 TypeEnumerator
* type_enum
= new TypeEnumerator(pin_
.get());
90 type_enum
->index_
= index_
;
96 friend class base::RefCounted
<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_
;
110 PinBase::PinBase(IBaseFilter
* owner
) : owner_(owner
) {
111 memset(¤t_media_type_
, 0, sizeof(current_media_type_
));
114 void PinBase::SetOwner(IBaseFilter
* owner
) {
118 // Called on an output pin to and establish a
120 STDMETHODIMP
PinBase::Connect(IPin
* receive_pin
,
121 const AM_MEDIA_TYPE
* media_type
) {
122 if (!receive_pin
|| !media_type
)
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
);
133 // Called from an output pin on an input pin to and establish a
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
;
142 connected_pin_
.Attach(connector
);
146 STDMETHODIMP
PinBase::Disconnect() {
147 if (!connected_pin_
.get())
150 connected_pin_
.Release();
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();
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_
;
170 STDMETHODIMP
PinBase::QueryPinInfo(PIN_INFO
* info
) {
171 info
->dir
= PINDIR_INPUT
;
172 info
->pFilter
= owner_
;
175 info
->achName
[0] = L
'\0';
180 STDMETHODIMP
PinBase::QueryDirection(PIN_DIRECTION
* pin_dir
) {
181 *pin_dir
= PINDIR_INPUT
;
185 STDMETHODIMP
PinBase::QueryId(LPWSTR
* id
) {
187 return E_OUTOFMEMORY
;
190 STDMETHODIMP
PinBase::QueryAccept(const AM_MEDIA_TYPE
* media_type
) {
194 STDMETHODIMP
PinBase::EnumMediaTypes(IEnumMediaTypes
** types
) {
195 *types
= new TypeEnumerator(this);
200 STDMETHODIMP
PinBase::QueryInternalConnections(IPin
** pins
, ULONG
* no_pins
) {
204 STDMETHODIMP
PinBase::EndOfStream() {
208 STDMETHODIMP
PinBase::BeginFlush() {
212 STDMETHODIMP
PinBase::EndFlush() {
216 STDMETHODIMP
PinBase::NewSegment(REFERENCE_TIME start
,
223 // Inherited from IMemInputPin.
224 STDMETHODIMP
PinBase::GetAllocator(IMemAllocator
** allocator
) {
225 return VFW_E_NO_ALLOCATOR
;
228 STDMETHODIMP
PinBase::NotifyAllocator(IMemAllocator
* allocator
,
233 STDMETHODIMP
PinBase::GetAllocatorRequirements(
234 ALLOCATOR_PROPERTIES
* properties
) {
238 STDMETHODIMP
PinBase::ReceiveMultiple(IMediaSample
** samples
,
245 while (sample_count
--) {
246 hr
= Receive(samples
[*processed
]);
247 // S_FALSE means don't send any more.
255 STDMETHODIMP
PinBase::ReceiveCanBlock() {
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);
266 return E_NOINTERFACE
;
272 STDMETHODIMP_(ULONG
) PinBase::AddRef() {
273 base::RefCounted
<PinBase
>::AddRef();
277 STDMETHODIMP_(ULONG
) PinBase::Release() {
278 base::RefCounted
<PinBase
>::Release();
282 PinBase::~PinBase() {