зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1552755 - Update video_capture/windows code to tip of webrtc.org; r=ng
This updates just video_capture/windows to the tip of webrtc.org, from commit 8581877121f58435d683c2a39a73e72e5dcd558a. This removes the locking which was leading to the deadlock in Bug 1552755. It also removes the reliance upon the DirectShow example code which lead to our local implementations of BaseFilter, BaseInputPin, BasePin, and MediaType. These can now be removed. Differential Revision: https://phabricator.services.mozilla.com/D33336 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
6d792169fe
Коммит
3a63433a17
|
@ -149,8 +149,6 @@ if (!build_with_chromium) {
|
|||
sources = [
|
||||
"windows/device_info_ds.cc",
|
||||
"windows/device_info_ds.h",
|
||||
"windows/device_info_mf.cc",
|
||||
"windows/device_info_mf.h",
|
||||
"windows/help_functions_ds.cc",
|
||||
"windows/help_functions_ds.h",
|
||||
"windows/sink_filter_ds.cc",
|
||||
|
@ -158,22 +156,10 @@ if (!build_with_chromium) {
|
|||
"windows/video_capture_ds.cc",
|
||||
"windows/video_capture_ds.h",
|
||||
"windows/video_capture_factory_windows.cc",
|
||||
"windows/video_capture_mf.cc",
|
||||
"windows/video_capture_mf.h",
|
||||
]
|
||||
|
||||
libs = [ "Strmiids.lib" ]
|
||||
|
||||
if (build_with_mozilla) {
|
||||
sources += [
|
||||
"windows/BaseFilter.cpp",
|
||||
"windows/BaseInputPin.cpp",
|
||||
"windows/BasePin.cpp",
|
||||
"windows/MediaType.cpp",
|
||||
]
|
||||
} else {
|
||||
deps += [ "//third_party/winsdk_samples" ]
|
||||
}
|
||||
}
|
||||
if (is_ios || is_mac) {
|
||||
deps += [ ":video_capture_internal_impl_objc" ]
|
||||
|
|
|
@ -1,478 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <assert.h>
|
||||
#include "BaseFilter.h"
|
||||
#include "BasePin.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
#define NS_IF_ADDREF(expr) \
|
||||
if (expr) { \
|
||||
(expr)->AddRef(); \
|
||||
}
|
||||
|
||||
#define NS_IF_RELEASE(expr) \
|
||||
if (expr) { \
|
||||
(expr)->Release(); \
|
||||
}
|
||||
|
||||
// Used by BaseFilter to enumerate pins on a DirectShow filter.
|
||||
// If the number of pins on the filter changes while an EnumPins
|
||||
// is enumerating pins on a filter, methods start failing with
|
||||
// return value VFW_E_ENUM_OUT_OF_SYNC. Really only an issue when
|
||||
// doing dynamic filter reconnections.
|
||||
//
|
||||
// Implements:
|
||||
// * IEnumPins
|
||||
// * IUnknown
|
||||
//
|
||||
class DECLSPEC_UUID("0e9924bd-1cb8-48ad-ba31-2fb831b162be")
|
||||
EnumPins : public IEnumPins
|
||||
{
|
||||
public:
|
||||
|
||||
explicit EnumPins(BaseFilter* aFilter)
|
||||
: mFilter(aFilter)
|
||||
, mRefCnt(0)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
explicit EnumPins(EnumPins* aEnumPins)
|
||||
: mFilter(aEnumPins->mFilter)
|
||||
, mNumPins(aEnumPins->mNumPins)
|
||||
, mPinIdx(aEnumPins->mPinIdx)
|
||||
, mRefCnt(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual ~EnumPins() {}
|
||||
|
||||
STDMETHODIMP QueryInterface(REFIID aIId, void **aInterface)
|
||||
{
|
||||
if (!aInterface) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (aIId == IID_IEnumPins) {
|
||||
*aInterface = static_cast<IEnumPins*>(this);
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
STDMETHODIMP_(ULONG) AddRef()
|
||||
{
|
||||
return ::InterlockedIncrement(&mRefCnt);
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) Release()
|
||||
{
|
||||
unsigned long newRefCnt = ::InterlockedDecrement(&mRefCnt);
|
||||
|
||||
if (!newRefCnt) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
return newRefCnt;
|
||||
}
|
||||
|
||||
// IEnumPins methods.
|
||||
STDMETHODIMP Next(ULONG aNumPins,
|
||||
IPin** aPinArray,
|
||||
ULONG* aNumFetched)
|
||||
{
|
||||
if (!aPinArray)
|
||||
return E_POINTER;
|
||||
|
||||
if (!aNumFetched && aNumPins != 1)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (IsOutOfSync())
|
||||
return VFW_E_ENUM_OUT_OF_SYNC;
|
||||
|
||||
unsigned int numFetched = 0;
|
||||
|
||||
while (numFetched < aNumPins && mPinIdx < mNumPins) {
|
||||
IPinPtr pin = mFilter->GetPin(mPinIdx);
|
||||
aPinArray[numFetched] = pin;
|
||||
assert(aPinArray[numFetched] != NULL);
|
||||
if (!aPinArray[numFetched]) {
|
||||
// Failure, release all pins.
|
||||
for (unsigned int i=0; i<numFetched; i++) {
|
||||
NS_IF_RELEASE(aPinArray[i]);
|
||||
}
|
||||
return VFW_E_ENUM_OUT_OF_SYNC;
|
||||
}
|
||||
NS_IF_ADDREF(aPinArray[numFetched]);
|
||||
mPinIdx++;
|
||||
numFetched++;
|
||||
}
|
||||
|
||||
if (aNumFetched)
|
||||
*aNumFetched = numFetched;
|
||||
|
||||
|
||||
return (aNumPins == numFetched) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP Skip(ULONG aNumPins)
|
||||
{
|
||||
if (IsOutOfSync())
|
||||
return VFW_E_ENUM_OUT_OF_SYNC;
|
||||
|
||||
if ((mPinIdx + aNumPins) > mNumPins)
|
||||
return S_FALSE;
|
||||
|
||||
mPinIdx += aNumPins;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Reset()
|
||||
{
|
||||
mNumPins = mFilter->GetPinCount();
|
||||
mPinIdx = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Clone(IEnumPins** aEnum)
|
||||
{
|
||||
if (!aEnum)
|
||||
return E_POINTER;
|
||||
|
||||
if (IsOutOfSync())
|
||||
return VFW_E_ENUM_OUT_OF_SYNC;
|
||||
|
||||
EnumPins *p = new EnumPins(this);
|
||||
|
||||
*aEnum = p;
|
||||
NS_IF_ADDREF(p);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
private:
|
||||
|
||||
bool IsOutOfSync() {
|
||||
return mNumPins != mFilter->GetPinCount();
|
||||
}
|
||||
|
||||
BaseFilterPtr mFilter;
|
||||
unsigned int mNumPins;
|
||||
unsigned int mPinIdx;
|
||||
unsigned long mRefCnt;
|
||||
};
|
||||
|
||||
_COM_SMARTPTR_TYPEDEF(IMediaEventSink, __uuidof(IMediaEventSink));
|
||||
|
||||
BaseFilter::BaseFilter(const wchar_t* aName,
|
||||
REFCLSID aClsID)
|
||||
: mClsId(aClsID)
|
||||
, mState(State_Stopped)
|
||||
, mLock("BaseFilter::mLock")
|
||||
, mRefCnt(0)
|
||||
{
|
||||
mName = aName;
|
||||
assert(mName == aName);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP BaseFilter::QueryInterface(REFIID riid,
|
||||
void** aInterface)
|
||||
{
|
||||
if (!aInterface) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (riid == IID_IBaseFilter || riid == IID_IUnknown) {
|
||||
*aInterface = static_cast<IBaseFilter*>(this);
|
||||
} else if (riid == IID_IMediaFilter) {
|
||||
*aInterface = static_cast<IMediaFilter*>(this);
|
||||
} else if (riid == IID_IPersist) {
|
||||
*aInterface = static_cast<IPersist*>(this);
|
||||
} else {
|
||||
*aInterface = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BaseFilter::GetClassID(CLSID* aClsId)
|
||||
{
|
||||
if (!aClsId)
|
||||
return E_POINTER;
|
||||
*aClsId = mClsId;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BaseFilter::GetState(DWORD, FILTER_STATE* aState)
|
||||
{
|
||||
if (!aState)
|
||||
return E_POINTER;
|
||||
*aState = mState;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BaseFilter::SetSyncSource(IReferenceClock* aClock)
|
||||
{
|
||||
CriticalSectionAutoEnter monitor(mLock);
|
||||
mClock = aClock;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BaseFilter::GetSyncSource(IReferenceClock** aClock)
|
||||
{
|
||||
if (!aClock)
|
||||
return E_POINTER;
|
||||
|
||||
CriticalSectionAutoEnter monitor(mLock);
|
||||
|
||||
if (mClock) {
|
||||
// returning an interface... addref it...
|
||||
mClock->AddRef();
|
||||
}
|
||||
*aClock = mClock;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Stop deactivates any active, connected pins on this filter.
|
||||
STDMETHODIMP
|
||||
BaseFilter::Stop()
|
||||
{
|
||||
CriticalSectionAutoEnter monitor(mLock);
|
||||
HRESULT retval = S_OK;
|
||||
|
||||
if (mState == State_Stopped)
|
||||
return S_OK;
|
||||
|
||||
int numPins = GetPinCount();
|
||||
for (int i = 0; i < numPins; i++) {
|
||||
|
||||
BasePin* pin = GetPin(i);
|
||||
if (NULL == pin) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pin->IsConnected()) {
|
||||
HRESULT hr = pin->Inactive();
|
||||
if (FAILED(hr) && SUCCEEDED(retval)) {
|
||||
retval = hr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mState = State_Stopped;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
// Moves the filter into the paused state. If the graph is stopped, notify all
|
||||
// the connected pins that they're active.
|
||||
STDMETHODIMP
|
||||
BaseFilter::Pause()
|
||||
{
|
||||
CriticalSectionAutoEnter monitor(mLock);
|
||||
|
||||
if (mState == State_Stopped) {
|
||||
int numPins = GetPinCount();
|
||||
for (int i = 0; i < numPins; i++) {
|
||||
|
||||
BasePin* pin = GetPin(i);
|
||||
if (NULL == pin) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (pin->IsConnected()) {
|
||||
HRESULT hr = pin->Active();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mState = State_Paused;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// Moves the filter into a running state. aStartTime is the offset to be added
|
||||
// to the samples' stream time in order for the samples to appear in stream time.
|
||||
STDMETHODIMP
|
||||
BaseFilter::Run(REFERENCE_TIME aStartTime)
|
||||
{
|
||||
CriticalSectionAutoEnter monitor(mLock);
|
||||
|
||||
mStartTime = aStartTime;
|
||||
|
||||
if (mState == State_Running) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// First pause the filter if it's stopped.
|
||||
if (mState == State_Stopped) {
|
||||
HRESULT hr = Pause();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
// Start all connected pins.
|
||||
int numPins = GetPinCount();
|
||||
for (int i = 0; i < numPins; i++) {
|
||||
|
||||
BasePin* pin = GetPin(i);
|
||||
assert(pin != NULL);
|
||||
if (!pin) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pin->IsConnected()) {
|
||||
HRESULT hr = pin->Run(aStartTime);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mState = State_Running;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
BaseFilter::EnumPins(IEnumPins** aEnum)
|
||||
{
|
||||
if (!aEnum)
|
||||
return E_POINTER;
|
||||
|
||||
*aEnum = new mozilla::media::EnumPins(this);
|
||||
if (!(*aEnum))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
NS_IF_ADDREF(*aEnum);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BaseFilter::FindPin(LPCWSTR aId,
|
||||
IPin** aPin)
|
||||
{
|
||||
if (!aPin)
|
||||
return E_POINTER;
|
||||
|
||||
*aPin = NULL;
|
||||
|
||||
CriticalSectionAutoEnter monitor(mLock);
|
||||
int numPins = GetPinCount();
|
||||
for (int i = 0; i < numPins; i++) {
|
||||
BasePin* pin = GetPin(i);
|
||||
if (NULL == pin) {
|
||||
assert(pin != NULL);
|
||||
return VFW_E_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!pin->Name().compare(aId)) {
|
||||
// Found a pin with a matching name, AddRef() and return it.
|
||||
*aPin = pin;
|
||||
NS_IF_ADDREF(pin);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return VFW_E_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BaseFilter::QueryFilterInfo(FILTER_INFO* aInfo)
|
||||
{
|
||||
if (!aInfo)
|
||||
return E_POINTER;
|
||||
|
||||
if (!mName.empty()) {
|
||||
StringCchCopyW(aInfo->achName, NUMELMS(aInfo->achName), mName.data());
|
||||
} else {
|
||||
aInfo->achName[0] = L'\0';
|
||||
}
|
||||
aInfo->pGraph = mGraph;
|
||||
NS_IF_ADDREF(mGraph);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BaseFilter::JoinFilterGraph(IFilterGraph* aGraph,
|
||||
LPCWSTR aName)
|
||||
{
|
||||
CriticalSectionAutoEnter monitor(mLock);
|
||||
mGraph = aGraph;
|
||||
IMediaEventSinkPtr sink = mGraph;
|
||||
// Store weak ref to event sink. Graph holds strong reg to us, so if we hold
|
||||
// strong ref to its event sink we'll create a cycle.
|
||||
mEventSink = sink;
|
||||
if (aGraph) {
|
||||
mName = aName;
|
||||
} else {
|
||||
mName.resize(0);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
BaseFilter::NotifyEvent(long aEventCode,
|
||||
LONG_PTR aEventParam1,
|
||||
LONG_PTR aEventParam2)
|
||||
{
|
||||
IMediaEventSink* sink = mEventSink;
|
||||
if (sink) {
|
||||
if (EC_COMPLETE == aEventCode) {
|
||||
aEventParam2 = (LONG_PTR)(static_cast<IBaseFilter*>(this));
|
||||
}
|
||||
return sink->Notify(aEventCode, aEventParam1, aEventParam2);
|
||||
}
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
BaseFilter::AddRef()
|
||||
{
|
||||
return ::InterlockedIncrement(&mRefCnt);
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
BaseFilter::Release()
|
||||
{
|
||||
unsigned long newRefCnt = ::InterlockedDecrement(&mRefCnt);
|
||||
|
||||
if (!newRefCnt) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
return newRefCnt;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_BASEFILTER_H_
|
||||
#define WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_BASEFILTER_H_
|
||||
|
||||
#include "dshow.h"
|
||||
#include <comdef.h>
|
||||
#include "DShowTools.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
_COM_SMARTPTR_TYPEDEF(IReferenceClock, __uuidof(IReferenceClock));
|
||||
|
||||
class BasePin;
|
||||
|
||||
// Base class for a data source filter which supplies media streams
|
||||
// for rendering in DirectShow.
|
||||
//
|
||||
// Implements:
|
||||
// * IBaseFilter
|
||||
// * IUnknown
|
||||
//
|
||||
|
||||
class DECLSPEC_UUID("4debd354-b0c6-44ab-93cf-49f64ed36ab8")
|
||||
BaseFilter : public IBaseFilter
|
||||
{
|
||||
friend class BasePin;
|
||||
public:
|
||||
// The maximum number of buffers that this samples allocator will request.
|
||||
// Allocators are negotiated between filters. The size of the buffers is
|
||||
// determined in subclasses. We must have enough buffers so that we can read
|
||||
// up to the first keyframe before we run out of buffers.
|
||||
static const unsigned int sMaxNumBuffers = 256;
|
||||
|
||||
// Zero all fields on alloc.
|
||||
void* operator new(size_t sz) throw() {
|
||||
void* rv = ::operator new(sz);
|
||||
if (rv) {
|
||||
memset(rv, 0, sz);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
void operator delete(void* ptr) {
|
||||
::operator delete(ptr);
|
||||
}
|
||||
|
||||
// |aName| is the debug name of the filter (shows up in GraphEdit).
|
||||
// |aClsID| is the clsid of the filter.
|
||||
BaseFilter(const wchar_t* aName, REFCLSID aClsID);
|
||||
|
||||
virtual ~BaseFilter() {}
|
||||
|
||||
STDMETHODIMP QueryInterface(REFIID aIId, void **aInterface);
|
||||
STDMETHODIMP_(ULONG) AddRef();
|
||||
STDMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IPersist
|
||||
STDMETHODIMP GetClassID(CLSID* aClsID);
|
||||
|
||||
// IMediaFilter methods.
|
||||
|
||||
// Retrieves the state of the filter (running, stopped, or paused).
|
||||
STDMETHODIMP GetState(DWORD aTimeout, FILTER_STATE* aState);
|
||||
|
||||
// Sets the reference clock for the filter or the filter graph.
|
||||
STDMETHODIMP SetSyncSource(IReferenceClock* aClock);
|
||||
|
||||
// Retrieves the current reference clock.
|
||||
STDMETHODIMP GetSyncSource(IReferenceClock** aClock);
|
||||
|
||||
// Stops the filter.
|
||||
STDMETHODIMP Stop();
|
||||
|
||||
// Pauses the filter.
|
||||
STDMETHODIMP Pause();
|
||||
|
||||
// Runs the filter.
|
||||
STDMETHODIMP Run(REFERENCE_TIME aStartTime);
|
||||
|
||||
// IBaseFilter methods.
|
||||
|
||||
// Enumerates the pins on this filter.
|
||||
STDMETHODIMP EnumPins(IEnumPins** aEnum);
|
||||
|
||||
// Retrieves the pin with the specified identifier.
|
||||
STDMETHODIMP FindPin(LPCWSTR aId, IPin** aPin);
|
||||
|
||||
// Retrieves information about the filter.
|
||||
STDMETHODIMP QueryFilterInfo(FILTER_INFO* aInfo);
|
||||
|
||||
// Notifies the filter that it has joined or left the filter graph.
|
||||
STDMETHODIMP JoinFilterGraph(IFilterGraph* aGraph, LPCWSTR aName);
|
||||
|
||||
// Retrieves a string containing vendor information.
|
||||
// Dfault implementation returns E_NOTIMPL.
|
||||
STDMETHODIMP QueryVendorInfo(LPWSTR* aVendorInfo) { return E_NOTIMPL; }
|
||||
|
||||
// Helper methods.
|
||||
HRESULT NotifyEvent(long aEventCode,
|
||||
LONG_PTR aEventParam1,
|
||||
LONG_PTR aEventParam2);
|
||||
|
||||
// Returns the number of pins on this filter. This must be implemented
|
||||
// in subclasses.
|
||||
virtual int GetPinCount() = 0;
|
||||
|
||||
// Returns the n'th pin. This must be implemented in subclasses.
|
||||
virtual BasePin* GetPin(int n) = 0;
|
||||
|
||||
// Called when the filter's graph is about to be paused.
|
||||
virtual void AboutToPause() { }
|
||||
|
||||
protected:
|
||||
// Current state, running, paused, etc.
|
||||
FILTER_STATE mState;
|
||||
|
||||
// Reference clock of the graph. This provides an monotonically incrementing
|
||||
// clock which the graph may use to timestamp frames.
|
||||
IReferenceClockPtr mClock;
|
||||
|
||||
// The offset of stream time to the reference clock.
|
||||
REFERENCE_TIME mStartTime;
|
||||
|
||||
// This filter's class ID.
|
||||
CLSID mClsId;
|
||||
|
||||
// Filter lock used for serialization.
|
||||
CriticalSection mLock;
|
||||
|
||||
// Graph to which this filter belongs. This must be a weak reference,
|
||||
// as the graphs holds a strong reference to each filter it contains.
|
||||
// This is set when the graph calls to JoinFilterGraph(), and unset
|
||||
// by a call to JoinFilterGraph(NULL) when the filter leaves the graph.
|
||||
IFilterGraph* mGraph;
|
||||
|
||||
// Event sink for notifications. This is QI'd of mGraph in JoinFilterGraph(),
|
||||
// and must be a weak reference for the same reasons as mGraph must.
|
||||
IMediaEventSink* mEventSink;
|
||||
|
||||
// Name assigned to this filter.
|
||||
std::wstring mName;
|
||||
|
||||
// IUnknown ref counting.
|
||||
unsigned long mRefCnt;
|
||||
};
|
||||
|
||||
// For mingw __uuidof support
|
||||
#ifdef __CRT_UUID_DECL
|
||||
}
|
||||
}
|
||||
__CRT_UUID_DECL(mozilla::media::BaseFilter, 0x4debd354,0xb0c6,0x44ab,0x93,0xcf,0x49,0xf6,0x4e,0xd3,0x6a,0xb8);
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
#endif
|
||||
|
||||
_COM_SMARTPTR_TYPEDEF(BaseFilter, __uuidof(BaseFilter));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,105 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <assert.h>
|
||||
#include "BaseInputPin.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
STDMETHODIMP
|
||||
BaseInputPin::QueryInterface(REFIID aIId, void **aInterface)
|
||||
{
|
||||
if (!aInterface) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (aIId == IID_IMemInputPin) {
|
||||
*aInterface = static_cast<IMemInputPin*>(this);
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return BasePin::QueryInterface(aIId, aInterface);
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
BaseInputPin::BeginFlush()
|
||||
{
|
||||
CriticalSectionAutoEnter lock(*mLock);
|
||||
assert(!mFlushing);
|
||||
mFlushing = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
BaseInputPin::EndFlush()
|
||||
{
|
||||
CriticalSectionAutoEnter lock(*mLock);
|
||||
assert(mFlushing);
|
||||
mFlushing = false;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
BaseInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES*)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
BaseInputPin::ReceiveCanBlock()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
BaseInputPin::Receive(IMediaSample* aSample)
|
||||
{
|
||||
if (mFlushing) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
BaseInputPin::ReceiveMultiple(IMediaSample **aSamples, long aSampleCount, long *aProcessedCount)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
*aProcessedCount = 0;
|
||||
while (aSampleCount-- > 0) {
|
||||
hr = Receive(aSamples[*aProcessedCount]);
|
||||
|
||||
// Refuse when S_FALSE
|
||||
if (hr != S_OK) {
|
||||
break;
|
||||
}
|
||||
(*aProcessedCount)++;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
BaseInputPin::GetAllocator(IMemAllocator **aAllocator)
|
||||
{
|
||||
// It appears DirectShow will create an allocator for us in this case.
|
||||
return VFW_E_NO_ALLOCATOR;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
BaseInputPin::NotifyAllocator(IMemAllocator *aAllocator, BOOL aReadOnly)
|
||||
{
|
||||
mAllocator = aAllocator;
|
||||
mReadOnly = aReadOnly;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_BASEINPUTPIN_H_
|
||||
#define WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_BASEINPUTPIN_H_
|
||||
|
||||
|
||||
#include "BasePin.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
_COM_SMARTPTR_TYPEDEF(IMemAllocator, __uuidof(IMemAllocator));
|
||||
|
||||
class BaseInputPin : public BasePin
|
||||
, public IMemInputPin
|
||||
{
|
||||
protected:
|
||||
BaseInputPin(
|
||||
const wchar_t* aObjectName,
|
||||
BaseFilter *aFilter,
|
||||
CriticalSection *aLock,
|
||||
HRESULT *aHR,
|
||||
const wchar_t* aName)
|
||||
: BasePin(aFilter, aLock, aName, PINDIR_INPUT)
|
||||
, mFlushing(false)
|
||||
, mReadOnly(false)
|
||||
{
|
||||
*aHR = S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP BeginFlush();
|
||||
STDMETHODIMP EndFlush();
|
||||
STDMETHODIMP QueryInterface(REFIID aIId, void **aInterface);
|
||||
STDMETHODIMP_(ULONG) AddRef() { return mFilter->AddRef(); }
|
||||
STDMETHODIMP_(ULONG) Release() { return mFilter->Release(); }
|
||||
|
||||
STDMETHODIMP GetAllocator(IMemAllocator **aAllocator);
|
||||
STDMETHODIMP NotifyAllocator(IMemAllocator *aAllocator, BOOL aReadOnly);
|
||||
STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES *aProps);
|
||||
STDMETHODIMP Receive(IMediaSample *aSample);
|
||||
STDMETHODIMP ReceiveMultiple(IMediaSample **aSamples, long aSampleCount, long *aProcessedCount);
|
||||
STDMETHODIMP ReceiveCanBlock();
|
||||
protected:
|
||||
bool mFlushing;
|
||||
bool mReadOnly;
|
||||
IMemAllocatorPtr mAllocator;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,656 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include "BasePin.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
// Implements IEnumMediaTypes for nsBasePin::EnumMediaTypes().
|
||||
// Does not support dynamic media types.
|
||||
//
|
||||
// Implements:
|
||||
// * IEnumMediaTypes
|
||||
// * IUnknown
|
||||
//
|
||||
class DECLSPEC_UUID("4de7a03c-6c3f-4314-949a-ee7e1ad05083")
|
||||
EnumMediaTypes
|
||||
: public IEnumMediaTypes
|
||||
{
|
||||
public:
|
||||
|
||||
explicit EnumMediaTypes(BasePin* aPin)
|
||||
: mPin(aPin)
|
||||
, mIndex(0)
|
||||
, mRefCnt(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit EnumMediaTypes(EnumMediaTypes* aEnum)
|
||||
: mPin(aEnum->mPin)
|
||||
, mIndex(aEnum->mIndex)
|
||||
, mRefCnt(0)
|
||||
{
|
||||
}
|
||||
|
||||
STDMETHODIMP QueryInterface(REFIID aIId, void **aInterface)
|
||||
{
|
||||
if (!aInterface) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (aIId == IID_IEnumMediaTypes) {
|
||||
*aInterface = static_cast<IEnumMediaTypes*>(this);
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
STDMETHODIMP_(ULONG) AddRef()
|
||||
{
|
||||
return ::InterlockedIncrement(&mRefCnt);
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) Release()
|
||||
{
|
||||
unsigned long newRefCnt = ::InterlockedDecrement(&mRefCnt);
|
||||
|
||||
if (!newRefCnt) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
return newRefCnt;
|
||||
}
|
||||
|
||||
// IEnumMediaTypes
|
||||
STDMETHODIMP Next(ULONG aCount,
|
||||
AM_MEDIA_TYPE ** aMediaTypes,
|
||||
ULONG * aNumFetched)
|
||||
{
|
||||
if (!aMediaTypes)
|
||||
return E_POINTER;
|
||||
|
||||
if (aNumFetched) {
|
||||
*aNumFetched = 0;
|
||||
} else if (aCount > 1) {
|
||||
// !aNumFetched && aCount>1, we can't report how many media types we read.
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
unsigned int numFetched = 0;
|
||||
while (numFetched < aCount) {
|
||||
// Get the media type
|
||||
MediaType mediaType;
|
||||
HRESULT hr = mPin->GetMediaType(mIndex++, &mediaType);
|
||||
if (hr != S_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Create a copy of media type on the free store.
|
||||
MediaType* m = new MediaType(mediaType);
|
||||
if (!m)
|
||||
return E_OUTOFMEMORY;
|
||||
aMediaTypes[numFetched] = m;
|
||||
if (!aMediaTypes[numFetched])
|
||||
break;
|
||||
|
||||
numFetched++;
|
||||
}
|
||||
|
||||
if (aNumFetched)
|
||||
*aNumFetched = numFetched;
|
||||
|
||||
return (numFetched == aCount) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP Skip(ULONG aCount)
|
||||
{
|
||||
if (aCount == 0)
|
||||
return S_OK;
|
||||
|
||||
// Advance the media type index by |aCount|.
|
||||
mIndex += aCount;
|
||||
|
||||
// See if the new index is *past* the end by querying for a media type.
|
||||
MediaType mediaType;
|
||||
HRESULT hr = mPin->GetMediaType(mIndex-1, &mediaType);
|
||||
|
||||
// Forget mediaTypes pointers, so nsMediaType destructor it won't release them.
|
||||
mediaType.Forget();
|
||||
|
||||
return (hr != S_OK) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP Reset()
|
||||
{
|
||||
mIndex = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Clone(IEnumMediaTypes **aClone)
|
||||
{
|
||||
if (!aClone)
|
||||
return E_POINTER;
|
||||
|
||||
EnumMediaTypes* e = new EnumMediaTypes(this);
|
||||
if (!e)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
e->AddRef();
|
||||
|
||||
*aClone = static_cast<IEnumMediaTypes*>(e);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Pin whose media types we are iterating.
|
||||
BasePinPtr mPin;
|
||||
|
||||
// Index of our "iterator" through mPin's media types.
|
||||
int mIndex;
|
||||
|
||||
unsigned long mRefCnt;
|
||||
|
||||
};
|
||||
_COM_SMARTPTR_TYPEDEF(IEnumMediaTypes, __uuidof(IEnumMediaTypes));
|
||||
|
||||
BasePin::BasePin(BaseFilter* aFilter,
|
||||
CriticalSection* aLock,
|
||||
const wchar_t* aName,
|
||||
PIN_DIRECTION aDirection)
|
||||
: mFilter(aFilter)
|
||||
, mLock(aLock)
|
||||
, mName(aName)
|
||||
, mDirection(aDirection)
|
||||
, mQualitySink(NULL)
|
||||
{
|
||||
assert(aFilter != NULL);
|
||||
assert(aLock != NULL);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::QueryInterface(REFIID aIID, void ** aInterface)
|
||||
{
|
||||
if (!aInterface) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (aIID == IID_IPin || aIID == IID_IUnknown) {
|
||||
*aInterface = static_cast<IPin*>(this);
|
||||
} else if (aIID == IID_IQualityControl) {
|
||||
*aInterface = static_cast<IQualityControl*>(this);
|
||||
} else {
|
||||
*aInterface = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::QueryPinInfo(PIN_INFO * aInfo)
|
||||
{
|
||||
if (!aInfo)
|
||||
return E_POINTER;
|
||||
|
||||
memset(aInfo, 0, sizeof(PIN_INFO));
|
||||
|
||||
aInfo->pFilter = mFilter;
|
||||
if (mFilter) {
|
||||
mFilter->AddRef();
|
||||
}
|
||||
|
||||
if (!mName.empty()) {
|
||||
// Copy at most (max_buffer_size - sizeof(WCHAR)). The -1 is there to
|
||||
// ensure we always have a null terminator.
|
||||
size_t len = std::min<size_t>(MAX_PIN_NAME - 1, mName.length()) * sizeof(WCHAR);
|
||||
memcpy(aInfo->achName, mName.data(), len);
|
||||
}
|
||||
|
||||
aInfo->dir = mDirection;
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::QueryDirection(PIN_DIRECTION * aPinDir)
|
||||
{
|
||||
if (!aPinDir)
|
||||
return E_POINTER;
|
||||
*aPinDir = mDirection;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::QueryId(LPWSTR * aId)
|
||||
{
|
||||
if (!aId)
|
||||
return E_POINTER;
|
||||
|
||||
*aId = NULL;
|
||||
|
||||
WCHAR* str = NULL;
|
||||
|
||||
// Length not including null-terminator.
|
||||
unsigned int sz = mName.length() * sizeof(WCHAR);
|
||||
|
||||
// Allocate memory for new string copy, plus 1 for null-terminator.
|
||||
str = (LPWSTR)CoTaskMemAlloc(sz + sizeof(WCHAR));
|
||||
if (!str)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
// Copy name.
|
||||
memcpy(str, mName.data(), sz);
|
||||
|
||||
// Set null-terminator.
|
||||
str[mName.length()] = 0;
|
||||
|
||||
*aId = str;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::EnumMediaTypes(IEnumMediaTypes **aEnum)
|
||||
{
|
||||
if (!aEnum)
|
||||
return E_POINTER;
|
||||
|
||||
*aEnum = new mozilla::media::EnumMediaTypes(this);
|
||||
|
||||
if (*aEnum == NULL)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
// Must addref, caller's responsibility to release.
|
||||
(*aEnum)->AddRef();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// Base class returns an error; we expect sub-classes to override this.
|
||||
HRESULT
|
||||
BasePin::GetMediaType(int, MediaType*)
|
||||
{
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::QueryAccept(const AM_MEDIA_TYPE *aMediaType)
|
||||
{
|
||||
if (!aMediaType)
|
||||
return E_POINTER;
|
||||
|
||||
// Defer to subclasses CheckMediaType() function. Map all errors to S_FALSE,
|
||||
// so that we match the spec for QueryAccept().
|
||||
|
||||
if (FAILED(CheckMediaType((MediaType*)aMediaType)))
|
||||
return S_FALSE;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
BasePin::Active(void)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
BasePin::Run(REFERENCE_TIME)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
BasePin::Inactive(void)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::EndOfStream(void)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::SetSink(IQualityControl* aQualitySink)
|
||||
{
|
||||
CriticalSectionAutoEnter monitor(*mLock);
|
||||
mQualitySink = aQualitySink;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::Notify(IBaseFilter *, Quality)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::NewSegment(REFERENCE_TIME aStartTime,
|
||||
REFERENCE_TIME aStopTime,
|
||||
double aRate)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
// This pin attempts to connect to |aPin| with media type |aMediaType|.
|
||||
// If |aMediaType| is fully specified, we must attempt to connect with
|
||||
// that, else we just enumerate our types, then the other pin's type and
|
||||
// try them, filtering them using |aMediaType| if it's paritally
|
||||
// specificed. Used by Connect().
|
||||
STDMETHODIMP
|
||||
BasePin::Connect(IPin * aPin,
|
||||
const AM_MEDIA_TYPE* aMediaType)
|
||||
{
|
||||
if (!aPin)
|
||||
return E_POINTER;
|
||||
|
||||
CriticalSectionAutoEnter monitor(*mLock);
|
||||
|
||||
if (IsConnected())
|
||||
return VFW_E_ALREADY_CONNECTED;
|
||||
|
||||
// Can't connect when filter is not stopped.
|
||||
if (!IsStopped())
|
||||
return VFW_E_NOT_STOPPED;
|
||||
|
||||
// Find a muatually acceptable media type. First try the media type
|
||||
// suggested, then try our media types, then the other pin's media types.
|
||||
|
||||
const MediaType* mediaType = reinterpret_cast<const MediaType*>(aMediaType);
|
||||
|
||||
if (aMediaType && !mediaType->IsPartiallySpecified()) {
|
||||
// Media type is supplied and not partially specified, we must try to
|
||||
// connect with that.
|
||||
return AttemptConnection(aPin, mediaType);
|
||||
}
|
||||
|
||||
// Try this pin's media types...
|
||||
IEnumMediaTypesPtr enumMediaTypes;
|
||||
HRESULT hr = EnumMediaTypes(&enumMediaTypes);
|
||||
assert(SUCCEEDED(hr));
|
||||
if (enumMediaTypes) {
|
||||
hr = TryMediaTypes(aPin, mediaType, enumMediaTypes);
|
||||
if (SUCCEEDED(hr))
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Can't connect with our media types, try other pins types...
|
||||
enumMediaTypes = NULL;
|
||||
hr = aPin->EnumMediaTypes(&enumMediaTypes);
|
||||
assert(SUCCEEDED(hr));
|
||||
if (enumMediaTypes) {
|
||||
hr = TryMediaTypes(aPin, mediaType, enumMediaTypes);
|
||||
if (SUCCEEDED(hr))
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Nothing connects.
|
||||
return VFW_E_NO_ACCEPTABLE_TYPES;
|
||||
}
|
||||
|
||||
|
||||
// Try the media types of |aEnum| when connecting to |aPin| with type limiter
|
||||
// of |aFilter|. If |aFilter| is specified, we will only attempt to connect
|
||||
// with media types from |aEnum| which partially match |aFilter|.
|
||||
HRESULT
|
||||
BasePin::TryMediaTypes(IPin *aPin,
|
||||
const MediaType *aFilter,
|
||||
IEnumMediaTypes *aEnum)
|
||||
{
|
||||
// Reset enumerator.
|
||||
HRESULT hr = aEnum->Reset();
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
while (true) {
|
||||
AM_MEDIA_TYPE* amt = NULL;
|
||||
ULONG mediaCount = 0;
|
||||
HRESULT hr = aEnum->Next(1, &amt, &mediaCount);
|
||||
if (hr != S_OK) // No more media types...
|
||||
return VFW_E_NO_ACCEPTABLE_TYPES;
|
||||
|
||||
assert(mediaCount == 1 && hr == S_OK);
|
||||
|
||||
MediaType* mediaType = reinterpret_cast<MediaType*>(amt);
|
||||
if (!aFilter || mediaType->MatchesPartial(aFilter)) {
|
||||
// Either there's no limiter, or we partially match it,
|
||||
// attempt connection.
|
||||
if (SUCCEEDED(AttemptConnection(aPin, mediaType)))
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Checks if this pin can connect to |aPin|. We expect sub classes to
|
||||
// override this method to support their own needs.
|
||||
HRESULT
|
||||
BasePin::CheckConnect(IPin* aPin)
|
||||
{
|
||||
PIN_DIRECTION otherPinsDirection;
|
||||
aPin->QueryDirection(&otherPinsDirection);
|
||||
|
||||
// Can't connect pins with same direction together...
|
||||
if (otherPinsDirection == mDirection) {
|
||||
return VFW_E_INVALID_DIRECTION;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// Called when we've made a connection to another pin. Returning failure
|
||||
// triggers the caller to break the connection. Subclasses may want to
|
||||
// override this.
|
||||
HRESULT
|
||||
BasePin::CompleteConnect(IPin *)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// Sets the media type of the connection.
|
||||
HRESULT
|
||||
BasePin::SetMediaType(const MediaType *aMediaType)
|
||||
{
|
||||
return mMediaType.Assign(aMediaType);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::QueryInternalConnections(IPin**, ULONG*)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
// This is called to release any resources needed for a connection.
|
||||
HRESULT
|
||||
BasePin::BreakConnect()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::Disconnect()
|
||||
{
|
||||
CriticalSectionAutoEnter monitor(*mLock);
|
||||
|
||||
// Can't disconnect a non-stopped filter.
|
||||
if (!IsStopped())
|
||||
return VFW_E_NOT_STOPPED;
|
||||
|
||||
if (!IsConnected())
|
||||
return S_FALSE;
|
||||
|
||||
HRESULT hr = BreakConnect();
|
||||
mConnectedPin = NULL;
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Attempt to connect this pin to |aPin| using given media type.
|
||||
HRESULT
|
||||
BasePin::AttemptConnection(IPin* aPin,
|
||||
const MediaType* aMediaType)
|
||||
{
|
||||
CriticalSectionAutoEnter monitor(*mLock);
|
||||
|
||||
// Ensure we can connect to the other pin. Gives subclasses a chance
|
||||
// to prevent connection.
|
||||
HRESULT hr = CheckConnect(aPin);
|
||||
if (FAILED(hr)) {
|
||||
BreakConnect();
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Ensure we can connect with this media type. This gives subclasses a
|
||||
// chance to abort the connection.
|
||||
hr = CheckMediaType(aMediaType);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = SetMediaType(aMediaType);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
// Ask the other pin if it will accept a connection with our media type.
|
||||
hr = aPin->ReceiveConnection(static_cast<IPin*>(this), aMediaType);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
// Looks good so far, give subclass one final chance to refuse connection...
|
||||
mConnectedPin = aPin;
|
||||
hr = CompleteConnect(aPin);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
// Subclass refused the connection, inform the other pin that we're
|
||||
// disconnecting, and break the connection.
|
||||
aPin->Disconnect();
|
||||
BreakConnect();
|
||||
mConnectedPin = NULL;
|
||||
mMediaType.Clear();
|
||||
return VFW_E_TYPE_NOT_ACCEPTED;
|
||||
}
|
||||
|
||||
// Otherwise, we're all good!
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::ReceiveConnection(IPin * aPin,
|
||||
const AM_MEDIA_TYPE *aMediaType)
|
||||
{
|
||||
if (!aPin)
|
||||
return E_POINTER;
|
||||
|
||||
if (!aMediaType)
|
||||
E_POINTER;
|
||||
|
||||
CriticalSectionAutoEnter monitor(*mLock);
|
||||
|
||||
if (IsConnected())
|
||||
return VFW_E_ALREADY_CONNECTED;
|
||||
|
||||
if (!IsStopped())
|
||||
return VFW_E_NOT_STOPPED;
|
||||
|
||||
HRESULT hr = CheckConnect(aPin);
|
||||
if (FAILED(hr)) {
|
||||
BreakConnect();
|
||||
return hr;
|
||||
}
|
||||
|
||||
// See if subclass supports the specified media type.
|
||||
const MediaType* mediaType = reinterpret_cast<const MediaType*>(aMediaType);
|
||||
hr = CheckMediaType(mediaType);
|
||||
if (FAILED(hr)) {
|
||||
BreakConnect();
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Supported, set it.
|
||||
hr = SetMediaType(mediaType);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
// Complete the connection.
|
||||
mConnectedPin = aPin;
|
||||
// Give the subclass one last chance to refuse the connection.
|
||||
hr = CompleteConnect(aPin);
|
||||
if (FAILED(hr)) {
|
||||
// Subclass refused connection, fail...
|
||||
mConnectedPin = NULL;
|
||||
BreakConnect();
|
||||
return hr;
|
||||
}
|
||||
|
||||
// It's all good, we're connected.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::ConnectedTo(IPin** aPin)
|
||||
{
|
||||
if (!aPin)
|
||||
return E_POINTER;
|
||||
|
||||
if (!IsConnected())
|
||||
return VFW_E_NOT_CONNECTED;
|
||||
|
||||
*aPin = mConnectedPin;
|
||||
(*aPin)->AddRef();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
BasePin::ConnectionMediaType(AM_MEDIA_TYPE *aMediaType)
|
||||
{
|
||||
if (!aMediaType)
|
||||
return E_POINTER;
|
||||
|
||||
CriticalSectionAutoEnter monitor(*mLock);
|
||||
|
||||
if (IsConnected()) {
|
||||
reinterpret_cast<MediaType*>(aMediaType)->Assign(&mMediaType);
|
||||
return S_OK;
|
||||
} else {
|
||||
memset(aMediaType, 0, sizeof(AM_MEDIA_TYPE));
|
||||
return VFW_E_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,215 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_BASEPIN_H_
|
||||
#define WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_BASEPIN_H_
|
||||
|
||||
|
||||
#include "BaseFilter.h"
|
||||
#include "MediaType.h"
|
||||
|
||||
#include "dshow.h"
|
||||
#include "strmif.h"
|
||||
#include <string>
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
_COM_SMARTPTR_TYPEDEF(IPin, __uuidof(IPin));
|
||||
|
||||
|
||||
// Base class for DirectShow filter pins.
|
||||
//
|
||||
// Implements:
|
||||
// * IPin
|
||||
// * IQualityControl
|
||||
// * IUnknown
|
||||
//
|
||||
class DECLSPEC_UUID("199669c6-672a-4130-b13e-57aa830eae55")
|
||||
BasePin
|
||||
: public IPin
|
||||
, public IQualityControl
|
||||
{
|
||||
public:
|
||||
|
||||
BasePin(BaseFilter* aFilter,
|
||||
CriticalSection* aLock,
|
||||
const wchar_t* aName,
|
||||
PIN_DIRECTION aDirection);
|
||||
|
||||
virtual ~BasePin() {}
|
||||
|
||||
// Reference count of the pin is actually stored on the owning filter.
|
||||
// So don't AddRef() the filter from the pin, else you'll create a cycle.
|
||||
STDMETHODIMP QueryInterface(REFIID aIId, void **aInterface);
|
||||
STDMETHODIMP_(ULONG) AddRef() { return mFilter->AddRef(); }
|
||||
STDMETHODIMP_(ULONG) Release() { return mFilter->Release(); }
|
||||
|
||||
// IPin overrides.
|
||||
|
||||
// Connects the pin to another pin. The pmt parameter can be NULL or a
|
||||
// partial media type.
|
||||
STDMETHODIMP Connect(IPin* aReceivePin,
|
||||
const AM_MEDIA_TYPE* aMediaType);
|
||||
|
||||
//Accepts a connection from another pin.
|
||||
STDMETHODIMP ReceiveConnection(IPin* aConnector,
|
||||
const AM_MEDIA_TYPE* aMediaType);
|
||||
|
||||
// Breaks the current pin connection.
|
||||
STDMETHODIMP Disconnect();
|
||||
|
||||
// Retrieves the pin connected to this pin.
|
||||
STDMETHODIMP ConnectedTo(IPin** aPin);
|
||||
|
||||
// Retrieves the media type for the current pin connection.
|
||||
STDMETHODIMP ConnectionMediaType(AM_MEDIA_TYPE* aMediaType);
|
||||
|
||||
// Retrieves information about the pin, such as the name, the owning filter,
|
||||
// and the direction.
|
||||
STDMETHODIMP QueryPinInfo(PIN_INFO* aInfo);
|
||||
|
||||
// Retrieves the direction of the pin (input or output).
|
||||
STDMETHODIMP QueryDirection(PIN_DIRECTION* aDirection);
|
||||
|
||||
// Retrieves the pin identifier.
|
||||
STDMETHODIMP QueryId(LPWSTR* Id);
|
||||
|
||||
// Determines whether the pin accepts a specified media type.
|
||||
STDMETHODIMP QueryAccept(const AM_MEDIA_TYPE* aMediaType);
|
||||
|
||||
// Enumerates the pin's preferred media types.
|
||||
STDMETHODIMP EnumMediaTypes(IEnumMediaTypes** aEnum);
|
||||
|
||||
// Retrieves the pins that are connected internally to this pin
|
||||
// (within the filter).
|
||||
STDMETHODIMP QueryInternalConnections(IPin** apPin,
|
||||
ULONG* aPin);
|
||||
|
||||
// Notifies the pin that no additional data is expected.
|
||||
STDMETHODIMP EndOfStream(void);
|
||||
|
||||
// IPin::BeginFlush() and IPin::EndFlush() are still pure virtual,
|
||||
// and must be implemented in a subclass.
|
||||
|
||||
// Notifies the pin that media samples received after this call
|
||||
// are grouped as a segment.
|
||||
STDMETHODIMP NewSegment(
|
||||
REFERENCE_TIME aStartTime,
|
||||
REFERENCE_TIME aStopTime,
|
||||
double aRate);
|
||||
|
||||
|
||||
|
||||
// IQualityControl overrides.
|
||||
|
||||
// Notifies the recipient that a quality change is requested.
|
||||
STDMETHODIMP Notify(IBaseFilter * aSender, Quality aQuality);
|
||||
|
||||
// Sets the IQualityControl object that will receive quality messages.
|
||||
STDMETHODIMP SetSink(IQualityControl* aQualitySink);
|
||||
|
||||
|
||||
|
||||
// Other methods.
|
||||
|
||||
// Sets the media type of the connection.
|
||||
virtual HRESULT SetMediaType(const MediaType *aMediaType);
|
||||
|
||||
// check if the pin can support this specific proposed type and format
|
||||
virtual HRESULT CheckMediaType(const MediaType *) = 0;
|
||||
|
||||
// This is called to release any resources needed for a connection.
|
||||
virtual HRESULT BreakConnect();
|
||||
|
||||
// Called when we've made a connection to another pin. Returning failure
|
||||
// triggers the caller to break the connection. Subclasses may want to
|
||||
// override this.
|
||||
virtual HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// Checks if this pin can connect to |aPin|. We expect sub classes to
|
||||
// override this method to support their own needs. Default implementation
|
||||
// simply checks that the directions of the pins do not match.
|
||||
virtual HRESULT CheckConnect(IPin *);
|
||||
|
||||
// Check if our filter is currently stopped
|
||||
BOOL IsStopped() {
|
||||
return mFilter->mState == State_Stopped;
|
||||
};
|
||||
|
||||
// Moves pin to active state (running or paused). Subclasses will
|
||||
// override to prepare to handle data.
|
||||
virtual HRESULT Active(void);
|
||||
|
||||
// Moves pin into inactive state (stopped). Releases resources associated
|
||||
// with handling data. Subclasses should override this.
|
||||
virtual HRESULT Inactive(void);
|
||||
|
||||
// Called when Run() is called on the parent filter. Subclasses may want to
|
||||
// override this.
|
||||
virtual HRESULT Run(REFERENCE_TIME aStartTime);
|
||||
|
||||
// Gets the supported media types for this pin.
|
||||
virtual HRESULT GetMediaType(int aIndex, MediaType *aMediaType);
|
||||
|
||||
// Access name.
|
||||
const std::wstring& Name() { return mName; };
|
||||
|
||||
bool IsConnected() { return mConnectedPin != NULL; }
|
||||
|
||||
IPin* GetConnected() { return mConnectedPin; }
|
||||
|
||||
protected:
|
||||
|
||||
// The pin's name, as returned by QueryPinInfo().
|
||||
std::wstring mName;
|
||||
|
||||
// Event sink for quality messages.
|
||||
IQualityControl *mQualitySink;
|
||||
|
||||
// The pin which this one is connected to.
|
||||
IPinPtr mConnectedPin;
|
||||
|
||||
// Direction of data flow through this pin.
|
||||
PIN_DIRECTION mDirection;
|
||||
|
||||
// Media type of the pin's connection.
|
||||
MediaType mMediaType;
|
||||
|
||||
// Our state lock. All state should be accessed while this is locked.
|
||||
mozilla::CriticalSection *mLock;
|
||||
|
||||
// Our owning filter.
|
||||
BaseFilter *mFilter;
|
||||
|
||||
// This pin attempts to connect to |aPin| with media type |aMediaType|.
|
||||
// If |aMediaType| is fully specified, we must attempt to connect with
|
||||
// that, else we just enumerate our types, then the other pin's type and
|
||||
// try them, filtering them using |aMediaType| if it's paritally
|
||||
// specificed. Used by Connect().
|
||||
HRESULT AttemptConnection(IPin* aPin, const MediaType* aMediaType);
|
||||
|
||||
// Tries to form a connection using all media types in the enumeration.
|
||||
HRESULT TryMediaTypes(IPin *aPin,
|
||||
const MediaType *aMediaType,
|
||||
IEnumMediaTypes *aEnum);
|
||||
};
|
||||
|
||||
// For mingw __uuidof support
|
||||
#ifdef __CRT_UUID_DECL
|
||||
}
|
||||
}
|
||||
__CRT_UUID_DECL(mozilla::media::BasePin, 0x199669c6,0x672a,0x4130,0xb1,0x3e,0x57,0xaa,0x83,0x0e,0xae,0x55);
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
#endif
|
||||
|
||||
_COM_SMARTPTR_TYPEDEF(BasePin, __uuidof(BasePin));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,111 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_DSHOWTOOLS_H_
|
||||
#define WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_DSHOWTOOLS_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* CriticalSection
|
||||
* Java-like monitor.
|
||||
* When possible, use CriticalSectionAutoEnter to hold this monitor within a
|
||||
* scope, instead of calling Enter/Exit directly.
|
||||
**/
|
||||
class CriticalSection
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* CriticalSection
|
||||
* @param aName A name which can reference this monitor
|
||||
*/
|
||||
explicit CriticalSection(const char* aName)
|
||||
{
|
||||
::InitializeCriticalSection(&mCriticalSection);
|
||||
}
|
||||
|
||||
/**
|
||||
* ~CriticalSection
|
||||
**/
|
||||
~CriticalSection()
|
||||
{
|
||||
::DeleteCriticalSection(&mCriticalSection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter
|
||||
* @see prmon.h
|
||||
**/
|
||||
void Enter()
|
||||
{
|
||||
::EnterCriticalSection(&mCriticalSection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit
|
||||
* @see prmon.h
|
||||
**/
|
||||
void Leave()
|
||||
{
|
||||
::LeaveCriticalSection(&mCriticalSection);
|
||||
}
|
||||
|
||||
private:
|
||||
CriticalSection();
|
||||
CriticalSection(const CriticalSection&);
|
||||
CriticalSection& operator =(const CriticalSection&);
|
||||
|
||||
CRITICAL_SECTION mCriticalSection;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* CriticalSectionAutoEnter
|
||||
* Enters the CriticalSection when it enters scope, and exits it when
|
||||
* it leaves scope.
|
||||
*
|
||||
* MUCH PREFERRED to bare calls to CriticalSection.Enter and Exit.
|
||||
*/
|
||||
class CriticalSectionAutoEnter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* The constructor aquires the given lock. The destructor
|
||||
* releases the lock.
|
||||
*
|
||||
* @param aCriticalSection A valid mozilla::CriticalSection*.
|
||||
**/
|
||||
explicit CriticalSectionAutoEnter(mozilla::CriticalSection &aCriticalSection) :
|
||||
mCriticalSection(&aCriticalSection)
|
||||
{
|
||||
assert(mCriticalSection);
|
||||
mCriticalSection->Enter();
|
||||
}
|
||||
|
||||
~CriticalSectionAutoEnter(void)
|
||||
{
|
||||
mCriticalSection->Leave();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
CriticalSectionAutoEnter();
|
||||
CriticalSectionAutoEnter(const CriticalSectionAutoEnter&);
|
||||
CriticalSectionAutoEnter& operator =(const CriticalSectionAutoEnter&);
|
||||
static void* operator new(size_t) throw();
|
||||
static void operator delete(void*);
|
||||
|
||||
mozilla::CriticalSection* mCriticalSection;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
#endif // ifndef mozilla_CriticalSection_h
|
|
@ -1,177 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MediaType.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
MediaType::MediaType()
|
||||
{
|
||||
// Zero out our memory. We do it here, rather than in operator new,
|
||||
// in case this is allocated on the stack.
|
||||
memset(this, 0, sizeof(MediaType));
|
||||
lSampleSize = 1;
|
||||
bFixedSizeSamples = TRUE;
|
||||
}
|
||||
|
||||
|
||||
MediaType::MediaType(const MediaType& aMediaType)
|
||||
{
|
||||
memset(this, 0, sizeof(MediaType));
|
||||
Assign(aMediaType);
|
||||
}
|
||||
|
||||
|
||||
MediaType::MediaType(const AM_MEDIA_TYPE* aMediaType)
|
||||
{
|
||||
memset(this, 0, sizeof(MediaType));
|
||||
Assign(aMediaType);
|
||||
}
|
||||
|
||||
|
||||
MediaType::~MediaType()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MediaType::operator delete(void* ptr)
|
||||
{
|
||||
CoTaskMemFree((void*)ptr);
|
||||
}
|
||||
|
||||
|
||||
void*
|
||||
MediaType::operator new(size_t sz) throw()
|
||||
{
|
||||
return CoTaskMemAlloc(sz);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MediaType::Clear()
|
||||
{
|
||||
if (cbFormat) {
|
||||
CoTaskMemFree(pbFormat);
|
||||
cbFormat = 0;
|
||||
pbFormat = NULL;
|
||||
}
|
||||
if (pUnk) {
|
||||
pUnk->Release();
|
||||
pUnk = NULL;
|
||||
}
|
||||
memset(this, 0, sizeof(MediaType));
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
MediaType::Assign(const AM_MEDIA_TYPE* aMediaType)
|
||||
{
|
||||
if (!aMediaType)
|
||||
return E_POINTER;
|
||||
|
||||
if (aMediaType == this)
|
||||
return S_OK;
|
||||
|
||||
// Release old data...
|
||||
Clear();
|
||||
|
||||
// Shallow copy.
|
||||
memcpy(static_cast<AM_MEDIA_TYPE*>(this), aMediaType, sizeof(AM_MEDIA_TYPE));
|
||||
|
||||
if (pUnk)
|
||||
pUnk->AddRef();
|
||||
|
||||
// Create deep copy of incoming data...
|
||||
if (cbFormat) {
|
||||
pbFormat = (BYTE*)CoTaskMemAlloc(cbFormat);
|
||||
if (!pbFormat)
|
||||
return E_OUTOFMEMORY;
|
||||
memcpy(pbFormat, aMediaType->pbFormat, cbFormat);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MediaType::Forget()
|
||||
{
|
||||
cbFormat = 0;
|
||||
pbFormat = NULL;
|
||||
pUnk = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MediaType::IsEqual(const AM_MEDIA_TYPE* aMediaType)
|
||||
{
|
||||
if (!aMediaType)
|
||||
return false;
|
||||
|
||||
if (aMediaType == this)
|
||||
return true;
|
||||
|
||||
return IsEqualGUID(majortype, aMediaType->majortype) &&
|
||||
IsEqualGUID(subtype, aMediaType->subtype) &&
|
||||
IsEqualGUID(formattype, aMediaType->formattype) &&
|
||||
(cbFormat == aMediaType->cbFormat) &&
|
||||
((cbFormat == 0) ||
|
||||
(pbFormat != NULL &&
|
||||
aMediaType->pbFormat != NULL &&
|
||||
(memcmp(pbFormat, aMediaType->pbFormat, cbFormat) == 0)));
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MediaType::MatchesPartial(const AM_MEDIA_TYPE* aMediaType) const
|
||||
{
|
||||
|
||||
if (!aMediaType)
|
||||
return false;
|
||||
|
||||
if ((aMediaType->majortype != GUID_NULL) &&
|
||||
(majortype != aMediaType->majortype))
|
||||
return false;
|
||||
|
||||
if ((aMediaType->subtype != GUID_NULL) &&
|
||||
(subtype != aMediaType->subtype))
|
||||
return false;
|
||||
|
||||
if (aMediaType->formattype != GUID_NULL) {
|
||||
|
||||
if (formattype != aMediaType->formattype)
|
||||
return false;
|
||||
|
||||
if (cbFormat != aMediaType->cbFormat)
|
||||
return false;
|
||||
|
||||
if ((cbFormat != 0) &&
|
||||
(memcmp(pbFormat, aMediaType->pbFormat, cbFormat) != 0))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MediaType::IsPartiallySpecified() const
|
||||
{
|
||||
return (majortype == GUID_NULL) || (formattype == GUID_NULL);
|
||||
}
|
||||
|
||||
BYTE*
|
||||
MediaType::AllocFormatBuffer(SIZE_T aSize)
|
||||
{
|
||||
pbFormat = static_cast<BYTE*>(CoTaskMemAlloc(aSize));
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_MEDIATYPE_H_
|
||||
#define WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_MEDIATYPE_H_
|
||||
|
||||
#include "dshow.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
// Wrapper for AM_MEDIA_TYPE. Can be used for a drop in replacement
|
||||
// for AM_MEDIA_TYPE. Manages memory of the AM_MEDIA_TYPE structure.
|
||||
// This class must be instantiated/destroyed using its custom new/detele
|
||||
// operators.
|
||||
class MediaType : public AM_MEDIA_TYPE
|
||||
{
|
||||
public:
|
||||
|
||||
MediaType();
|
||||
explicit MediaType(const AM_MEDIA_TYPE* aMediaType);
|
||||
explicit MediaType(const MediaType& aMediaType);
|
||||
|
||||
~MediaType();
|
||||
|
||||
// Deep copies |aMediaType| into this instance, freeing memory of this
|
||||
// instance first.
|
||||
HRESULT Assign(const AM_MEDIA_TYPE* aMediaType);
|
||||
HRESULT Assign(const AM_MEDIA_TYPE& aMediaType) {
|
||||
return Assign(&aMediaType);
|
||||
}
|
||||
|
||||
// Checks if |aMediaType|'s majortype, subtype, and format
|
||||
// blocks exactly match.
|
||||
bool IsEqual(const AM_MEDIA_TYPE* aMediaType);
|
||||
bool IsEqual(const AM_MEDIA_TYPE& aMediaType) {
|
||||
return IsEqual(&aMediaType);
|
||||
}
|
||||
|
||||
// Checks if |aMediaType|'s majortype, subtype, and format
|
||||
// blocks partially match. Null fields are assumed to match.
|
||||
bool MatchesPartial(const AM_MEDIA_TYPE* aMediaType) const;
|
||||
bool MatchesPartial(const AM_MEDIA_TYPE& aMediaType) const {
|
||||
return MatchesPartial(&aMediaType);
|
||||
}
|
||||
|
||||
// Returns true if media type isn't fully specified, i.e. it doesn't
|
||||
// have both a major and sub media type.
|
||||
bool IsPartiallySpecified() const;
|
||||
|
||||
// Release all memory for held by pointers in this media type
|
||||
// (the format buffer, and the ref count on pUnk).
|
||||
void Clear();
|
||||
|
||||
// Blanks all pointers to memory allocated on the free store.
|
||||
// Call this when ownership of that memory passes to another object.
|
||||
void Forget();
|
||||
|
||||
const GUID* Type() const
|
||||
{
|
||||
return &majortype;
|
||||
}
|
||||
void SetType(const GUID* aType)
|
||||
{
|
||||
majortype = *aType;
|
||||
}
|
||||
|
||||
const GUID* Subtype() const
|
||||
{
|
||||
return &subtype;
|
||||
}
|
||||
void SetSubtype(const GUID* aType)
|
||||
{
|
||||
subtype = *aType;
|
||||
}
|
||||
|
||||
const GUID* FormatType() const
|
||||
{
|
||||
return &formattype;
|
||||
}
|
||||
void SetFormatType(const GUID* aType)
|
||||
{
|
||||
formattype = *aType;
|
||||
}
|
||||
|
||||
BOOL TemporalCompression() const { return bTemporalCompression; }
|
||||
void SetTemporalCompression(BOOL aCompression)
|
||||
{
|
||||
bTemporalCompression = aCompression;
|
||||
}
|
||||
|
||||
ULONG SampleSize() const { return lSampleSize; }
|
||||
void SetSampleSize(ULONG aSampleSize)
|
||||
{
|
||||
lSampleSize = aSampleSize;
|
||||
}
|
||||
|
||||
BYTE* AllocFormatBuffer(SIZE_T aSize);
|
||||
BYTE* Format() const { return pbFormat; }
|
||||
|
||||
// Custom new/delete. This object *must* be allocated using
|
||||
// CoTaskMemAlloc(), and freed using CoTaskMemFree(). These new/delete
|
||||
// functions ensure that.
|
||||
void operator delete(void* ptr);
|
||||
void* operator new(size_t sz) throw();
|
||||
|
||||
operator AM_MEDIA_TYPE* () {
|
||||
return static_cast<AM_MEDIA_TYPE*>(this);
|
||||
}
|
||||
|
||||
private:
|
||||
// Don't allow assignment using operator=, use Assign() instead.
|
||||
MediaType& operator=(const MediaType&);
|
||||
MediaType& operator=(const AM_MEDIA_TYPE&);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -10,58 +10,16 @@
|
|||
|
||||
#include "modules/video_capture/windows/device_info_ds.h"
|
||||
|
||||
#include <ios> // std::hex
|
||||
|
||||
#include "modules/video_capture/video_capture_config.h"
|
||||
#include "modules/video_capture/windows/help_functions_ds.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/string_utils.h"
|
||||
|
||||
#include <Dvdmedia.h>
|
||||
#include <dbt.h>
|
||||
#include <ks.h>
|
||||
#include <dvdmedia.h>
|
||||
|
||||
namespace webrtc {
|
||||
namespace videocapturemodule {
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
DeviceInfoDS* pParent;
|
||||
if (uiMsg == WM_CREATE)
|
||||
{
|
||||
pParent = (DeviceInfoDS*)((LPCREATESTRUCT)lParam)->lpCreateParams;
|
||||
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pParent);
|
||||
}
|
||||
else if (uiMsg == WM_DESTROY)
|
||||
{
|
||||
SetWindowLongPtr(hWnd, GWLP_USERDATA, NULL);
|
||||
}
|
||||
else if (uiMsg == WM_DEVICECHANGE)
|
||||
{
|
||||
pParent = (DeviceInfoDS*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
||||
if (pParent)
|
||||
{
|
||||
pParent->DeviceChange();
|
||||
}
|
||||
}
|
||||
return DefWindowProc(hWnd, uiMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
void _FreeMediaType(AM_MEDIA_TYPE& mt)
|
||||
{
|
||||
if (mt.cbFormat != 0)
|
||||
{
|
||||
CoTaskMemFree((PVOID)mt.pbFormat);
|
||||
mt.cbFormat = 0;
|
||||
mt.pbFormat = NULL;
|
||||
}
|
||||
if (mt.pUnk != NULL)
|
||||
{
|
||||
// pUnk should not be used.
|
||||
mt.pUnk->Release();
|
||||
mt.pUnk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
DeviceInfoDS* DeviceInfoDS::Create() {
|
||||
DeviceInfoDS* dsInfo = new DeviceInfoDS();
|
||||
|
@ -73,7 +31,8 @@ DeviceInfoDS* DeviceInfoDS::Create() {
|
|||
}
|
||||
|
||||
DeviceInfoDS::DeviceInfoDS()
|
||||
: DeviceInfoImpl(), _dsDevEnum(NULL),
|
||||
: _dsDevEnum(NULL),
|
||||
_dsMonikerDevEnum(NULL),
|
||||
_CoUninitializeIsRequired(true) {
|
||||
// 1) Initialize the COM library (make Windows load the DLLs).
|
||||
//
|
||||
|
@ -114,34 +73,17 @@ DeviceInfoDS::DeviceInfoDS()
|
|||
//
|
||||
RTC_LOG(LS_INFO) << __FUNCTION__
|
||||
<< ": CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)"
|
||||
<< " => RPC_E_CHANGED_MODE, error 0x" << std::hex << hr;
|
||||
<< " => RPC_E_CHANGED_MODE, error 0x" << rtc::ToHex(hr);
|
||||
}
|
||||
}
|
||||
|
||||
_hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(NULL));
|
||||
_wndClass = {0};
|
||||
_wndClass.lpfnWndProc = &WndProc;
|
||||
_wndClass.lpszClassName = TEXT("DeviceInfoDS");
|
||||
_wndClass.hInstance = _hInstance;
|
||||
|
||||
if (RegisterClass(&_wndClass))
|
||||
{
|
||||
_hwnd = CreateWindow(_wndClass.lpszClassName, NULL, 0, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
|
||||
NULL, _hInstance, this);
|
||||
}
|
||||
}
|
||||
|
||||
DeviceInfoDS::~DeviceInfoDS() {
|
||||
RELEASE_AND_CLEAR(_dsMonikerDevEnum);
|
||||
RELEASE_AND_CLEAR(_dsDevEnum);
|
||||
if (_CoUninitializeIsRequired) {
|
||||
CoUninitialize();
|
||||
}
|
||||
if (_hwnd != NULL)
|
||||
{
|
||||
DestroyWindow(_hwnd);
|
||||
}
|
||||
UnregisterClass(_wndClass.lpszClassName, _hInstance);
|
||||
}
|
||||
|
||||
int32_t DeviceInfoDS::Init() {
|
||||
|
@ -149,14 +91,14 @@ int32_t DeviceInfoDS::Init() {
|
|||
IID_ICreateDevEnum, (void**)&_dsDevEnum);
|
||||
if (hr != NOERROR) {
|
||||
RTC_LOG(LS_INFO) << "Failed to create CLSID_SystemDeviceEnum, error 0x"
|
||||
<< std::hex << hr;
|
||||
<< rtc::ToHex(hr);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
uint32_t DeviceInfoDS::NumberOfDevices() {
|
||||
ReadLockScoped cs(_apiLock);
|
||||
return GetDeviceInfo(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
return GetDeviceInfo(0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
int32_t DeviceInfoDS::GetDeviceName(uint32_t deviceNumber,
|
||||
|
@ -165,14 +107,11 @@ int32_t DeviceInfoDS::GetDeviceName(uint32_t deviceNumber,
|
|||
char* deviceUniqueIdUTF8,
|
||||
uint32_t deviceUniqueIdUTF8Length,
|
||||
char* productUniqueIdUTF8,
|
||||
uint32_t productUniqueIdUTF8Length,
|
||||
pid_t* pid)
|
||||
{
|
||||
uint32_t productUniqueIdUTF8Length) {
|
||||
ReadLockScoped cs(_apiLock);
|
||||
const int32_t result = GetDeviceInfo(
|
||||
deviceNumber, deviceNameUTF8, deviceNameLength, deviceUniqueIdUTF8,
|
||||
deviceUniqueIdUTF8Length, productUniqueIdUTF8, productUniqueIdUTF8Length,
|
||||
pid);
|
||||
deviceUniqueIdUTF8Length, productUniqueIdUTF8, productUniqueIdUTF8Length);
|
||||
return result > (int32_t)deviceNumber ? 0 : -1;
|
||||
}
|
||||
|
||||
|
@ -182,17 +121,16 @@ int32_t DeviceInfoDS::GetDeviceInfo(uint32_t deviceNumber,
|
|||
char* deviceUniqueIdUTF8,
|
||||
uint32_t deviceUniqueIdUTF8Length,
|
||||
char* productUniqueIdUTF8,
|
||||
uint32_t productUniqueIdUTF8Length,
|
||||
pid_t* pid)
|
||||
uint32_t productUniqueIdUTF8Length)
|
||||
|
||||
{
|
||||
// enumerate all video capture devices
|
||||
IEnumMoniker* _dsMonikerDevEnum = NULL;
|
||||
RELEASE_AND_CLEAR(_dsMonikerDevEnum);
|
||||
HRESULT hr = _dsDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
|
||||
&_dsMonikerDevEnum, 0);
|
||||
if (hr != NOERROR) {
|
||||
RTC_LOG(LS_INFO) << "Failed to enumerate CLSID_SystemDeviceEnum, error 0x"
|
||||
<< std::hex << hr << ". No webcam exist?";
|
||||
RELEASE_AND_CLEAR(_dsMonikerDevEnum);
|
||||
<< rtc::ToHex(hr) << ". No webcam exist?";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -225,7 +163,6 @@ int32_t DeviceInfoDS::GetDeviceInfo(uint32_t deviceNumber,
|
|||
if (convResult == 0) {
|
||||
RTC_LOG(LS_INFO) << "Failed to convert device name to UTF8, "
|
||||
<< "error = " << GetLastError();
|
||||
RELEASE_AND_CLEAR(_dsMonikerDevEnum);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -245,7 +182,6 @@ int32_t DeviceInfoDS::GetDeviceInfo(uint32_t deviceNumber,
|
|||
RTC_LOG(LS_INFO)
|
||||
<< "Failed to convert device "
|
||||
<< "name to UTF8, error = " << GetLastError();
|
||||
RELEASE_AND_CLEAR(_dsMonikerDevEnum);
|
||||
return -1;
|
||||
}
|
||||
if (productUniqueIdUTF8 && productUniqueIdUTF8Length > 0) {
|
||||
|
@ -264,9 +200,8 @@ int32_t DeviceInfoDS::GetDeviceInfo(uint32_t deviceNumber,
|
|||
}
|
||||
}
|
||||
if (deviceNameLength) {
|
||||
RTC_LOG(LS_INFO) << __FUNCTION__ << ": deviceName: " << deviceNameUTF8;
|
||||
RTC_LOG(LS_INFO) << __FUNCTION__ << " " << deviceNameUTF8;
|
||||
}
|
||||
RELEASE_AND_CLEAR(_dsMonikerDevEnum);
|
||||
return index;
|
||||
}
|
||||
|
||||
|
@ -281,13 +216,12 @@ IBaseFilter* DeviceInfoDS::GetDeviceFilter(const char* deviceUniqueIdUTF8,
|
|||
}
|
||||
|
||||
// enumerate all video capture devices
|
||||
IEnumMoniker* _dsMonikerDevEnum = NULL;
|
||||
RELEASE_AND_CLEAR(_dsMonikerDevEnum);
|
||||
HRESULT hr = _dsDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
|
||||
&_dsMonikerDevEnum, 0);
|
||||
if (hr != NOERROR) {
|
||||
RTC_LOG(LS_INFO) << "Failed to enumerate CLSID_SystemDeviceEnum, error 0x"
|
||||
<< std::hex << hr << ". No webcam exist?";
|
||||
RELEASE_AND_CLEAR(_dsMonikerDevEnum);
|
||||
<< rtc::ToHex(hr) << ". No webcam exist?";
|
||||
return 0;
|
||||
}
|
||||
_dsMonikerDevEnum->Reset();
|
||||
|
@ -343,7 +277,6 @@ IBaseFilter* DeviceInfoDS::GetDeviceFilter(const char* deviceUniqueIdUTF8,
|
|||
pM->Release();
|
||||
}
|
||||
}
|
||||
RELEASE_AND_CLEAR(_dsMonikerDevEnum);
|
||||
return captureFilter;
|
||||
}
|
||||
|
||||
|
@ -362,6 +295,7 @@ int32_t DeviceInfoDS::GetWindowsCapability(
|
|||
}
|
||||
|
||||
int32_t DeviceInfoDS::CreateCapabilityMap(const char* deviceUniqueIdUTF8)
|
||||
|
||||
{
|
||||
// Reset old capability list
|
||||
_captureCapabilities.clear();
|
||||
|
@ -500,7 +434,7 @@ int32_t DeviceInfoDS::CreateCapabilityMap(const char* deviceUniqueIdUTF8)
|
|||
}
|
||||
|
||||
if (hrVC == S_OK) {
|
||||
LONGLONG* frameDurationList = NULL;
|
||||
LONGLONG* frameDurationList;
|
||||
LONGLONG maxFPS;
|
||||
long listSize;
|
||||
SIZE size;
|
||||
|
@ -517,9 +451,7 @@ int32_t DeviceInfoDS::CreateCapabilityMap(const char* deviceUniqueIdUTF8)
|
|||
|
||||
// On some odd cameras, you may get a 0 for duration.
|
||||
// GetMaxOfFrameArray returns the lowest duration (highest FPS)
|
||||
// Initialize and check the returned list for null since
|
||||
// some broken drivers don't modify it.
|
||||
if (hrVC == S_OK && listSize > 0 && frameDurationList &&
|
||||
if (hrVC == S_OK && listSize > 0 &&
|
||||
0 != (maxFPS = GetMaxOfFrameArray(frameDurationList, listSize))) {
|
||||
capability.maxFPS = static_cast<int>(10000000 / maxFPS);
|
||||
capability.supportFrameRateControl = true;
|
||||
|
@ -531,9 +463,6 @@ int32_t DeviceInfoDS::CreateCapabilityMap(const char* deviceUniqueIdUTF8)
|
|||
else
|
||||
capability.maxFPS = 0;
|
||||
}
|
||||
if (frameDurationList) {
|
||||
CoTaskMemFree((PVOID)frameDurationList); // NULL not safe
|
||||
}
|
||||
} else // use existing method in case IAMVideoControl is not supported
|
||||
{
|
||||
if (avgTimePerFrame > 0)
|
||||
|
@ -579,6 +508,7 @@ int32_t DeviceInfoDS::CreateCapabilityMap(const char* deviceUniqueIdUTF8)
|
|||
RTC_LOG(LS_WARNING)
|
||||
<< "Device support unknown media type " << strGuid << ", width "
|
||||
<< capability.width << ", height " << capability.height;
|
||||
continue;
|
||||
}
|
||||
|
||||
_captureCapabilities.push_back(capability);
|
||||
|
@ -588,7 +518,7 @@ int32_t DeviceInfoDS::CreateCapabilityMap(const char* deviceUniqueIdUTF8)
|
|||
<< " type:" << static_cast<int>(capability.videoType)
|
||||
<< " fps:" << capability.maxFPS;
|
||||
}
|
||||
_FreeMediaType(*pmt);
|
||||
FreeMediaType(pmt);
|
||||
pmt = NULL;
|
||||
}
|
||||
RELEASE_AND_CLEAR(streamConfig);
|
||||
|
@ -607,13 +537,12 @@ int32_t DeviceInfoDS::CreateCapabilityMap(const char* deviceUniqueIdUTF8)
|
|||
return static_cast<int32_t>(_captureCapabilities.size());
|
||||
}
|
||||
|
||||
/* Constructs a product ID from the Windows DevicePath. on a USB device the
|
||||
devicePath contains product id and vendor id. This seems to work for firewire
|
||||
as well
|
||||
/* Example of device path
|
||||
"\\?\usb#vid_0408&pid_2010&mi_00#7&258e7aaf&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
|
||||
"\\?\avc#sony&dv-vcr&camcorder&dv#65b2d50301460008#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
|
||||
*/
|
||||
// Constructs a product ID from the Windows DevicePath. on a USB device the
|
||||
// devicePath contains product id and vendor id. This seems to work for firewire
|
||||
// as well.
|
||||
// Example of device path:
|
||||
// "\\?\usb#vid_0408&pid_2010&mi_00#7&258e7aaf&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
|
||||
// "\\?\avc#sony&dv-vcr&camcorder&dv#65b2d50301460008#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
|
||||
void DeviceInfoDS::GetProductId(const char* devicePath,
|
||||
char* productUniqueIdUTF8,
|
||||
uint32_t productUniqueIdUTF8Length) {
|
||||
|
|
|
@ -15,96 +15,83 @@
|
|||
#include "modules/video_capture/video_capture_impl.h"
|
||||
|
||||
#include <dshow.h>
|
||||
#include <windows.h>
|
||||
|
||||
namespace webrtc
|
||||
{
|
||||
namespace videocapturemodule
|
||||
{
|
||||
struct VideoCaptureCapabilityWindows: public VideoCaptureCapability
|
||||
{
|
||||
namespace webrtc {
|
||||
namespace videocapturemodule {
|
||||
struct VideoCaptureCapabilityWindows : public VideoCaptureCapability {
|
||||
uint32_t directShowCapabilityIndex;
|
||||
bool supportFrameRateControl;
|
||||
VideoCaptureCapabilityWindows()
|
||||
{
|
||||
VideoCaptureCapabilityWindows() {
|
||||
directShowCapabilityIndex = 0;
|
||||
supportFrameRateControl = false;
|
||||
}
|
||||
};
|
||||
|
||||
class DeviceInfoDS: public DeviceInfoImpl
|
||||
{
|
||||
public:
|
||||
class DeviceInfoDS : public DeviceInfoImpl {
|
||||
public:
|
||||
// Factory function.
|
||||
static DeviceInfoDS* Create();
|
||||
|
||||
DeviceInfoDS();
|
||||
virtual ~DeviceInfoDS();
|
||||
~DeviceInfoDS() override;
|
||||
|
||||
int32_t Init();
|
||||
virtual uint32_t NumberOfDevices();
|
||||
int32_t Refresh() { return 0; }
|
||||
int32_t Init() override;
|
||||
uint32_t NumberOfDevices() override;
|
||||
|
||||
/*
|
||||
* Returns the available capture devices.
|
||||
*/
|
||||
virtual int32_t
|
||||
GetDeviceName(uint32_t deviceNumber,
|
||||
int32_t GetDeviceName(uint32_t deviceNumber,
|
||||
char* deviceNameUTF8,
|
||||
uint32_t deviceNameLength,
|
||||
char* deviceUniqueIdUTF8,
|
||||
uint32_t deviceUniqueIdUTF8Length,
|
||||
char* productUniqueIdUTF8,
|
||||
uint32_t productUniqueIdUTF8Length,
|
||||
pid_t* pid);
|
||||
uint32_t productUniqueIdUTF8Length) override;
|
||||
|
||||
/*
|
||||
* Display OS /capture device specific settings dialog
|
||||
*/
|
||||
virtual int32_t
|
||||
DisplayCaptureSettingsDialogBox(
|
||||
const char* deviceUniqueIdUTF8,
|
||||
int32_t DisplayCaptureSettingsDialogBox(const char* deviceUniqueIdUTF8,
|
||||
const char* dialogTitleUTF8,
|
||||
void* parentWindow,
|
||||
uint32_t positionX,
|
||||
uint32_t positionY);
|
||||
uint32_t positionY) override;
|
||||
|
||||
// Windows specific
|
||||
|
||||
/* Gets a capture device filter
|
||||
The user of this API is responsible for releasing the filter when it not needed.
|
||||
The user of this API is responsible for releasing the filter when it not
|
||||
needed.
|
||||
*/
|
||||
IBaseFilter * GetDeviceFilter(const char* deviceUniqueIdUTF8,
|
||||
IBaseFilter* GetDeviceFilter(const char* deviceUniqueIdUTF8,
|
||||
char* productUniqueIdUTF8 = NULL,
|
||||
uint32_t productUniqueIdUTF8Length = 0);
|
||||
|
||||
int32_t
|
||||
GetWindowsCapability(const int32_t capabilityIndex,
|
||||
int32_t GetWindowsCapability(
|
||||
const int32_t capabilityIndex,
|
||||
VideoCaptureCapabilityWindows& windowsCapability);
|
||||
|
||||
static void GetProductId(const char* devicePath,
|
||||
char* productUniqueIdUTF8,
|
||||
uint32_t productUniqueIdUTF8Length);
|
||||
|
||||
protected:
|
||||
protected:
|
||||
int32_t GetDeviceInfo(uint32_t deviceNumber,
|
||||
char* deviceNameUTF8,
|
||||
uint32_t deviceNameLength,
|
||||
char* deviceUniqueIdUTF8,
|
||||
uint32_t deviceUniqueIdUTF8Length,
|
||||
char* productUniqueIdUTF8,
|
||||
uint32_t productUniqueIdUTF8Length,
|
||||
pid_t* pid);
|
||||
uint32_t productUniqueIdUTF8Length);
|
||||
|
||||
virtual int32_t
|
||||
CreateCapabilityMap(const char* deviceUniqueIdUTF8);
|
||||
private:
|
||||
int32_t CreateCapabilityMap(const char* deviceUniqueIdUTF8) override;
|
||||
|
||||
private:
|
||||
ICreateDevEnum* _dsDevEnum;
|
||||
IEnumMoniker* _dsMonikerDevEnum;
|
||||
bool _CoUninitializeIsRequired;
|
||||
std::vector<VideoCaptureCapabilityWindows> _captureCapabilitiesWindows;
|
||||
HWND _hwnd;
|
||||
WNDCLASS _wndClass;
|
||||
HINSTANCE _hInstance;
|
||||
};
|
||||
} // namespace videocapturemodule
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/video_capture/windows/device_info_mf.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace videocapturemodule {
|
||||
|
||||
DeviceInfoMF::DeviceInfoMF() : DeviceInfoImpl() {
|
||||
}
|
||||
|
||||
DeviceInfoMF::~DeviceInfoMF() {
|
||||
}
|
||||
|
||||
int32_t DeviceInfoMF::Init() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t DeviceInfoMF::NumberOfDevices() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t DeviceInfoMF::GetDeviceName(
|
||||
uint32_t deviceNumber,
|
||||
char* deviceNameUTF8,
|
||||
uint32_t deviceNameLength,
|
||||
char* deviceUniqueIdUTF8,
|
||||
uint32_t deviceUniqueIdUTF8Length,
|
||||
char* productUniqueIdUTF8,
|
||||
uint32_t productUniqueIdUTF8Length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t DeviceInfoMF::DisplayCaptureSettingsDialogBox(
|
||||
const char* deviceUniqueIdUTF8,
|
||||
const char* dialogTitleUTF8,
|
||||
void* parentWindow,
|
||||
uint32_t positionX,
|
||||
uint32_t positionY) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace videocapturemodule
|
||||
} // namespace webrtc
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_VIDEO_CAPTURE_WINDOWS_DEVICE_INFO_MF_H_
|
||||
#define MODULES_VIDEO_CAPTURE_WINDOWS_DEVICE_INFO_MF_H_
|
||||
|
||||
#include "modules/video_capture/device_info_impl.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace videocapturemodule {
|
||||
|
||||
// Provides video capture device information using the Media Foundation API.
|
||||
class DeviceInfoMF : public DeviceInfoImpl {
|
||||
public:
|
||||
DeviceInfoMF();
|
||||
virtual ~DeviceInfoMF();
|
||||
|
||||
int32_t Init();
|
||||
virtual uint32_t NumberOfDevices();
|
||||
|
||||
virtual int32_t GetDeviceName(uint32_t deviceNumber, char* deviceNameUTF8,
|
||||
uint32_t deviceNameLength,
|
||||
char* deviceUniqueIdUTF8,
|
||||
uint32_t deviceUniqueIdUTF8Length,
|
||||
char* productUniqueIdUTF8,
|
||||
uint32_t productUniqueIdUTF8Length);
|
||||
|
||||
virtual int32_t DisplayCaptureSettingsDialogBox(
|
||||
const char* deviceUniqueIdUTF8, const char* dialogTitleUTF8,
|
||||
void* parentWindow, uint32_t positionX, uint32_t positionY);
|
||||
};
|
||||
|
||||
} // namespace videocapturemodule
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_VIDEO_CAPTURE_WINDOWS_DEVICE_INFO_MF_H_
|
|
@ -14,40 +14,35 @@
|
|||
|
||||
#include "modules/video_capture/windows/help_functions_ds.h"
|
||||
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
#include <cguid.h>
|
||||
|
||||
namespace webrtc
|
||||
{
|
||||
namespace videocapturemodule
|
||||
{
|
||||
namespace webrtc {
|
||||
namespace videocapturemodule {
|
||||
// This returns minimum :), which will give max frame rate...
|
||||
LONGLONG GetMaxOfFrameArray(LONGLONG *maxFps, long size)
|
||||
{
|
||||
LONGLONG GetMaxOfFrameArray(LONGLONG* maxFps, long size) {
|
||||
LONGLONG maxFPS = maxFps[0];
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (maxFPS > maxFps[i])
|
||||
maxFPS = maxFps[i];
|
||||
}
|
||||
return maxFPS;
|
||||
}
|
||||
|
||||
IPin* GetInputPin(IBaseFilter* filter)
|
||||
{
|
||||
IPin* GetInputPin(IBaseFilter* filter) {
|
||||
HRESULT hr;
|
||||
IPin* pin = NULL;
|
||||
IEnumPins* pPinEnum = NULL;
|
||||
filter->EnumPins(&pPinEnum);
|
||||
if (pPinEnum == NULL)
|
||||
{
|
||||
if (pPinEnum == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get first unconnected pin
|
||||
hr = pPinEnum->Reset(); // set to first pin
|
||||
|
||||
while (S_OK == pPinEnum->Next(1, &pin, NULL))
|
||||
{
|
||||
while (S_OK == pPinEnum->Next(1, &pin, NULL)) {
|
||||
PIN_DIRECTION pPinDir;
|
||||
pin->QueryDirection(&pPinDir);
|
||||
if (PINDIR_INPUT == pPinDir) // This is an input pin
|
||||
|
@ -65,26 +60,22 @@ IPin* GetInputPin(IBaseFilter* filter)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
IPin* GetOutputPin(IBaseFilter* filter, REFGUID Category)
|
||||
{
|
||||
IPin* GetOutputPin(IBaseFilter* filter, REFGUID Category) {
|
||||
HRESULT hr;
|
||||
IPin* pin = NULL;
|
||||
IEnumPins* pPinEnum = NULL;
|
||||
filter->EnumPins(&pPinEnum);
|
||||
if (pPinEnum == NULL)
|
||||
{
|
||||
if (pPinEnum == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// get first unconnected pin
|
||||
hr = pPinEnum->Reset(); // set to first pin
|
||||
while (S_OK == pPinEnum->Next(1, &pin, NULL))
|
||||
{
|
||||
while (S_OK == pPinEnum->Next(1, &pin, NULL)) {
|
||||
PIN_DIRECTION pPinDir;
|
||||
pin->QueryDirection(&pPinDir);
|
||||
if (PINDIR_OUTPUT == pPinDir) // This is an output pin
|
||||
{
|
||||
if (Category == GUID_NULL || PinMatchesCategory(pin, Category))
|
||||
{
|
||||
if (Category == GUID_NULL || PinMatchesCategory(pin, Category)) {
|
||||
pPinEnum->Release();
|
||||
return pin;
|
||||
}
|
||||
|
@ -96,24 +87,72 @@ IPin* GetOutputPin(IBaseFilter* filter, REFGUID Category)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
BOOL PinMatchesCategory(IPin *pPin, REFGUID Category)
|
||||
{
|
||||
BOOL PinMatchesCategory(IPin* pPin, REFGUID Category) {
|
||||
BOOL bFound = FALSE;
|
||||
IKsPropertySet *pKs = NULL;
|
||||
IKsPropertySet* pKs = NULL;
|
||||
HRESULT hr = pPin->QueryInterface(IID_PPV_ARGS(&pKs));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (SUCCEEDED(hr)) {
|
||||
GUID PinCategory;
|
||||
DWORD cbReturned;
|
||||
hr = pKs->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0, &PinCategory,
|
||||
sizeof(GUID), &cbReturned);
|
||||
if (SUCCEEDED(hr) && (cbReturned == sizeof(GUID)))
|
||||
{
|
||||
hr = pKs->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0,
|
||||
&PinCategory, sizeof(GUID), &cbReturned);
|
||||
if (SUCCEEDED(hr) && (cbReturned == sizeof(GUID))) {
|
||||
bFound = (PinCategory == Category);
|
||||
}
|
||||
pKs->Release();
|
||||
}
|
||||
return bFound;
|
||||
}
|
||||
|
||||
void ResetMediaType(AM_MEDIA_TYPE* media_type) {
|
||||
if (!media_type)
|
||||
return;
|
||||
if (media_type->cbFormat != 0) {
|
||||
CoTaskMemFree(media_type->pbFormat);
|
||||
media_type->cbFormat = 0;
|
||||
media_type->pbFormat = nullptr;
|
||||
}
|
||||
if (media_type->pUnk) {
|
||||
media_type->pUnk->Release();
|
||||
media_type->pUnk = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void FreeMediaType(AM_MEDIA_TYPE* media_type) {
|
||||
if (!media_type)
|
||||
return;
|
||||
ResetMediaType(media_type);
|
||||
CoTaskMemFree(media_type);
|
||||
}
|
||||
|
||||
HRESULT CopyMediaType(AM_MEDIA_TYPE* target, const AM_MEDIA_TYPE* source) {
|
||||
RTC_DCHECK_NE(source, target);
|
||||
*target = *source;
|
||||
if (source->cbFormat != 0) {
|
||||
RTC_DCHECK(source->pbFormat);
|
||||
target->pbFormat =
|
||||
reinterpret_cast<BYTE*>(CoTaskMemAlloc(source->cbFormat));
|
||||
if (target->pbFormat == nullptr) {
|
||||
target->cbFormat = 0;
|
||||
return E_OUTOFMEMORY;
|
||||
} else {
|
||||
CopyMemory(target->pbFormat, source->pbFormat, target->cbFormat);
|
||||
}
|
||||
}
|
||||
|
||||
if (target->pUnk != nullptr)
|
||||
target->pUnk->AddRef();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
wchar_t* DuplicateWideString(const wchar_t* str) {
|
||||
size_t len = lstrlenW(str);
|
||||
wchar_t* ret =
|
||||
reinterpret_cast<LPWSTR>(CoTaskMemAlloc((len + 1) * sizeof(wchar_t)));
|
||||
lstrcpyW(ret, str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace videocapturemodule
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -13,22 +13,105 @@
|
|||
|
||||
#include <dshow.h>
|
||||
|
||||
DEFINE_GUID(MEDIASUBTYPE_I420, 0x30323449, 0x0000, 0x0010, 0x80, 0x00, 0x00,
|
||||
0xAA, 0x00, 0x38, 0x9B, 0x71);
|
||||
DEFINE_GUID(MEDIASUBTYPE_HDYC, 0x43594448, 0x0000, 0x0010, 0x80, 0x00, 0x00,
|
||||
0xAA, 0x00, 0x38, 0x9B, 0x71);
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#define RELEASE_AND_CLEAR(p) if (p) { (p) -> Release () ; (p) = NULL ; }
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "rtc_base/ref_counter.h"
|
||||
|
||||
namespace webrtc
|
||||
{
|
||||
namespace videocapturemodule
|
||||
{
|
||||
LONGLONG GetMaxOfFrameArray(LONGLONG *maxFps, long size);
|
||||
DEFINE_GUID(MEDIASUBTYPE_I420,
|
||||
0x30323449,
|
||||
0x0000,
|
||||
0x0010,
|
||||
0x80,
|
||||
0x00,
|
||||
0x00,
|
||||
0xAA,
|
||||
0x00,
|
||||
0x38,
|
||||
0x9B,
|
||||
0x71);
|
||||
DEFINE_GUID(MEDIASUBTYPE_HDYC,
|
||||
0x43594448,
|
||||
0x0000,
|
||||
0x0010,
|
||||
0x80,
|
||||
0x00,
|
||||
0x00,
|
||||
0xAA,
|
||||
0x00,
|
||||
0x38,
|
||||
0x9B,
|
||||
0x71);
|
||||
|
||||
#define RELEASE_AND_CLEAR(p) \
|
||||
if (p) { \
|
||||
(p)->Release(); \
|
||||
(p) = NULL; \
|
||||
}
|
||||
|
||||
namespace webrtc {
|
||||
namespace videocapturemodule {
|
||||
LONGLONG GetMaxOfFrameArray(LONGLONG* maxFps, long size);
|
||||
|
||||
IPin* GetInputPin(IBaseFilter* filter);
|
||||
IPin* GetOutputPin(IBaseFilter* filter, REFGUID Category);
|
||||
BOOL PinMatchesCategory(IPin *pPin, REFGUID Category);
|
||||
BOOL PinMatchesCategory(IPin* pPin, REFGUID Category);
|
||||
void ResetMediaType(AM_MEDIA_TYPE* media_type);
|
||||
void FreeMediaType(AM_MEDIA_TYPE* media_type);
|
||||
HRESULT CopyMediaType(AM_MEDIA_TYPE* target, const AM_MEDIA_TYPE* source);
|
||||
|
||||
// Helper function to make using scoped_refptr with COM interface pointers
|
||||
// a little less awkward. rtc::scoped_refptr doesn't support the & operator
|
||||
// or a way to receive values via an out ptr.
|
||||
// The function is intentionally not called QueryInterface to make things less
|
||||
// confusing for the compiler to figure out what the caller wants to do when
|
||||
// called from within the context of a class that also implements COM
|
||||
// interfaces.
|
||||
template <class T>
|
||||
HRESULT GetComInterface(IUnknown* object, rtc::scoped_refptr<T>* ptr) {
|
||||
// This helper function is not meant to magically free ptr. If we do that
|
||||
// we add code bloat to most places where it's not needed and make the code
|
||||
// less readable since it's not clear at the call site that the pointer
|
||||
// would get freed even inf QI() fails.
|
||||
RTC_DCHECK(!ptr->get());
|
||||
void* new_ptr = nullptr;
|
||||
HRESULT hr = object->QueryInterface(__uuidof(T), &new_ptr);
|
||||
if (SUCCEEDED(hr))
|
||||
ptr->swap(reinterpret_cast<T**>(&new_ptr));
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Provides a reference count implementation for COM (IUnknown derived) classes.
|
||||
// The implementation uses atomics for managing the ref count.
|
||||
template <class T>
|
||||
class ComRefCount : public T {
|
||||
public:
|
||||
ComRefCount() {}
|
||||
|
||||
template <class P0>
|
||||
explicit ComRefCount(P0&& p0) : T(std::forward<P0>(p0)) {}
|
||||
|
||||
STDMETHOD_(ULONG, AddRef)() override {
|
||||
ref_count_.IncRef();
|
||||
return 1;
|
||||
}
|
||||
|
||||
STDMETHOD_(ULONG, Release)() override {
|
||||
const auto status = ref_count_.DecRef();
|
||||
if (status == rtc::RefCountReleaseStatus::kDroppedLastRef) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected:
|
||||
~ComRefCount() {}
|
||||
|
||||
private:
|
||||
webrtc::webrtc_impl::RefCounter ref_count_{0};
|
||||
};
|
||||
|
||||
} // namespace videocapturemodule
|
||||
} // namespace webrtc
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -11,94 +11,151 @@
|
|||
#ifndef MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_SINK_FILTER_DS_H_
|
||||
#define MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_SINK_FILTER_DS_H_
|
||||
|
||||
#include "modules/video_capture/video_capture_defines.h"
|
||||
#include "BaseInputPin.h"
|
||||
#include "BaseFilter.h"
|
||||
#include "MediaType.h"
|
||||
#include <dshow.h>
|
||||
|
||||
namespace webrtc
|
||||
{
|
||||
namespace videocapturemodule
|
||||
{
|
||||
//forward declaration
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "modules/video_capture/video_capture_impl.h"
|
||||
#include "modules/video_capture/windows/help_functions_ds.h"
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
#include "rtc_base/thread_checker.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace videocapturemodule {
|
||||
// forward declarations
|
||||
class CaptureSinkFilter;
|
||||
/**
|
||||
* input pin for camera input
|
||||
*
|
||||
*/
|
||||
class CaptureInputPin: public mozilla::media::BaseInputPin
|
||||
{
|
||||
public:
|
||||
int32_t _moduleId;
|
||||
|
||||
VideoCaptureCapability _requestedCapability;
|
||||
VideoCaptureCapability _resultingCapability;
|
||||
HANDLE _threadHandle;
|
||||
// Input pin for camera input
|
||||
// Implements IMemInputPin, IPin.
|
||||
class CaptureInputPin : public IMemInputPin, public IPin {
|
||||
public:
|
||||
CaptureInputPin(CaptureSinkFilter* filter);
|
||||
|
||||
CaptureInputPin(int32_t moduleId,
|
||||
IN TCHAR* szName,
|
||||
IN CaptureSinkFilter* pFilter,
|
||||
IN mozilla::CriticalSection * pLock,
|
||||
OUT HRESULT * pHr,
|
||||
IN LPCWSTR pszName);
|
||||
HRESULT SetRequestedCapability(const VideoCaptureCapability& capability);
|
||||
|
||||
// Notifications from the filter.
|
||||
void OnFilterActivated();
|
||||
void OnFilterDeactivated();
|
||||
|
||||
protected:
|
||||
virtual ~CaptureInputPin();
|
||||
|
||||
HRESULT GetMediaType (IN int iPos, OUT mozilla::media::MediaType * pmt);
|
||||
HRESULT CheckMediaType (IN const mozilla::media::MediaType * pmt);
|
||||
STDMETHODIMP Receive (IN IMediaSample *);
|
||||
HRESULT SetMatchingMediaType(const VideoCaptureCapability& capability);
|
||||
private:
|
||||
CaptureSinkFilter* Filter() const;
|
||||
|
||||
HRESULT AttemptConnection(IPin* receive_pin, const AM_MEDIA_TYPE* media_type);
|
||||
std::vector<AM_MEDIA_TYPE*> DetermineCandidateFormats(
|
||||
IPin* receive_pin,
|
||||
const AM_MEDIA_TYPE* media_type);
|
||||
void ClearAllocator(bool decommit);
|
||||
HRESULT CheckDirection(IPin* pin) const;
|
||||
|
||||
// IUnknown
|
||||
STDMETHOD(QueryInterface)(REFIID riid, void** ppv) override;
|
||||
|
||||
// clang-format off
|
||||
// clang isn't sure what to do with the longer STDMETHOD() function
|
||||
// declarations.
|
||||
|
||||
// IPin
|
||||
STDMETHOD(Connect)(IPin* receive_pin,
|
||||
const AM_MEDIA_TYPE* media_type) override;
|
||||
STDMETHOD(ReceiveConnection)(IPin* connector,
|
||||
const AM_MEDIA_TYPE* media_type) override;
|
||||
STDMETHOD(Disconnect)() override;
|
||||
STDMETHOD(ConnectedTo)(IPin** pin) override;
|
||||
STDMETHOD(ConnectionMediaType)(AM_MEDIA_TYPE* media_type) override;
|
||||
STDMETHOD(QueryPinInfo)(PIN_INFO* info) override;
|
||||
STDMETHOD(QueryDirection)(PIN_DIRECTION* pin_dir) override;
|
||||
STDMETHOD(QueryId)(LPWSTR* id) override;
|
||||
STDMETHOD(QueryAccept)(const AM_MEDIA_TYPE* media_type) override;
|
||||
STDMETHOD(EnumMediaTypes)(IEnumMediaTypes** types) override;
|
||||
STDMETHOD(QueryInternalConnections)(IPin** pins, ULONG* count) override;
|
||||
STDMETHOD(EndOfStream)() override;
|
||||
STDMETHOD(BeginFlush)() override;
|
||||
STDMETHOD(EndFlush)() override;
|
||||
STDMETHOD(NewSegment)(REFERENCE_TIME start, REFERENCE_TIME stop,
|
||||
double rate) override;
|
||||
|
||||
// IMemInputPin
|
||||
STDMETHOD(GetAllocator)(IMemAllocator** allocator) override;
|
||||
STDMETHOD(NotifyAllocator)(IMemAllocator* allocator, BOOL read_only) override;
|
||||
STDMETHOD(GetAllocatorRequirements)(ALLOCATOR_PROPERTIES* props) override;
|
||||
STDMETHOD(Receive)(IMediaSample* sample) override;
|
||||
STDMETHOD(ReceiveMultiple)(IMediaSample** samples, long count,
|
||||
long* processed) override;
|
||||
STDMETHOD(ReceiveCanBlock)() override;
|
||||
// clang-format on
|
||||
|
||||
rtc::ThreadChecker main_checker_;
|
||||
rtc::ThreadChecker capture_checker_;
|
||||
|
||||
VideoCaptureCapability requested_capability_ RTC_GUARDED_BY(main_checker_);
|
||||
// Accessed on the main thread when Filter()->IsStopped() (capture thread not
|
||||
// running), otherwise accessed on the capture thread.
|
||||
VideoCaptureCapability resulting_capability_;
|
||||
DWORD capture_thread_id_ = 0;
|
||||
rtc::scoped_refptr<IMemAllocator> allocator_ RTC_GUARDED_BY(main_checker_);
|
||||
rtc::scoped_refptr<IPin> receive_pin_ RTC_GUARDED_BY(main_checker_);
|
||||
std::atomic_bool flushing_{false};
|
||||
std::atomic_bool runtime_error_{false};
|
||||
// Holds a referenceless pointer to the owning filter, the name and
|
||||
// direction of the pin. The filter pointer can be considered const.
|
||||
PIN_INFO info_ = {};
|
||||
AM_MEDIA_TYPE media_type_ RTC_GUARDED_BY(main_checker_) = {};
|
||||
};
|
||||
|
||||
class CaptureSinkFilter: public mozilla::media::BaseFilter
|
||||
{
|
||||
// Implement IBaseFilter (including IPersist and IMediaFilter).
|
||||
class CaptureSinkFilter : public IBaseFilter {
|
||||
public:
|
||||
CaptureSinkFilter(VideoCaptureImpl* capture_observer);
|
||||
|
||||
public:
|
||||
CaptureSinkFilter(IN TCHAR * tszName,
|
||||
IN LPUNKNOWN punk,
|
||||
OUT HRESULT * phr,
|
||||
VideoCaptureExternal& captureObserver,
|
||||
int32_t moduleId);
|
||||
HRESULT SetRequestedCapability(const VideoCaptureCapability& capability);
|
||||
|
||||
// Called on the capture thread.
|
||||
void ProcessCapturedFrame(unsigned char* buffer,
|
||||
size_t length,
|
||||
const VideoCaptureCapability& frame_info);
|
||||
|
||||
void NotifyEvent(long code, LONG_PTR param1, LONG_PTR param2);
|
||||
bool IsStopped() const;
|
||||
|
||||
// IUnknown
|
||||
STDMETHOD(QueryInterface)(REFIID riid, void** ppv) override;
|
||||
|
||||
// IPersist
|
||||
STDMETHOD(GetClassID)(CLSID* clsid) override;
|
||||
|
||||
// IMediaFilter.
|
||||
STDMETHOD(GetState)(DWORD msecs, FILTER_STATE* state) override;
|
||||
STDMETHOD(SetSyncSource)(IReferenceClock* clock) override;
|
||||
STDMETHOD(GetSyncSource)(IReferenceClock** clock) override;
|
||||
STDMETHOD(Pause)() override;
|
||||
STDMETHOD(Run)(REFERENCE_TIME start) override;
|
||||
STDMETHOD(Stop)() override;
|
||||
|
||||
// IBaseFilter
|
||||
STDMETHOD(EnumPins)(IEnumPins** pins) override;
|
||||
STDMETHOD(FindPin)(LPCWSTR id, IPin** pin) override;
|
||||
STDMETHOD(QueryFilterInfo)(FILTER_INFO* info) override;
|
||||
STDMETHOD(JoinFilterGraph)(IFilterGraph* graph, LPCWSTR name) override;
|
||||
STDMETHOD(QueryVendorInfo)(LPWSTR* vendor_info) override;
|
||||
|
||||
protected:
|
||||
virtual ~CaptureSinkFilter();
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// class methods
|
||||
|
||||
void ProcessCapturedFrame(unsigned char* pBuffer, int32_t length,
|
||||
const VideoCaptureCapability& frameInfo);
|
||||
// explicit receiver lock aquisition and release
|
||||
void LockReceive() { m_crtRecv.Enter();}
|
||||
void UnlockReceive() {m_crtRecv.Leave();}
|
||||
// explicit filter lock aquisition and release
|
||||
void LockFilter() {m_crtFilter.Enter();}
|
||||
void UnlockFilter() { m_crtFilter.Leave(); }
|
||||
void SetFilterGraph(IGraphBuilder* graph); // Used if EVR
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// COM interfaces
|
||||
STDMETHODIMP QueryInterface(REFIID aIId, void **aInterface)
|
||||
{
|
||||
return mozilla::media::BaseFilter::QueryInterface(aIId, aInterface);
|
||||
}
|
||||
|
||||
STDMETHODIMP SetMatchingMediaType(const VideoCaptureCapability& capability);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// CBaseFilter methods
|
||||
int GetPinCount ();
|
||||
mozilla::media::BasePin * GetPin ( IN int Index);
|
||||
STDMETHODIMP Pause ();
|
||||
STDMETHODIMP Stop ();
|
||||
STDMETHODIMP GetClassID ( OUT CLSID * pCLSID);
|
||||
// --------------------------------------------------------------------
|
||||
// class factory calls this
|
||||
static IUnknown * CreateInstance (IN LPUNKNOWN punk, OUT HRESULT * phr);
|
||||
private:
|
||||
mozilla::CriticalSection m_crtFilter; // filter lock
|
||||
mozilla::CriticalSection m_crtRecv; // receiver lock; always acquire before filter lock
|
||||
CaptureInputPin * m_pInput;
|
||||
VideoCaptureExternal& _captureObserver;
|
||||
int32_t _moduleId;
|
||||
private:
|
||||
rtc::ThreadChecker main_checker_;
|
||||
const rtc::scoped_refptr<ComRefCount<CaptureInputPin>> input_pin_;
|
||||
VideoCaptureImpl* const capture_observer_;
|
||||
FILTER_INFO info_ RTC_GUARDED_BY(main_checker_) = {};
|
||||
// Set/cleared in JoinFilterGraph. The filter must be stopped (no capture)
|
||||
// at that time, so no lock is required. While the state is not stopped,
|
||||
// the sink will be used from the capture thread.
|
||||
IMediaEventSink* sink_ = nullptr;
|
||||
FILTER_STATE state_ RTC_GUARDED_BY(main_checker_) = State_Stopped;
|
||||
};
|
||||
} // namespace videocapturemodule
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -15,15 +15,14 @@
|
|||
#include "modules/video_capture/windows/sink_filter_ds.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
#include <Dvdmedia.h> // VIDEOINFOHEADER2
|
||||
#include <dvdmedia.h> // VIDEOINFOHEADER2
|
||||
|
||||
namespace webrtc {
|
||||
namespace videocapturemodule {
|
||||
VideoCaptureDS::VideoCaptureDS()
|
||||
: VideoCaptureImpl(), _dsInfo(), _captureFilter(NULL),
|
||||
: _captureFilter(NULL),
|
||||
_graphBuilder(NULL),
|
||||
_mediaControl(NULL),
|
||||
_sinkFilter(NULL),
|
||||
_inputSendPin(NULL),
|
||||
_outputCapturePin(NULL),
|
||||
_dvFilter(NULL),
|
||||
|
@ -35,8 +34,8 @@ VideoCaptureDS::~VideoCaptureDS() {
|
|||
_mediaControl->Stop();
|
||||
}
|
||||
if (_graphBuilder) {
|
||||
if (_sinkFilter)
|
||||
_graphBuilder->RemoveFilter(_sinkFilter);
|
||||
if (sink_filter_)
|
||||
_graphBuilder->RemoveFilter(sink_filter_);
|
||||
if (_captureFilter)
|
||||
_graphBuilder->RemoveFilter(_captureFilter);
|
||||
if (_dvFilter)
|
||||
|
@ -46,7 +45,6 @@ VideoCaptureDS::~VideoCaptureDS() {
|
|||
RELEASE_AND_CLEAR(_outputCapturePin);
|
||||
|
||||
RELEASE_AND_CLEAR(_captureFilter); // release the capture device
|
||||
RELEASE_AND_CLEAR(_sinkFilter);
|
||||
RELEASE_AND_CLEAR(_dvFilter);
|
||||
|
||||
RELEASE_AND_CLEAR(_mediaControl);
|
||||
|
@ -95,34 +93,29 @@ int32_t VideoCaptureDS::Init(const char* deviceUniqueIdUTF8) {
|
|||
}
|
||||
|
||||
_outputCapturePin = GetOutputPin(_captureFilter, PIN_CATEGORY_CAPTURE);
|
||||
if (_outputCapturePin == NULL)
|
||||
{
|
||||
RTC_LOG(LS_ERROR) << "Failed to get output capture pin";
|
||||
if (!_outputCapturePin) {
|
||||
RTC_LOG(LS_INFO) << "Failed to get output capture pin";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create the sink filte used for receiving Captured frames.
|
||||
_sinkFilter = new CaptureSinkFilter(SINK_FILTER_NAME, NULL, &hr, *this, 0);
|
||||
if (hr != S_OK) {
|
||||
RTC_LOG(LS_INFO) << "Failed to create send filter";
|
||||
return -1;
|
||||
}
|
||||
_sinkFilter->AddRef();
|
||||
sink_filter_ = new ComRefCount<CaptureSinkFilter>(this);
|
||||
|
||||
hr = _graphBuilder->AddFilter(_sinkFilter, SINK_FILTER_NAME);
|
||||
hr = _graphBuilder->AddFilter(sink_filter_, SINK_FILTER_NAME);
|
||||
if (FAILED(hr)) {
|
||||
RTC_LOG(LS_INFO) << "Failed to add the send filter to the graph.";
|
||||
return -1;
|
||||
}
|
||||
_inputSendPin = GetInputPin(_sinkFilter);
|
||||
if (_inputSendPin == NULL)
|
||||
{
|
||||
RTC_LOG(LS_ERROR) << "Failed to get input send pin";
|
||||
|
||||
_inputSendPin = GetInputPin(sink_filter_);
|
||||
if (!_inputSendPin) {
|
||||
RTC_LOG(LS_INFO) << "Failed to get input send pin";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Temporary connect here.
|
||||
// This is done so that no one else can use the capture device.
|
||||
if (SetCameraOutputIfNeeded(_requestedCapability) != 0) {
|
||||
if (SetCameraOutput(_requestedCapability) != 0) {
|
||||
return -1;
|
||||
}
|
||||
hr = _mediaControl->Pause();
|
||||
|
@ -139,9 +132,13 @@ int32_t VideoCaptureDS::Init(const char* deviceUniqueIdUTF8) {
|
|||
int32_t VideoCaptureDS::StartCapture(const VideoCaptureCapability& capability) {
|
||||
rtc::CritScope cs(&_apiCs);
|
||||
|
||||
if (SetCameraOutputIfNeeded(capability) != 0) {
|
||||
if (capability != _requestedCapability) {
|
||||
DisconnectGraph();
|
||||
|
||||
if (SetCameraOutput(capability) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
HRESULT hr = _mediaControl->Run();
|
||||
if (FAILED(hr)) {
|
||||
RTC_LOG(LS_INFO) << "Failed to start the Capture device.";
|
||||
|
@ -153,13 +150,14 @@ int32_t VideoCaptureDS::StartCapture(const VideoCaptureCapability& capability) {
|
|||
int32_t VideoCaptureDS::StopCapture() {
|
||||
rtc::CritScope cs(&_apiCs);
|
||||
|
||||
HRESULT hr = _mediaControl->Stop();
|
||||
HRESULT hr = _mediaControl->Pause();
|
||||
if (FAILED(hr)) {
|
||||
RTC_LOG(LS_INFO) << "Failed to stop the capture graph. " << hr;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool VideoCaptureDS::CaptureStarted() {
|
||||
OAFilterState state = 0;
|
||||
HRESULT hr = _mediaControl->GetState(1000, &state);
|
||||
|
@ -169,14 +167,14 @@ bool VideoCaptureDS::CaptureStarted() {
|
|||
RTC_LOG(LS_INFO) << "CaptureStarted " << state;
|
||||
return state == State_Running;
|
||||
}
|
||||
|
||||
int32_t VideoCaptureDS::CaptureSettings(VideoCaptureCapability& settings) {
|
||||
settings = _requestedCapability;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t VideoCaptureDS::SetCameraOutputIfNeeded(
|
||||
const VideoCaptureCapability& requestedCapability)
|
||||
{
|
||||
int32_t VideoCaptureDS::SetCameraOutput(
|
||||
const VideoCaptureCapability& requestedCapability) {
|
||||
// Get the best matching capability
|
||||
VideoCaptureCapability capability;
|
||||
int32_t capabilityIndex;
|
||||
|
@ -188,16 +186,6 @@ int32_t VideoCaptureDS::SetCameraOutputIfNeeded(
|
|||
_deviceUniqueId, _requestedCapability, capability)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (capability != _activeCapability) {
|
||||
DisconnectGraph();
|
||||
// Store the new mode the camera actually selected
|
||||
_activeCapability = capability;
|
||||
} else {
|
||||
// Camera selected the same mode, nothing to do
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reduce the frame rate if possible.
|
||||
if (capability.maxFPS > requestedCapability.maxFPS) {
|
||||
capability.maxFPS = requestedCapability.maxFPS;
|
||||
|
@ -205,13 +193,6 @@ int32_t VideoCaptureDS::SetCameraOutputIfNeeded(
|
|||
capability.maxFPS = 30;
|
||||
}
|
||||
|
||||
return SetCameraOutput(capability, capabilityIndex);
|
||||
}
|
||||
|
||||
|
||||
int32_t VideoCaptureDS::SetCameraOutput(const VideoCaptureCapability& capability,
|
||||
int32_t capabilityIndex)
|
||||
{
|
||||
// Convert it to the windows capability index since they are not nexessary
|
||||
// the same
|
||||
VideoCaptureCapabilityWindows windowsCapability;
|
||||
|
@ -248,7 +229,7 @@ int32_t VideoCaptureDS::SetCameraOutput(const VideoCaptureCapability& capability
|
|||
}
|
||||
|
||||
// Set the sink filter to request this capability
|
||||
_sinkFilter->SetMatchingMediaType(capability);
|
||||
sink_filter_->SetRequestedCapability(capability);
|
||||
// Order the capture device to use this capability
|
||||
hr += streamConfig->SetFormat(pmt);
|
||||
|
||||
|
@ -293,6 +274,7 @@ int32_t VideoCaptureDS::DisconnectGraph() {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureDS::ConnectDVCamera() {
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
|
@ -334,7 +316,6 @@ HRESULT VideoCaptureDS::ConnectDVCamera() {
|
|||
RTC_LOG(LS_INFO) << "Failed to connect capture device to the send graph: "
|
||||
<< hr;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
|
|
@ -11,22 +11,20 @@
|
|||
#ifndef MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_VIDEO_CAPTURE_DS_H_
|
||||
#define MODULES_VIDEO_CAPTURE_MAIN_SOURCE_WINDOWS_VIDEO_CAPTURE_DS_H_
|
||||
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "modules/video_capture/video_capture_impl.h"
|
||||
#include "modules/video_capture/windows/device_info_ds.h"
|
||||
|
||||
#define CAPTURE_FILTER_NAME L"VideoCaptureFilter"
|
||||
#define SINK_FILTER_NAME L"SinkFilter"
|
||||
|
||||
namespace webrtc
|
||||
{
|
||||
namespace videocapturemodule
|
||||
{
|
||||
namespace webrtc {
|
||||
namespace videocapturemodule {
|
||||
// Forward declaraion
|
||||
class CaptureSinkFilter;
|
||||
|
||||
class VideoCaptureDS: public VideoCaptureImpl
|
||||
{
|
||||
public:
|
||||
class VideoCaptureDS : public VideoCaptureImpl {
|
||||
public:
|
||||
VideoCaptureDS();
|
||||
|
||||
virtual int32_t Init(const char* deviceUniqueIdUTF8);
|
||||
|
@ -36,9 +34,8 @@ public:
|
|||
* Start/Stop
|
||||
*
|
||||
*************************************************************************/
|
||||
virtual int32_t
|
||||
StartCapture(const VideoCaptureCapability& capability);
|
||||
virtual int32_t StopCapture();
|
||||
int32_t StartCapture(const VideoCaptureCapability& capability) override;
|
||||
int32_t StopCapture() override;
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
|
@ -46,29 +43,24 @@ public:
|
|||
*
|
||||
**************************************************************************/
|
||||
|
||||
virtual bool CaptureStarted();
|
||||
virtual int32_t CaptureSettings(VideoCaptureCapability& settings);
|
||||
bool CaptureStarted() override;
|
||||
int32_t CaptureSettings(VideoCaptureCapability& settings) override;
|
||||
|
||||
protected:
|
||||
virtual ~VideoCaptureDS();
|
||||
protected:
|
||||
~VideoCaptureDS() override;
|
||||
|
||||
// Help functions
|
||||
int32_t
|
||||
SetCameraOutputIfNeeded(const VideoCaptureCapability& requestedCapability);
|
||||
int32_t
|
||||
SetCameraOutput(const VideoCaptureCapability& requestedCapability,
|
||||
int32_t capabilityIndex);
|
||||
|
||||
int32_t SetCameraOutput(const VideoCaptureCapability& requestedCapability);
|
||||
int32_t DisconnectGraph();
|
||||
HRESULT VideoCaptureDS::ConnectDVCamera();
|
||||
HRESULT ConnectDVCamera();
|
||||
|
||||
DeviceInfoDS _dsInfo;
|
||||
VideoCaptureCapability _activeCapability;
|
||||
|
||||
IBaseFilter* _captureFilter;
|
||||
IGraphBuilder* _graphBuilder;
|
||||
IMediaControl* _mediaControl;
|
||||
CaptureSinkFilter* _sinkFilter;
|
||||
rtc::scoped_refptr<CaptureSinkFilter> sink_filter_;
|
||||
IPin* _inputSendPin;
|
||||
IPin* _outputCapturePin;
|
||||
|
||||
|
@ -76,7 +68,6 @@ protected:
|
|||
IBaseFilter* _dvFilter;
|
||||
IPin* _inputDvPin;
|
||||
IPin* _outputDvPin;
|
||||
|
||||
};
|
||||
} // namespace videocapturemodule
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -8,11 +8,9 @@
|
|||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "modules/video_capture/windows/video_capture_ds.h"
|
||||
#include "modules/video_capture/windows/video_capture_mf.h"
|
||||
#include "rtc_base/refcount.h"
|
||||
#include "rtc_base/refcountedobject.h"
|
||||
#include "rtc_base/scoped_ref_ptr.h"
|
||||
#include "rtc_base/ref_counted_object.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace videocapturemodule {
|
||||
|
@ -23,7 +21,8 @@ VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo() {
|
|||
return DeviceInfoDS::Create();
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create(const char* device_id) {
|
||||
rtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create(
|
||||
const char* device_id) {
|
||||
if (device_id == nullptr)
|
||||
return nullptr;
|
||||
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/video_capture/windows/video_capture_mf.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace videocapturemodule {
|
||||
|
||||
VideoCaptureMF::VideoCaptureMF() {}
|
||||
VideoCaptureMF::~VideoCaptureMF() {}
|
||||
|
||||
int32_t VideoCaptureMF::Init(const char* device_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t VideoCaptureMF::StartCapture(
|
||||
const VideoCaptureCapability& capability) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t VideoCaptureMF::StopCapture() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool VideoCaptureMF::CaptureStarted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t VideoCaptureMF::CaptureSettings(
|
||||
VideoCaptureCapability& settings) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace videocapturemodule
|
||||
} // namespace webrtc
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_VIDEO_CAPTURE_WINDOWS_VIDEO_CAPTURE_MF_H_
|
||||
#define MODULES_VIDEO_CAPTURE_WINDOWS_VIDEO_CAPTURE_MF_H_
|
||||
|
||||
#include "modules/video_capture/video_capture_impl.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace videocapturemodule {
|
||||
|
||||
// VideoCapture implementation that uses the Media Foundation API on Windows.
|
||||
// This will replace the DirectShow based implementation on Vista and higher.
|
||||
// TODO(tommi): Finish implementing and switch out the DS in the factory method
|
||||
// for supported platforms.
|
||||
class VideoCaptureMF : public VideoCaptureImpl {
|
||||
public:
|
||||
VideoCaptureMF();
|
||||
|
||||
int32_t Init(const char* device_id);
|
||||
|
||||
// Overrides from VideoCaptureImpl.
|
||||
virtual int32_t StartCapture(const VideoCaptureCapability& capability);
|
||||
virtual int32_t StopCapture();
|
||||
virtual bool CaptureStarted();
|
||||
virtual int32_t CaptureSettings(
|
||||
VideoCaptureCapability& settings); // NOLINT
|
||||
|
||||
protected:
|
||||
virtual ~VideoCaptureMF();
|
||||
};
|
||||
|
||||
} // namespace videocapturemodule
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_VIDEO_CAPTURE_WINDOWS_VIDEO_CAPTURE_MF_H_
|
Загрузка…
Ссылка в новой задаче