Commit cb078a8a authored by Réda Housni Alaoui's avatar Réda Housni Alaoui Committed by Commit Bot

Reland: Win video capture: use IMFCaptureEngine for Media Foundation

Fixes for reland number 6:
- "Win10 Tester" capture_unittests failure
- "Win8 Tester" capture_unittests failure

Fixes for reland number 5:
- "Win10 Tester" browser_tests_functional failure
- "Win8 Tester" browser_tests_functional failure

Fixes for reland number 4:
- "Win10 Tester" browser_tests_functional failure
- "Win8 Tester" browser_tests_functional failure
- "Win8 Tester" capture_unittests failure

Fixes for reland number 3:
- "Win10 Tester" browser_tests_functional failure
- "Win10 Tester" capture_unittests failure
- "Win8 Tester" browser_tests_functional failure
- "Win8 Tester" capture_unittests failure

Fixes for reland number 2:
- "Win10 Tester" browser_tests_functional failure
- "Win10 Tester" capture_unittests failure
- "Win8 Tester" browser_tests_functional failure
- "Win8 Tester" capture_unittests failure

Fixes for reland number 1:
- "Win8 Tester" browser_tests_functional failure
- "Win8 Tester" capture_unittests failure

Original description:
- Full rewrite of the MediaFoundation implementation video part to use
IMFCaptureEngine
- Implementation of takePhoto, setPhotoOptions and getPhotoCapabilities
- takePhoto triggers a still image capture with the highest available
resolution without stopping the video stream thanks to IMFCaptureEngine

TEST=adapted video_capture_device_unittest.cc and
webrtc_image_capture_browsertest.cc; launch Chrome with
--force-mediafoundation on Win8+ and capture video using
e.g. https://webrtc.github.io/samples/src/content/getusermedia/gum/

R=mcasas@chromium.org

Bug: 730068
Change-Id: I7b7ff88f2db8d71f46428a2ecbb733e18a25a334
Reviewed-on: https://chromium-review.googlesource.com/734042
Commit-Queue: Christian Fremerey <chfremer@chromium.org>
Reviewed-by: default avatarMiguel Casas <mcasas@chromium.org>
Reviewed-by: default avatarChristian Fremerey <chfremer@chromium.org>
Cr-Original-Original-Original-Original-Original-Commit-Position: refs/heads/master@{#521435}
Reviewed-on: https://chromium-review.googlesource.com/810766
Cr-Original-Original-Original-Original-Commit-Position: refs/heads/master@{#524417}
Reviewed-on: https://chromium-review.googlesource.com/843974
Cr-Original-Original-Original-Commit-Position: refs/heads/master@{#527139}
Reviewed-on: https://chromium-review.googlesource.com/852455
Commit-Queue: Miguel Casas <mcasas@chromium.org>
Cr-Original-Original-Commit-Position: refs/heads/master@{#528005}
Reviewed-on: https://chromium-review.googlesource.com/858138
Cr-Original-Commit-Position: refs/heads/master@{#531109}
Reviewed-on: https://chromium-review.googlesource.com/885815
Cr-Commit-Position: refs/heads/master@{#532040}
parent 64262b5a
......@@ -69,6 +69,16 @@ static struct TargetVideoCaptureStack {
#endif
};
enum class TargetVideoCaptureImplementation {
DEFAULT,
#if defined(OS_WIN)
WIN_MEDIA_FOUNDATION
#endif
};
const TargetVideoCaptureImplementation
kTargetVideoCaptureImplementationsForFakeDevice[] = {
TargetVideoCaptureImplementation::DEFAULT};
} // namespace
// This class is the content_browsertests for Image Capture API, which allows
......@@ -134,7 +144,9 @@ class WebRtcImageCaptureBrowserTestBase
class WebRtcImageCaptureSucceedsBrowserTest
: public WebRtcImageCaptureBrowserTestBase,
public testing::WithParamInterface<
std::tuple<TargetCamera, TargetVideoCaptureStack>> {
std::tuple<TargetCamera,
TargetVideoCaptureStack,
TargetVideoCaptureImplementation>> {
public:
WebRtcImageCaptureSucceedsBrowserTest() {
if (std::get<1>(GetParam()).use_video_capture_service) {
......@@ -154,6 +166,16 @@ class WebRtcImageCaptureSucceedsBrowserTest
ASSERT_TRUE(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseFakeDeviceForMediaStream));
}
#if defined(OS_WIN)
if (std::get<2>(GetParam()) ==
TargetVideoCaptureImplementation::WIN_MEDIA_FOUNDATION) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kForceMediaFoundationVideoCapture);
ASSERT_TRUE(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceMediaFoundationVideoCapture));
}
#endif
}
bool RunImageCaptureTestCase(const std::string& command) override {
......@@ -220,21 +242,35 @@ INSTANTIATE_TEST_CASE_P(
, // Use no prefix, so that these get picked up when using
// --gtest_filter=WebRtc*
WebRtcImageCaptureSucceedsBrowserTest,
testing::Combine(testing::Values(TargetCamera::FAKE_DEVICE),
testing::ValuesIn(kTargetVideoCaptureStacks)));
testing::Combine(
testing::Values(TargetCamera::FAKE_DEVICE),
testing::ValuesIn(kTargetVideoCaptureStacks),
testing::ValuesIn(kTargetVideoCaptureImplementationsForFakeDevice)));
// Tests on real webcam can only run on platforms for which the image capture
// API has already been implemented.
// Note, these tests must be run sequentially, since multiple parallel test runs
// competing for a single physical webcam typically causes failures.
#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_ANDROID)
#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_ANDROID) || \
defined(OS_WIN)
const TargetVideoCaptureImplementation
kTargetVideoCaptureImplementationsForRealWebcam[] = {
TargetVideoCaptureImplementation::DEFAULT,
#if defined(OS_WIN)
TargetVideoCaptureImplementation::WIN_MEDIA_FOUNDATION
#endif
};
INSTANTIATE_TEST_CASE_P(
UsingRealWebcam, // This prefix can be used with --gtest_filter to
// distinguish the tests using a real camera from the ones
// that don't.
WebRtcImageCaptureSucceedsBrowserTest,
testing::Combine(testing::Values(TargetCamera::REAL_WEBCAM),
testing::ValuesIn(kTargetVideoCaptureStacks)));
testing::Combine(
testing::Values(TargetCamera::REAL_WEBCAM),
testing::ValuesIn(kTargetVideoCaptureStacks),
testing::ValuesIn(kTargetVideoCaptureImplementationsForRealWebcam)));
#endif
// Test fixture template for setting up a fake device with a custom
......
......@@ -6,7 +6,7 @@
<body>
<script type="text/javascript" src="webrtc_test_utilities.js"></script>
<script>
const WIDTH = 320;
const WIDTH = 640;
/** @const */ var CONSTRAINTS = { width: { max : WIDTH } };
// Returns a Promise resolved with |object| after a delay of |delayInMs|.
......
......@@ -28,9 +28,11 @@
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
#include <mfcaptureengine.h>
#include "base/win/scoped_com_initializer.h"
#include "base/win/windows_version.h" // For fine-grained suppression.
#include "media/capture/video/win/video_capture_device_factory_win.h"
#include "media/capture/video/win/video_capture_device_mf_win.h"
#endif
#if defined(OS_MACOSX)
......@@ -86,9 +88,16 @@
#define MAYBE_GetPhotoState DISABLED_GetPhotoState
#endif
// Wrap the TEST_P macro into another one to allow to preprocess |test_name|
// macros. Needed until https://github.com/google/googletest/issues/389 is
// fixed.
#define WRAPPED_TEST_P(test_case_name, test_name) \
TEST_P(test_case_name, test_name)
using ::testing::_;
using ::testing::Invoke;
using ::testing::SaveArg;
using ::testing::Return;
namespace media {
namespace {
......@@ -114,6 +123,35 @@ static bool IsDeviceUsableForTesting(
};
#endif
enum VideoCaptureImplementationTweak {
NONE,
#if defined(OS_WIN)
WIN_MEDIA_FOUNDATION
#endif
};
#if defined(OS_WIN)
class MockMFPhotoCallback final : public IMFCaptureEngineOnSampleCallback {
public:
~MockMFPhotoCallback() {}
MOCK_METHOD2(DoQueryInterface, HRESULT(REFIID, void**));
MOCK_METHOD0(DoAddRef, ULONG(void));
MOCK_METHOD0(DoRelease, ULONG(void));
MOCK_METHOD1(DoOnSample, HRESULT(IMFSample*));
STDMETHOD(QueryInterface)(REFIID riid, void** object) override {
return DoQueryInterface(riid, object);
}
STDMETHOD_(ULONG, AddRef)() override { return DoAddRef(); }
STDMETHOD_(ULONG, Release)() override { return DoRelease(); }
STDMETHOD(OnSample)(IMFSample* sample) override { return DoOnSample(sample); }
};
#endif
class MockVideoCaptureClient : public VideoCaptureDevice::Client {
public:
MOCK_METHOD0(DoReserveOutputBuffer, void(void));
......@@ -226,7 +264,19 @@ class MockImageCaptureClient
} // namespace
class VideoCaptureDeviceTest : public testing::TestWithParam<gfx::Size> {
class VideoCaptureDeviceTest
: public testing::TestWithParam<
std::tuple<gfx::Size, VideoCaptureImplementationTweak>> {
public:
#if defined(OS_WIN)
scoped_refptr<IMFCaptureEngineOnSampleCallback> CreateMockPhotoCallback(
MockMFPhotoCallback* mock_photo_callback,
VideoCaptureDevice::TakePhotoCallback callback,
VideoCaptureFormat format) {
return scoped_refptr<IMFCaptureEngineOnSampleCallback>(mock_photo_callback);
}
#endif
protected:
typedef VideoCaptureDevice::Client Client;
......@@ -259,6 +309,10 @@ class VideoCaptureDeviceTest : public testing::TestWithParam<gfx::Size> {
static_cast<VideoCaptureDeviceFactoryAndroid*>(
video_capture_device_factory_.get())
->ConfigureForTesting();
#elif defined(OS_WIN)
static_cast<VideoCaptureDeviceFactoryWin*>(
video_capture_device_factory_.get())
->set_use_media_foundation_for_testing(UseWinMediaFoundation());
#endif
EXPECT_CALL(*video_capture_client_, DoReserveOutputBuffer()).Times(0);
EXPECT_CALL(*video_capture_client_, DoOnIncomingCapturedBuffer()).Times(0);
......@@ -266,6 +320,12 @@ class VideoCaptureDeviceTest : public testing::TestWithParam<gfx::Size> {
.Times(0);
}
#if defined(OS_WIN)
bool UseWinMediaFoundation() {
return std::get<1>(GetParam()) == WIN_MEDIA_FOUNDATION;
}
#endif
void ResetWithNewClient() {
video_capture_client_.reset(new MockVideoCaptureClient(base::Bind(
&VideoCaptureDeviceTest::OnFrameCaptured, base::Unretained(this))));
......@@ -380,7 +440,7 @@ class VideoCaptureDeviceTest : public testing::TestWithParam<gfx::Size> {
#define MAYBE_OpenInvalidDevice OpenInvalidDevice
#endif
// Tries to allocate an invalid device and verifies it doesn't work.
TEST_F(VideoCaptureDeviceTest, MAYBE_OpenInvalidDevice) {
WRAPPED_TEST_P(VideoCaptureDeviceTest, MAYBE_OpenInvalidDevice) {
VideoCaptureDeviceDescriptor invalid_descriptor;
invalid_descriptor.device_id = "jibberish";
invalid_descriptor.display_name = "jibberish";
......@@ -412,12 +472,12 @@ TEST_F(VideoCaptureDeviceTest, MAYBE_OpenInvalidDevice) {
}
// Allocates the first enumerated device, and expects a frame.
TEST_P(VideoCaptureDeviceTest, CaptureWithSize) {
WRAPPED_TEST_P(VideoCaptureDeviceTest, CaptureWithSize) {
const auto descriptor = FindUsableDeviceDescriptor();
if (!descriptor)
return;
const gfx::Size& size = GetParam();
const gfx::Size& size = std::get<0>(GetParam());
if (!IsCaptureSizeSupported(*descriptor, size))
return;
const int width = size.width();
......@@ -447,14 +507,22 @@ TEST_P(VideoCaptureDeviceTest, CaptureWithSize) {
}
const gfx::Size kCaptureSizes[] = {gfx::Size(640, 480), gfx::Size(1280, 720)};
const VideoCaptureImplementationTweak kCaptureImplementationTweaks[] = {
NONE,
#if defined(OS_WIN)
WIN_MEDIA_FOUNDATION
#endif
};
INSTANTIATE_TEST_CASE_P(VideoCaptureDeviceTests,
INSTANTIATE_TEST_CASE_P(
VideoCaptureDeviceTests,
VideoCaptureDeviceTest,
testing::ValuesIn(kCaptureSizes));
testing::Combine(testing::ValuesIn(kCaptureSizes),
testing::ValuesIn(kCaptureImplementationTweaks)));
// Allocates a device with an uncommon resolution and verifies frames are
// captured in a close, much more typical one.
TEST_F(VideoCaptureDeviceTest, MAYBE_AllocateBadSize) {
WRAPPED_TEST_P(VideoCaptureDeviceTest, MAYBE_AllocateBadSize) {
const auto descriptor = FindUsableDeviceDescriptor();
if (!descriptor)
return;
......@@ -481,7 +549,7 @@ TEST_F(VideoCaptureDeviceTest, MAYBE_AllocateBadSize) {
}
// Cause hangs on Windows, Linux. Fails Android. https://crbug.com/417824
TEST_F(VideoCaptureDeviceTest, DISABLED_ReAllocateCamera) {
WRAPPED_TEST_P(VideoCaptureDeviceTest, DISABLED_ReAllocateCamera) {
const auto descriptor = FindUsableDeviceDescriptor();
if (!descriptor)
return;
......@@ -525,7 +593,7 @@ TEST_F(VideoCaptureDeviceTest, DISABLED_ReAllocateCamera) {
}
// Starts the camera in 720p to try and capture MJPEG format.
TEST_F(VideoCaptureDeviceTest, MAYBE_CaptureMjpeg) {
WRAPPED_TEST_P(VideoCaptureDeviceTest, MAYBE_CaptureMjpeg) {
std::unique_ptr<VideoCaptureDeviceDescriptor> device_descriptor =
GetFirstDeviceDescriptorSupportingPixelFormat(PIXEL_FORMAT_MJPEG);
if (!device_descriptor) {
......@@ -562,7 +630,7 @@ TEST_F(VideoCaptureDeviceTest, MAYBE_CaptureMjpeg) {
device->StopAndDeAllocate();
}
TEST_F(VideoCaptureDeviceTest, NoCameraSupportsPixelFormatMax) {
WRAPPED_TEST_P(VideoCaptureDeviceTest, NoCameraSupportsPixelFormatMax) {
// Use PIXEL_FORMAT_MAX to iterate all device names for testing
// GetDeviceSupportedFormats().
std::unique_ptr<VideoCaptureDeviceDescriptor> device_descriptor =
......@@ -574,7 +642,7 @@ TEST_F(VideoCaptureDeviceTest, NoCameraSupportsPixelFormatMax) {
// Starts the camera and verifies that a photo can be taken. The correctness of
// the photo is enforced by MockImageCaptureClient.
TEST_F(VideoCaptureDeviceTest, MAYBE_TakePhoto) {
WRAPPED_TEST_P(VideoCaptureDeviceTest, MAYBE_TakePhoto) {
const auto descriptor = FindUsableDeviceDescriptor();
if (!descriptor)
return;
......@@ -623,7 +691,7 @@ TEST_F(VideoCaptureDeviceTest, MAYBE_TakePhoto) {
}
// Starts the camera and verifies that the photo capabilities can be retrieved.
TEST_F(VideoCaptureDeviceTest, MAYBE_GetPhotoState) {
WRAPPED_TEST_P(VideoCaptureDeviceTest, MAYBE_GetPhotoState) {
const auto descriptor = FindUsableDeviceDescriptor();
if (!descriptor)
return;
......@@ -674,4 +742,64 @@ TEST_F(VideoCaptureDeviceTest, MAYBE_GetPhotoState) {
device->StopAndDeAllocate();
}
#if defined(OS_WIN)
// Verifies that the photo callback is correctly released by MediaFoundation
WRAPPED_TEST_P(VideoCaptureDeviceTest, CheckPhotoCallbackRelease) {
if (!UseWinMediaFoundation())
return;
std::unique_ptr<VideoCaptureDeviceDescriptor> descriptor =
GetFirstDeviceDescriptorSupportingPixelFormat(PIXEL_FORMAT_MJPEG);
if (!descriptor) {
DVLOG(1) << "No usable media foundation device descriptor. Exiting test.";
return;
}
EXPECT_CALL(*video_capture_client_, OnError(_, _)).Times(0);
EXPECT_CALL(*video_capture_client_, OnStarted());
std::unique_ptr<VideoCaptureDevice> device(
video_capture_device_factory_->CreateDevice(*descriptor));
ASSERT_TRUE(device);
VideoCaptureParams capture_params;
capture_params.requested_format.frame_size.SetSize(320, 240);
capture_params.requested_format.frame_rate = 30;
capture_params.requested_format.pixel_format = PIXEL_FORMAT_MJPEG;
device->AllocateAndStart(capture_params, std::move(video_capture_client_));
if (!static_cast<VideoCaptureDeviceMFWin*>(device.get())
->get_use_photo_stream_to_take_photo_for_testing()) {
DVLOG(1) << "The device is not using the MediaFoundation photo callback. "
"Exiting test.";
device->StopAndDeAllocate();
return;
}
MockMFPhotoCallback* callback = new MockMFPhotoCallback();
EXPECT_CALL(*callback, DoQueryInterface(_, _)).WillRepeatedly(Return(S_OK));
EXPECT_CALL(*callback, DoAddRef()).WillOnce(Return(1U));
EXPECT_CALL(*callback, DoRelease()).WillOnce(Return(1U));
EXPECT_CALL(*callback, DoOnSample(_)).WillOnce(Return(S_OK));
static_cast<VideoCaptureDeviceMFWin*>(device.get())
->set_create_mf_photo_callback_for_testing(
base::BindRepeating(&VideoCaptureDeviceTest::CreateMockPhotoCallback,
base::Unretained(this), callback));
VideoCaptureDevice::TakePhotoCallback scoped_callback = base::BindOnce(
&MockImageCaptureClient::DoOnPhotoTaken, image_capture_client_);
base::RunLoop run_loop;
base::RepeatingClosure quit_closure =
BindToCurrentLoop(run_loop.QuitClosure());
EXPECT_CALL(*image_capture_client_.get(), OnCorrectPhotoTaken())
.WillOnce(RunClosure(quit_closure));
device->TakePhoto(std::move(scoped_callback));
run_loop.Run();
device->StopAndDeAllocate();
}
#endif
}; // namespace media
......@@ -17,22 +17,38 @@
namespace media {
struct CapabilityWin {
CapabilityWin(int index, const VideoCaptureFormat& format)
: stream_index(index), supported_format(format), info_header() {}
CapabilityWin(int media_type_index, const VideoCaptureFormat& format)
: media_type_index(media_type_index),
supported_format(format),
info_header(),
stream_index(0) {}
// Used by VideoCaptureDeviceWin.
CapabilityWin(int index,
CapabilityWin(int media_type_index,
const VideoCaptureFormat& format,
const BITMAPINFOHEADER& info_header)
: stream_index(index),
: media_type_index(media_type_index),
supported_format(format),
info_header(info_header) {}
info_header(info_header),
stream_index(0) {}
const int stream_index;
// Used by VideoCaptureDeviceMFWin.
CapabilityWin(int media_type_index,
const VideoCaptureFormat& format,
int stream_index)
: media_type_index(media_type_index),
supported_format(format),
info_header(),
stream_index(stream_index) {}
const int media_type_index;
const VideoCaptureFormat supported_format;
// |info_header| is only valid if DirectShow is used.
const BITMAPINFOHEADER info_header;
// |stream_index| is only valid if MediaFoundation is used.
const int stream_index;
};
typedef std::list<CapabilityWin> CapabilityList;
......
......@@ -69,10 +69,9 @@ static bool IsDeviceBlacklistedForQueryingDetailedFrameRates(
static bool LoadMediaFoundationDlls() {
static const wchar_t* const kMfDLLs[] = {
L"%WINDIR%\\system32\\mf.dll",
L"%WINDIR%\\system32\\mfplat.dll",
L"%WINDIR%\\system32\\mf.dll", L"%WINDIR%\\system32\\mfplat.dll",
L"%WINDIR%\\system32\\mfreadwrite.dll",
};
L"%WINDIR%\\system32\\MFCaptureEngine.dll"};
for (const wchar_t* kMfDLL : kMfDLLs) {
wchar_t path[MAX_PATH] = {0};
......@@ -86,8 +85,13 @@ static bool LoadMediaFoundationDlls() {
static bool PrepareVideoCaptureAttributesMediaFoundation(
IMFAttributes** attributes,
int count) {
if (!InitializeMediaFoundation())
// Once https://bugs.chromium.org/p/chromium/issues/detail?id=791615 is fixed,
// we must make sure that this method succeeds in capture_unittests context
// when MediaFoundation is enabled.
if (!VideoCaptureDeviceFactoryWin::PlatformSupportsMediaFoundation() ||
!InitializeMediaFoundation()) {
return false;
}
if (FAILED(MFCreateAttributes(attributes, count)))
return false;
......@@ -286,8 +290,9 @@ static void GetDeviceSupportedFormatsMediaFoundation(
DWORD stream_index = 0;
ComPtr<IMFMediaType> type;
while (SUCCEEDED(reader->GetNativeMediaType(kFirstVideoStream, stream_index,
type.GetAddressOf()))) {
while (SUCCEEDED(hr = reader->GetNativeMediaType(
static_cast<DWORD>(MF_SOURCE_READER_FIRST_VIDEO_STREAM),
stream_index, type.GetAddressOf()))) {
UINT32 width, height;
hr = MFGetAttributeSize(type.Get(), MF_MT_FRAME_SIZE, &width, &height);
if (FAILED(hr)) {
......
......@@ -30,10 +30,12 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryWin
const VideoCaptureDeviceDescriptor& device_descriptor,
VideoCaptureFormats* supported_formats) override;
void set_use_media_foundation_for_testing(bool use) {
use_media_foundation_ = use;
}
private:
// Media Foundation is available in Win7 and later, use it if explicitly
// forced via flag, else use DirectShow.
const bool use_media_foundation_;
bool use_media_foundation_;
DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryWin);
};
......
......@@ -3,12 +3,13 @@
// found in the LICENSE file.
// Windows specific implementation of VideoCaptureDevice.
// DirectShow is used for capturing. DirectShow provide its own threads
// for capturing.
// MediaFoundation is used for capturing. MediaFoundation provides its own
// threads for capturing.
#ifndef MEDIA_CAPTURE_VIDEO_WIN_VIDEO_CAPTURE_DEVICE_MF_WIN_H_
#define MEDIA_CAPTURE_VIDEO_WIN_VIDEO_CAPTURE_DEVICE_MF_WIN_H_
#include <mfcaptureengine.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <stdint.h>
......@@ -16,11 +17,12 @@
#include <vector>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/sequence_checker.h"
#include "base/synchronization/lock.h"
#include "media/capture/capture_export.h"
#include "media/capture/video/video_capture_device.h"
#include "media/capture/video/win/capability_list_win.h"
interface IMFSourceReader;
......@@ -30,10 +32,7 @@ class Location;
namespace media {
class MFReaderCallback;
const DWORD kFirstVideoStream =
static_cast<DWORD>(MF_SOURCE_READER_FIRST_VIDEO_STREAM);
class MFVideoCallback;
class CAPTURE_EXPORT VideoCaptureDeviceMFWin : public VideoCaptureDevice {
public:
......@@ -51,6 +50,10 @@ class CAPTURE_EXPORT VideoCaptureDeviceMFWin : public VideoCaptureDevice {
const VideoCaptureParams& params,
std::unique_ptr<VideoCaptureDevice::Client> client) override;
void StopAndDeAllocate() override;
void TakePhoto(TakePhotoCallback callback) override;
void GetPhotoState(GetPhotoStateCallback callback) override;
void SetPhotoOptions(mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) override;
// Captured new video data.
void OnIncomingCapturedData(const uint8_t* data,
......@@ -58,19 +61,41 @@ class CAPTURE_EXPORT VideoCaptureDeviceMFWin : public VideoCaptureDevice {
int rotation,
base::TimeTicks reference_time,
base::TimeDelta timestamp);
void OnEvent(IMFMediaEvent* media_event);
using CreateMFPhotoCallbackCB =
base::RepeatingCallback<scoped_refptr<IMFCaptureEngineOnSampleCallback>(
VideoCaptureDevice::TakePhotoCallback callback,
VideoCaptureFormat format)>;
bool get_use_photo_stream_to_take_photo_for_testing() {
return !photo_capabilities_.empty();
}
void set_create_mf_photo_callback_for_testing(CreateMFPhotoCallbackCB cb) {
create_mf_photo_callback_ = cb;
}
private:
void OnError(const base::Location& from_here, HRESULT hr);
void OnError(const base::Location& from_here, const char* message);
VideoCaptureDeviceDescriptor descriptor_;
Microsoft::WRL::ComPtr<IMFActivate> device_;
scoped_refptr<MFReaderCallback> callback_;
CreateMFPhotoCallbackCB create_mf_photo_callback_;
scoped_refptr<MFVideoCallback> video_callback_;
// Guards the below variables from concurrent access between methods running
// on |sequence_checker_| and calls to OnIncomingCapturedData() and OnEvent()
// made by MediaFoundation on threads outside of our control.
base::Lock lock_;
base::Lock lock_; // Used to guard the below variables.
std::unique_ptr<VideoCaptureDevice::Client> client_;
Microsoft::WRL::ComPtr<IMFSourceReader> reader_;
VideoCaptureFormat capture_format_;
bool capture_;
Microsoft::WRL::ComPtr<IMFCaptureEngine> engine_;
std::unique_ptr<CapabilityWin> selected_video_capability_;
CapabilityList photo_capabilities_;
std::unique_ptr<CapabilityWin> selected_photo_capability_;
bool is_started_;
base::queue<TakePhotoCallback> video_stream_take_photo_callbacks_;
SEQUENCE_CHECKER(sequence_checker_);
......
......@@ -526,7 +526,7 @@ void VideoCaptureDeviceWin::AllocateAndStart(
// Get the windows capability from the capture device.
// GetStreamCaps can return S_FALSE which we consider an error. Therefore the
// FAILED macro can't be used.
hr = stream_config->GetStreamCaps(found_capability.stream_index,
hr = stream_config->GetStreamCaps(found_capability.media_type_index,
media_type.Receive(), caps.get());
if (hr != S_OK) {
SetErrorState(FROM_HERE, "Failed to get capture device capabilities", hr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment