blob: 678b75899bc2cab149c593aa78be393869ec8470 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PACKAGES_CAMERA_CAMERA_WINDOWS_WINDOWS_TEST_MOCKS_H_
#define PACKAGES_CAMERA_CAMERA_WINDOWS_WINDOWS_TEST_MOCKS_H_
#include <flutter/method_call.h>
#include <flutter/method_result_functions.h>
#include <flutter/standard_method_codec.h>
#include <flutter/texture_registrar.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <mfcaptureengine.h>
#include "camera.h"
#include "camera_plugin.h"
#include "capture_controller.h"
#include "capture_controller_listener.h"
#include "capture_engine_listener.h"
namespace camera_windows {
namespace test {
namespace {
using flutter::EncodableMap;
using flutter::EncodableValue;
using ::testing::_;
class MockMethodResult : public flutter::MethodResult<> {
public:
~MockMethodResult() = default;
MOCK_METHOD(void, SuccessInternal, (const EncodableValue* result),
(override));
MOCK_METHOD(void, ErrorInternal,
(const std::string& error_code, const std::string& error_message,
const EncodableValue* details),
(override));
MOCK_METHOD(void, NotImplementedInternal, (), (override));
};
class MockBinaryMessenger : public flutter::BinaryMessenger {
public:
~MockBinaryMessenger() = default;
MOCK_METHOD(void, Send,
(const std::string& channel, const uint8_t* message,
size_t message_size, flutter::BinaryReply reply),
(const));
MOCK_METHOD(void, SetMessageHandler,
(const std::string& channel,
flutter::BinaryMessageHandler handler),
());
};
class MockTextureRegistrar : public flutter::TextureRegistrar {
public:
MockTextureRegistrar() {
ON_CALL(*this, RegisterTexture)
.WillByDefault([this](flutter::TextureVariant* texture) -> int64_t {
EXPECT_TRUE(texture);
this->texture_ = texture;
this->texture_id_ = 1000;
return this->texture_id_;
});
ON_CALL(*this, UnregisterTexture)
.WillByDefault([this](int64_t tid) -> bool {
if (tid == this->texture_id_) {
texture_ = nullptr;
this->texture_id_ = -1;
return true;
}
return false;
});
ON_CALL(*this, MarkTextureFrameAvailable)
.WillByDefault([this](int64_t tid) -> bool {
if (tid == this->texture_id_) {
return true;
}
return false;
});
}
~MockTextureRegistrar() { texture_ = nullptr; }
MOCK_METHOD(int64_t, RegisterTexture, (flutter::TextureVariant * texture),
(override));
MOCK_METHOD(bool, UnregisterTexture, (int64_t), (override));
MOCK_METHOD(bool, MarkTextureFrameAvailable, (int64_t), (override));
int64_t texture_id_ = -1;
flutter::TextureVariant* texture_ = nullptr;
};
class MockCameraFactory : public CameraFactory {
public:
MockCameraFactory() {
ON_CALL(*this, CreateCamera).WillByDefault([this]() {
assert(this->pending_camera_);
return std::move(this->pending_camera_);
});
}
~MockCameraFactory() = default;
// Disallow copy and move.
MockCameraFactory(const MockCameraFactory&) = delete;
MockCameraFactory& operator=(const MockCameraFactory&) = delete;
MOCK_METHOD(std::unique_ptr<Camera>, CreateCamera,
(const std::string& device_id), (override));
std::unique_ptr<Camera> pending_camera_;
};
class MockCamera : public Camera {
public:
MockCamera(const std::string& device_id)
: device_id_(device_id), Camera(device_id){};
~MockCamera() = default;
// Disallow copy and move.
MockCamera(const MockCamera&) = delete;
MockCamera& operator=(const MockCamera&) = delete;
MOCK_METHOD(void, OnCreateCaptureEngineSucceeded, (int64_t texture_id),
(override));
MOCK_METHOD(std::unique_ptr<flutter::MethodResult<>>, GetPendingResultByType,
(PendingResultType type));
MOCK_METHOD(void, OnCreateCaptureEngineFailed,
(CameraResult result, const std::string& error), (override));
MOCK_METHOD(void, OnStartPreviewSucceeded, (int32_t width, int32_t height),
(override));
MOCK_METHOD(void, OnStartPreviewFailed,
(CameraResult result, const std::string& error), (override));
MOCK_METHOD(void, OnResumePreviewSucceeded, (), (override));
MOCK_METHOD(void, OnResumePreviewFailed,
(CameraResult result, const std::string& error), (override));
MOCK_METHOD(void, OnPausePreviewSucceeded, (), (override));
MOCK_METHOD(void, OnPausePreviewFailed,
(CameraResult result, const std::string& error), (override));
MOCK_METHOD(void, OnStartRecordSucceeded, (), (override));
MOCK_METHOD(void, OnStartRecordFailed,
(CameraResult result, const std::string& error), (override));
MOCK_METHOD(void, OnStopRecordSucceeded, (const std::string& file_path),
(override));
MOCK_METHOD(void, OnStopRecordFailed,
(CameraResult result, const std::string& error), (override));
MOCK_METHOD(void, OnTakePictureSucceeded, (const std::string& file_path),
(override));
MOCK_METHOD(void, OnTakePictureFailed,
(CameraResult result, const std::string& error), (override));
MOCK_METHOD(void, OnVideoRecordSucceeded,
(const std::string& file_path, int64_t video_duration),
(override));
MOCK_METHOD(void, OnVideoRecordFailed,
(CameraResult result, const std::string& error), (override));
MOCK_METHOD(void, OnCaptureError,
(CameraResult result, const std::string& error), (override));
MOCK_METHOD(bool, HasDeviceId, (std::string & device_id), (const override));
MOCK_METHOD(bool, HasCameraId, (int64_t camera_id), (const override));
MOCK_METHOD(bool, AddPendingResult,
(PendingResultType type, std::unique_ptr<MethodResult<>> result),
(override));
MOCK_METHOD(bool, HasPendingResultByType, (PendingResultType type),
(const override));
MOCK_METHOD(camera_windows::CaptureController*, GetCaptureController, (),
(override));
MOCK_METHOD(bool, InitCamera,
(flutter::TextureRegistrar * texture_registrar,
flutter::BinaryMessenger* messenger, bool record_audio,
ResolutionPreset resolution_preset),
(override));
std::unique_ptr<CaptureController> capture_controller_;
std::unique_ptr<MethodResult<>> pending_result_;
std::string device_id_;
int64_t camera_id_ = -1;
};
class MockCaptureControllerFactory : public CaptureControllerFactory {
public:
MockCaptureControllerFactory(){};
virtual ~MockCaptureControllerFactory() = default;
// Disallow copy and move.
MockCaptureControllerFactory(const MockCaptureControllerFactory&) = delete;
MockCaptureControllerFactory& operator=(const MockCaptureControllerFactory&) =
delete;
MOCK_METHOD(std::unique_ptr<CaptureController>, CreateCaptureController,
(CaptureControllerListener * listener), (override));
};
class MockCaptureController : public CaptureController {
public:
~MockCaptureController() = default;
MOCK_METHOD(bool, InitCaptureDevice,
(flutter::TextureRegistrar * texture_registrar,
const std::string& device_id, bool record_audio,
ResolutionPreset resolution_preset),
(override));
MOCK_METHOD(uint32_t, GetPreviewWidth, (), (const override));
MOCK_METHOD(uint32_t, GetPreviewHeight, (), (const override));
// Actions
MOCK_METHOD(void, StartPreview, (), (override));
MOCK_METHOD(void, ResumePreview, (), (override));
MOCK_METHOD(void, PausePreview, (), (override));
MOCK_METHOD(void, StartRecord,
(const std::string& file_path, int64_t max_video_duration_ms),
(override));
MOCK_METHOD(void, StopRecord, (), (override));
MOCK_METHOD(void, TakePicture, (const std::string& file_path), (override));
};
// MockCameraPlugin extends CameraPlugin behaviour a bit to allow adding cameras
// without creating them first with create message handler and mocking static
// system calls
class MockCameraPlugin : public CameraPlugin {
public:
MockCameraPlugin(flutter::TextureRegistrar* texture_registrar,
flutter::BinaryMessenger* messenger)
: CameraPlugin(texture_registrar, messenger){};
// Creates a plugin instance with the given CameraFactory instance.
// Exists for unit testing with mock implementations.
MockCameraPlugin(flutter::TextureRegistrar* texture_registrar,
flutter::BinaryMessenger* messenger,
std::unique_ptr<CameraFactory> camera_factory)
: CameraPlugin(texture_registrar, messenger, std::move(camera_factory)){};
~MockCameraPlugin() = default;
// Disallow copy and move.
MockCameraPlugin(const MockCameraPlugin&) = delete;
MockCameraPlugin& operator=(const MockCameraPlugin&) = delete;
MOCK_METHOD(bool, EnumerateVideoCaptureDeviceSources,
(IMFActivate * **devices, UINT32* count), (override));
// Helper to add camera without creating it via CameraFactory for testing
// purposes
void AddCamera(std::unique_ptr<Camera> camera) {
cameras_.push_back(std::move(camera));
}
};
class MockCaptureSource : public IMFCaptureSource {
public:
MockCaptureSource(){};
~MockCaptureSource() = default;
// IUnknown
STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&ref_); }
// IUnknown
STDMETHODIMP_(ULONG) Release() {
LONG ref = InterlockedDecrement(&ref_);
if (ref == 0) {
delete this;
}
return ref;
}
// IUnknown
STDMETHODIMP_(HRESULT) QueryInterface(const IID& riid, void** ppv) {
*ppv = nullptr;
if (riid == IID_IMFCaptureSource) {
*ppv = static_cast<IMFCaptureSource*>(this);
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
MOCK_METHOD(HRESULT, GetCaptureDeviceSource,
(MF_CAPTURE_ENGINE_DEVICE_TYPE mfCaptureEngineDeviceType,
IMFMediaSource** ppMediaSource));
MOCK_METHOD(HRESULT, GetCaptureDeviceActivate,
(MF_CAPTURE_ENGINE_DEVICE_TYPE mfCaptureEngineDeviceType,
IMFActivate** ppActivate));
MOCK_METHOD(HRESULT, GetService,
(REFIID rguidService, REFIID riid, IUnknown** ppUnknown));
MOCK_METHOD(HRESULT, AddEffect,
(DWORD dwSourceStreamIndex, IUnknown* pUnknown));
MOCK_METHOD(HRESULT, RemoveEffect,
(DWORD dwSourceStreamIndex, IUnknown* pUnknown));
MOCK_METHOD(HRESULT, RemoveAllEffects, (DWORD dwSourceStreamIndex));
MOCK_METHOD(HRESULT, GetAvailableDeviceMediaType,
(DWORD dwSourceStreamIndex, DWORD dwMediaTypeIndex,
IMFMediaType** ppMediaType));
MOCK_METHOD(HRESULT, SetCurrentDeviceMediaType,
(DWORD dwSourceStreamIndex, IMFMediaType* pMediaType));
MOCK_METHOD(HRESULT, GetCurrentDeviceMediaType,
(DWORD dwSourceStreamIndex, IMFMediaType** ppMediaType));
MOCK_METHOD(HRESULT, GetDeviceStreamCount, (DWORD * pdwStreamCount));
MOCK_METHOD(HRESULT, GetDeviceStreamCategory,
(DWORD dwSourceStreamIndex,
MF_CAPTURE_ENGINE_STREAM_CATEGORY* pStreamCategory));
MOCK_METHOD(HRESULT, GetMirrorState,
(DWORD dwStreamIndex, BOOL* pfMirrorState));
MOCK_METHOD(HRESULT, SetMirrorState,
(DWORD dwStreamIndex, BOOL fMirrorState));
MOCK_METHOD(HRESULT, GetStreamIndexFromFriendlyName,
(UINT32 uifriendlyName, DWORD* pdwActualStreamIndex));
private:
volatile ULONG ref_ = 0;
};
// Uses IMFMediaSourceEx which has SetD3DManager method.
class MockMediaSource : public IMFMediaSourceEx {
public:
MockMediaSource(){};
~MockMediaSource() = default;
// IUnknown
STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&ref_); }
// IUnknown
STDMETHODIMP_(ULONG) Release() {
LONG ref = InterlockedDecrement(&ref_);
if (ref == 0) {
delete this;
}
return ref;
}
// IUnknown
STDMETHODIMP_(HRESULT) QueryInterface(const IID& riid, void** ppv) {
*ppv = nullptr;
if (riid == IID_IMFMediaSource) {
*ppv = static_cast<IMFMediaSource*>(this);
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
// IMFMediaSource
HRESULT GetCharacteristics(DWORD* dwCharacteristics) override {
return E_NOTIMPL;
}
// IMFMediaSource
HRESULT CreatePresentationDescriptor(
IMFPresentationDescriptor** presentationDescriptor) override {
return E_NOTIMPL;
}
// IMFMediaSource
HRESULT Start(IMFPresentationDescriptor* presentationDescriptor,
const GUID* guidTimeFormat,
const PROPVARIANT* varStartPosition) override {
return E_NOTIMPL;
}
// IMFMediaSource
HRESULT Stop(void) override { return E_NOTIMPL; }
// IMFMediaSource
HRESULT Pause(void) override { return E_NOTIMPL; }
// IMFMediaSource
HRESULT Shutdown(void) override { return E_NOTIMPL; }
// IMFMediaEventGenerator
HRESULT GetEvent(DWORD dwFlags, IMFMediaEvent** event) override {
return E_NOTIMPL;
}
// IMFMediaEventGenerator
HRESULT BeginGetEvent(IMFAsyncCallback* callback,
IUnknown* unkState) override {
return E_NOTIMPL;
}
// IMFMediaEventGenerator
HRESULT EndGetEvent(IMFAsyncResult* result, IMFMediaEvent** event) override {
return E_NOTIMPL;
}
// IMFMediaEventGenerator
HRESULT QueueEvent(MediaEventType met, REFGUID guidExtendedType,
HRESULT hrStatus, const PROPVARIANT* value) override {
return E_NOTIMPL;
}
// IMFMediaSourceEx
HRESULT GetSourceAttributes(IMFAttributes** attributes) { return E_NOTIMPL; }
// IMFMediaSourceEx
HRESULT GetStreamAttributes(DWORD stream_id, IMFAttributes** attributes) {
return E_NOTIMPL;
}
// IMFMediaSourceEx
HRESULT SetD3DManager(IUnknown* manager) { return S_OK; }
private:
volatile ULONG ref_ = 0;
};
class MockCapturePreviewSink : public IMFCapturePreviewSink {
public:
// IMFCaptureSink
MOCK_METHOD(HRESULT, GetOutputMediaType,
(DWORD dwSinkStreamIndex, IMFMediaType** ppMediaType));
// IMFCaptureSink
MOCK_METHOD(HRESULT, GetService,
(DWORD dwSinkStreamIndex, REFGUID rguidService, REFIID riid,
IUnknown** ppUnknown));
// IMFCaptureSink
MOCK_METHOD(HRESULT, AddStream,
(DWORD dwSourceStreamIndex, IMFMediaType* pMediaType,
IMFAttributes* pAttributes, DWORD* pdwSinkStreamIndex));
// IMFCaptureSink
MOCK_METHOD(HRESULT, Prepare, ());
// IMFCaptureSink
MOCK_METHOD(HRESULT, RemoveAllStreams, ());
// IMFCapturePreviewSink
MOCK_METHOD(HRESULT, SetRenderHandle, (HANDLE handle));
// IMFCapturePreviewSink
MOCK_METHOD(HRESULT, SetRenderSurface, (IUnknown * pSurface));
// IMFCapturePreviewSink
MOCK_METHOD(HRESULT, UpdateVideo,
(const MFVideoNormalizedRect* pSrc, const RECT* pDst,
const COLORREF* pBorderClr));
// IMFCapturePreviewSink
MOCK_METHOD(HRESULT, SetSampleCallback,
(DWORD dwStreamSinkIndex,
IMFCaptureEngineOnSampleCallback* pCallback));
// IMFCapturePreviewSink
MOCK_METHOD(HRESULT, GetMirrorState, (BOOL * pfMirrorState));
// IMFCapturePreviewSink
MOCK_METHOD(HRESULT, SetMirrorState, (BOOL fMirrorState));
// IMFCapturePreviewSink
MOCK_METHOD(HRESULT, GetRotation,
(DWORD dwStreamIndex, DWORD* pdwRotationValue));
// IMFCapturePreviewSink
MOCK_METHOD(HRESULT, SetRotation,
(DWORD dwStreamIndex, DWORD dwRotationValue));
// IMFCapturePreviewSink
MOCK_METHOD(HRESULT, SetCustomSink, (IMFMediaSink * pMediaSink));
// IUnknown
STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&ref_); }
// IUnknown
STDMETHODIMP_(ULONG) Release() {
LONG ref = InterlockedDecrement(&ref_);
if (ref == 0) {
delete this;
}
return ref;
}
// IUnknown
STDMETHODIMP_(HRESULT) QueryInterface(const IID& riid, void** ppv) {
*ppv = nullptr;
if (riid == IID_IMFCapturePreviewSink) {
*ppv = static_cast<IMFCapturePreviewSink*>(this);
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
void SendFakeSample(uint8_t* src_buffer, uint32_t size) {
assert(sample_callback_);
ComPtr<IMFSample> sample;
ComPtr<IMFMediaBuffer> buffer;
HRESULT hr = MFCreateSample(&sample);
if (SUCCEEDED(hr)) {
hr = MFCreateMemoryBuffer(size, &buffer);
}
if (SUCCEEDED(hr)) {
uint8_t* target_data;
if (SUCCEEDED(buffer->Lock(&target_data, nullptr, nullptr))) {
std::copy(src_buffer, src_buffer + size, target_data);
}
hr = buffer->Unlock();
}
if (SUCCEEDED(hr)) {
hr = buffer->SetCurrentLength(size);
}
if (SUCCEEDED(hr)) {
hr = sample->AddBuffer(buffer.Get());
}
if (SUCCEEDED(hr)) {
sample_callback_->OnSample(sample.Get());
}
}
ComPtr<IMFCaptureEngineOnSampleCallback> sample_callback_;
private:
~MockCapturePreviewSink() = default;
volatile ULONG ref_ = 0;
};
class MockCaptureRecordSink : public IMFCaptureRecordSink {
public:
// IMFCaptureSink
MOCK_METHOD(HRESULT, GetOutputMediaType,
(DWORD dwSinkStreamIndex, IMFMediaType** ppMediaType));
// IMFCaptureSink
MOCK_METHOD(HRESULT, GetService,
(DWORD dwSinkStreamIndex, REFGUID rguidService, REFIID riid,
IUnknown** ppUnknown));
// IMFCaptureSink
MOCK_METHOD(HRESULT, AddStream,
(DWORD dwSourceStreamIndex, IMFMediaType* pMediaType,
IMFAttributes* pAttributes, DWORD* pdwSinkStreamIndex));
// IMFCaptureSink
MOCK_METHOD(HRESULT, Prepare, ());
// IMFCaptureSink
MOCK_METHOD(HRESULT, RemoveAllStreams, ());
// IMFCaptureRecordSink
MOCK_METHOD(HRESULT, SetOutputByteStream,
(IMFByteStream * pByteStream, REFGUID guidContainerType));
// IMFCaptureRecordSink
MOCK_METHOD(HRESULT, SetOutputFileName, (LPCWSTR fileName));
// IMFCaptureRecordSink
MOCK_METHOD(HRESULT, SetSampleCallback,
(DWORD dwStreamSinkIndex,
IMFCaptureEngineOnSampleCallback* pCallback));
// IMFCaptureRecordSink
MOCK_METHOD(HRESULT, SetCustomSink, (IMFMediaSink * pMediaSink));
// IMFCaptureRecordSink
MOCK_METHOD(HRESULT, GetRotation,
(DWORD dwStreamIndex, DWORD* pdwRotationValue));
// IMFCaptureRecordSink
MOCK_METHOD(HRESULT, SetRotation,
(DWORD dwStreamIndex, DWORD dwRotationValue));
// IUnknown
STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&ref_); }
// IUnknown
STDMETHODIMP_(ULONG) Release() {
LONG ref = InterlockedDecrement(&ref_);
if (ref == 0) {
delete this;
}
return ref;
}
// IUnknown
STDMETHODIMP_(HRESULT) QueryInterface(const IID& riid, void** ppv) {
*ppv = nullptr;
if (riid == IID_IMFCaptureRecordSink) {
*ppv = static_cast<IMFCaptureRecordSink*>(this);
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
private:
~MockCaptureRecordSink() = default;
volatile ULONG ref_ = 0;
};
class MockCapturePhotoSink : public IMFCapturePhotoSink {
public:
// IMFCaptureSink
MOCK_METHOD(HRESULT, GetOutputMediaType,
(DWORD dwSinkStreamIndex, IMFMediaType** ppMediaType));
// IMFCaptureSink
MOCK_METHOD(HRESULT, GetService,
(DWORD dwSinkStreamIndex, REFGUID rguidService, REFIID riid,
IUnknown** ppUnknown));
// IMFCaptureSink
MOCK_METHOD(HRESULT, AddStream,
(DWORD dwSourceStreamIndex, IMFMediaType* pMediaType,
IMFAttributes* pAttributes, DWORD* pdwSinkStreamIndex));
// IMFCaptureSink
MOCK_METHOD(HRESULT, Prepare, ());
// IMFCaptureSink
MOCK_METHOD(HRESULT, RemoveAllStreams, ());
// IMFCapturePhotoSink
MOCK_METHOD(HRESULT, SetOutputFileName, (LPCWSTR fileName));
// IMFCapturePhotoSink
MOCK_METHOD(HRESULT, SetSampleCallback,
(IMFCaptureEngineOnSampleCallback * pCallback));
// IMFCapturePhotoSink
MOCK_METHOD(HRESULT, SetOutputByteStream, (IMFByteStream * pByteStream));
// IUnknown
STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&ref_); }
// IUnknown
STDMETHODIMP_(ULONG) Release() {
LONG ref = InterlockedDecrement(&ref_);
if (ref == 0) {
delete this;
}
return ref;
}
// IUnknown
STDMETHODIMP_(HRESULT) QueryInterface(const IID& riid, void** ppv) {
*ppv = nullptr;
if (riid == IID_IMFCapturePhotoSink) {
*ppv = static_cast<IMFCapturePhotoSink*>(this);
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
private:
~MockCapturePhotoSink() = default;
volatile ULONG ref_ = 0;
};
template <class T>
class FakeIMFAttributesBase : public T {
static_assert(std::is_base_of<IMFAttributes, T>::value,
"I must inherit from IMFAttributes");
// IIMFAttributes
HRESULT GetItem(REFGUID guidKey, PROPVARIANT* pValue) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT CompareItem(REFGUID guidKey, REFPROPVARIANT Value,
BOOL* pbResult) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT Compare(IMFAttributes* pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType,
BOOL* pbResult) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT GetUINT32(REFGUID guidKey, UINT32* punValue) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT GetUINT64(REFGUID guidKey, UINT64* punValue) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT GetDouble(REFGUID guidKey, double* pfValue) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT GetGUID(REFGUID guidKey, GUID* pguidValue) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT GetStringLength(REFGUID guidKey, UINT32* pcchLength) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize,
UINT32* pcchLength) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue,
UINT32* pcchLength) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize,
UINT32* pcbBlobSize) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf,
UINT32* pcbSize) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT GetUnknown(REFGUID guidKey, REFIID riid,
__RPC__deref_out_opt LPVOID* ppv) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT SetItem(REFGUID guidKey, REFPROPVARIANT Value) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT DeleteItem(REFGUID guidKey) override { return E_NOTIMPL; }
// IIMFAttributes
HRESULT DeleteAllItems(void) override { return E_NOTIMPL; }
// IIMFAttributes
HRESULT SetUINT32(REFGUID guidKey, UINT32 unValue) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT SetUINT64(REFGUID guidKey, UINT64 unValue) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT SetDouble(REFGUID guidKey, double fValue) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT SetGUID(REFGUID guidKey, REFGUID guidValue) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT SetString(REFGUID guidKey, LPCWSTR wszValue) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT SetBlob(REFGUID guidKey, const UINT8* pBuf,
UINT32 cbBufSize) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT SetUnknown(REFGUID guidKey, IUnknown* pUnknown) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT LockStore(void) override { return E_NOTIMPL; }
// IIMFAttributes
HRESULT UnlockStore(void) override { return E_NOTIMPL; }
// IIMFAttributes
HRESULT GetCount(UINT32* pcItems) override { return E_NOTIMPL; }
// IIMFAttributes
HRESULT GetItemByIndex(UINT32 unIndex, GUID* pguidKey,
PROPVARIANT* pValue) override {
return E_NOTIMPL;
}
// IIMFAttributes
HRESULT CopyAllItems(IMFAttributes* pDest) override { return E_NOTIMPL; }
};
class FakeMediaType : public FakeIMFAttributesBase<IMFMediaType> {
public:
FakeMediaType(GUID major_type, GUID sub_type, int width, int height)
: major_type_(major_type),
sub_type_(sub_type),
width_(width),
height_(height){};
// IMFAttributes
HRESULT GetUINT64(REFGUID key, UINT64* value) override {
if (key == MF_MT_FRAME_SIZE) {
*value = (int64_t)width_ << 32 | (int64_t)height_;
return S_OK;
} else if (key == MF_MT_FRAME_RATE) {
*value = (int64_t)frame_rate_ << 32 | 1;
return S_OK;
}
return E_FAIL;
};
// IMFAttributes
HRESULT GetGUID(REFGUID key, GUID* value) override {
if (key == MF_MT_MAJOR_TYPE) {
*value = major_type_;
return S_OK;
} else if (key == MF_MT_SUBTYPE) {
*value = sub_type_;
return S_OK;
}
return E_FAIL;
}
// IIMFAttributes
HRESULT CopyAllItems(IMFAttributes* pDest) override {
pDest->SetUINT64(MF_MT_FRAME_SIZE,
(int64_t)width_ << 32 | (int64_t)height_);
pDest->SetUINT64(MF_MT_FRAME_RATE, (int64_t)frame_rate_ << 32 | 1);
pDest->SetGUID(MF_MT_MAJOR_TYPE, major_type_);
pDest->SetGUID(MF_MT_SUBTYPE, sub_type_);
return S_OK;
}
// IMFMediaType
HRESULT STDMETHODCALLTYPE GetMajorType(GUID* pguidMajorType) override {
return E_NOTIMPL;
};
// IMFMediaType
HRESULT STDMETHODCALLTYPE IsCompressedFormat(BOOL* pfCompressed) override {
return E_NOTIMPL;
}
// IMFMediaType
HRESULT STDMETHODCALLTYPE IsEqual(IMFMediaType* pIMediaType,
DWORD* pdwFlags) override {
return E_NOTIMPL;
}
// IMFMediaType
HRESULT STDMETHODCALLTYPE GetRepresentation(
GUID guidRepresentation, LPVOID* ppvRepresentation) override {
return E_NOTIMPL;
}
// IMFMediaType
HRESULT STDMETHODCALLTYPE FreeRepresentation(
GUID guidRepresentation, LPVOID pvRepresentation) override {
return E_NOTIMPL;
}
// IUnknown
STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&ref_); }
// IUnknown
STDMETHODIMP_(ULONG) Release() {
LONG ref = InterlockedDecrement(&ref_);
if (ref == 0) {
delete this;
}
return ref;
}
// IUnknown
STDMETHODIMP_(HRESULT) QueryInterface(const IID& riid, void** ppv) {
*ppv = nullptr;
if (riid == IID_IMFMediaType) {
*ppv = static_cast<IMFMediaType*>(this);
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
private:
~FakeMediaType() = default;
volatile ULONG ref_ = 0;
const GUID major_type_;
const GUID sub_type_;
const int width_;
const int height_;
const int frame_rate_ = 30;
};
class MockCaptureEngine : public IMFCaptureEngine {
public:
MockCaptureEngine() {
ON_CALL(*this, Initialize)
.WillByDefault([this](IMFCaptureEngineOnEventCallback* callback,
IMFAttributes* attributes, IUnknown* audioSource,
IUnknown* videoSource) -> HRESULT {
EXPECT_TRUE(callback);
EXPECT_TRUE(attributes);
EXPECT_TRUE(videoSource);
// audioSource is allowed to be nullptr;
callback_ = callback;
videoSource_ = reinterpret_cast<IMFMediaSource*>(videoSource);
audioSource_ = reinterpret_cast<IMFMediaSource*>(audioSource);
initialized_ = true;
return S_OK;
});
};
virtual ~MockCaptureEngine() = default;
MOCK_METHOD(HRESULT, Initialize,
(IMFCaptureEngineOnEventCallback * callback,
IMFAttributes* attributes, IUnknown* audioSource,
IUnknown* videoSource));
MOCK_METHOD(HRESULT, StartPreview, ());
MOCK_METHOD(HRESULT, StopPreview, ());
MOCK_METHOD(HRESULT, StartRecord, ());
MOCK_METHOD(HRESULT, StopRecord,
(BOOL finalize, BOOL flushUnprocessedSamples));
MOCK_METHOD(HRESULT, TakePhoto, ());
MOCK_METHOD(HRESULT, GetSink,
(MF_CAPTURE_ENGINE_SINK_TYPE type, IMFCaptureSink** sink));
MOCK_METHOD(HRESULT, GetSource, (IMFCaptureSource * *ppSource));
// IUnknown
STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&ref_); }
// IUnknown
STDMETHODIMP_(ULONG) Release() {
LONG ref = InterlockedDecrement(&ref_);
if (ref == 0) {
delete this;
}
return ref;
}
// IUnknown
STDMETHODIMP_(HRESULT) QueryInterface(const IID& riid, void** ppv) {
*ppv = nullptr;
if (riid == IID_IMFCaptureEngine) {
*ppv = static_cast<IMFCaptureEngine*>(this);
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
void CreateFakeEvent(HRESULT hrStatus, GUID event_type) {
EXPECT_TRUE(initialized_);
ComPtr<IMFMediaEvent> event;
MFCreateMediaEvent(MEExtendedType, event_type, hrStatus, nullptr, &event);
if (callback_) {
callback_->OnEvent(event.Get());
}
}
ComPtr<IMFCaptureEngineOnEventCallback> callback_;
ComPtr<IMFMediaSource> videoSource_;
ComPtr<IMFMediaSource> audioSource_;
volatile ULONG ref_ = 0;
bool initialized_ = false;
};
#define MOCK_DEVICE_ID "mock_device_id"
#define MOCK_CAMERA_NAME "mock_camera_name <" MOCK_DEVICE_ID ">"
#define MOCK_INVALID_CAMERA_NAME "invalid_camera_name"
} // namespace
} // namespace test
} // namespace camera_windows
#endif // PACKAGES_CAMERA_CAMERA_WINDOWS_WINDOWS_TEST_MOCKS_H_