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

Make FileVideoCaptureDevice implement ImageCapture API

Implement GetPhotoState, SetPhotoOptions and TakePhoto in
FileVideoCaptureDevice to make TakePhoto works with video file as
source.

Bug: 806520, 807441
Change-Id: I487d5760162a13c34b5195d854b4285d0e2753dc
Reviewed-on: https://chromium-review.googlesource.com/890739
Commit-Queue: Christian Fremerey <chfremer@chromium.org>
Reviewed-by: default avatarChristian Fremerey <chfremer@chromium.org>
Reviewed-by: default avatarMiguel Casas <mcasas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#534462}
parent 0338da53
......@@ -15,6 +15,7 @@
#include "content/public/common/content_features.h"
#include "content/public/common/media_stream_request.h"
#include "media/base/bind_to_current_loop.h"
#include "media/capture/mojo/image_capture_types.h"
#include "media/capture/video/video_capture_device.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
......@@ -23,22 +24,6 @@ namespace content {
namespace {
media::mojom::PhotoStatePtr MakeEmptyCapabilities() {
media::mojom::PhotoStatePtr empty_capabilities =
media::mojom::PhotoState::New();
empty_capabilities->iso = media::mojom::Range::New();
empty_capabilities->width = media::mojom::Range::New();
empty_capabilities->height = media::mojom::Range::New();
empty_capabilities->zoom = media::mojom::Range::New();
empty_capabilities->exposure_compensation = media::mojom::Range::New();
empty_capabilities->color_temperature = media::mojom::Range::New();
empty_capabilities->brightness = media::mojom::Range::New();
empty_capabilities->contrast = media::mojom::Range::New();
empty_capabilities->saturation = media::mojom::Range::New();
empty_capabilities->sharpness = media::mojom::Range::New();
return empty_capabilities;
}
void GetPhotoStateOnIOThread(const std::string& source_id,
MediaStreamManager* media_stream_manager,
ImageCaptureImpl::GetPhotoStateCallback callback) {
......@@ -109,7 +94,7 @@ void ImageCaptureImpl::GetPhotoState(const std::string& source_id,
GetPhotoStateCallback scoped_callback =
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
media::BindToCurrentLoop(std::move(callback)),
MakeEmptyCapabilities());
mojo::CreateEmptyPhotoState());
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(&GetPhotoStateOnIOThread, source_id,
......
......@@ -10,6 +10,7 @@ group("capture") {
public_deps = [
":capture_lib",
"//media/capture/mojo:image_capture",
"//media/capture/mojo:image_capture_types",
"//media/capture/mojo:video_capture",
"//services/service_manager/public/cpp",
]
......@@ -60,6 +61,8 @@ source_set("capture_device_specific") {
"content/thread_safe_capture_oracle.h",
"content/video_capture_oracle.cc",
"content/video_capture_oracle.h",
"video/blob_utils.cc",
"video/blob_utils.h",
"video/fake_video_capture_device.cc",
"video/fake_video_capture_device.h",
"video/fake_video_capture_device_factory.cc",
......@@ -74,6 +77,7 @@ source_set("capture_device_specific") {
"video/video_capture_device_factory.cc",
"video/video_capture_device_factory.h",
]
public_deps = [
":capture_base",
]
......@@ -83,7 +87,9 @@ source_set("capture_device_specific") {
"//gpu/command_buffer/client",
"//media",
"//media/capture/mojo:image_capture",
"//media/capture/mojo:image_capture_types",
"//media/mojo/interfaces:interfaces",
"//third_party/libyuv",
"//ui/gfx",
]
}
......@@ -163,6 +169,7 @@ component("capture_lib") {
"//base:i18n",
"//media",
"//media/capture/mojo:image_capture",
"//media/capture/mojo:image_capture_types",
"//media/capture/mojo:video_capture",
"//media/mojo/interfaces:interfaces",
"//services/service_manager/public/cpp",
......@@ -212,13 +219,6 @@ component("capture_lib") {
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
}
if (is_linux || is_chromeos || is_win) {
sources += [
"video/blob_utils.cc",
"video/blob_utils.h",
]
}
if (is_chromeos) {
sources += [
"video/chromeos/camera_buffer_factory.cc",
......@@ -253,6 +253,7 @@ source_set("test_support") {
"//base/test:test_support",
"//media:test_support",
"//media/capture/mojo:image_capture",
"//media/capture/mojo:image_capture_types",
"//testing/gmock",
"//ui/gfx:test_support",
]
......@@ -268,6 +269,7 @@ test("capture_unittests") {
"content/video_capture_oracle_unittest.cc",
"run_all_unittests.cc",
"video/fake_video_capture_device_unittest.cc",
"video/file_video_capture_device_unittest.cc",
"video/linux/camera_config_chromeos_unittest.cc",
"video/linux/v4l2_capture_delegate_unittest.cc",
"video/mac/video_capture_device_factory_mac_unittest.mm",
......@@ -277,12 +279,17 @@ test("capture_unittests") {
"video_capture_types_unittest.cc",
]
data = [
"//media/test/data/bear.mjpeg",
]
deps = [
":capture",
":test_support",
"//base/test:test_support",
"//media:test_support",
"//media/capture/mojo:image_capture",
"//media/capture/mojo:image_capture_types",
"//mojo/edk/system",
"//testing/gmock",
"//testing/gtest",
......
......@@ -22,3 +22,14 @@ mojom("image_capture") {
"image_capture.mojom",
]
}
source_set("image_capture_types") {
sources = [
"image_capture_types.cc",
"image_capture_types.h",
]
deps = [
"//media/capture/mojo:image_capture",
]
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/capture/mojo/image_capture_types.h"
namespace mojo {
media::mojom::PhotoStatePtr CreateEmptyPhotoState() {
media::mojom::PhotoStatePtr photo_capabilities =
media::mojom::PhotoState::New();
photo_capabilities->height = media::mojom::Range::New();
photo_capabilities->width = media::mojom::Range::New();
photo_capabilities->exposure_compensation = media::mojom::Range::New();
photo_capabilities->color_temperature = media::mojom::Range::New();
photo_capabilities->iso = media::mojom::Range::New();
photo_capabilities->brightness = media::mojom::Range::New();
photo_capabilities->contrast = media::mojom::Range::New();
photo_capabilities->saturation = media::mojom::Range::New();
photo_capabilities->sharpness = media::mojom::Range::New();
photo_capabilities->zoom = media::mojom::Range::New();
photo_capabilities->torch = false;
photo_capabilities->red_eye_reduction = media::mojom::RedEyeReduction::NEVER;
return photo_capabilities;
}
} // namespace mojo
\ No newline at end of file
// Copyright 2018 The Chromium 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 MEDIA_CAPTURE_MOJO_IMAGE_CAPTURE_TYPES_H_
#define MEDIA_CAPTURE_MOJO_IMAGE_CAPTURE_TYPES_H_
#include "media/capture/mojo/image_capture.mojom.h"
namespace mojo {
media::mojom::PhotoStatePtr CreateEmptyPhotoState();
} // namespace mojo
#endif // MEDIA_CAPTURE_MOJO_IMAGE_CAPTURE_TYPES_H_
\ No newline at end of file
......@@ -15,6 +15,8 @@
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "media/capture/mojo/image_capture_types.h"
#include "media/capture/video/blob_utils.h"
#include "media/capture/video_capture_types.h"
#include "media/filters/jpeg_parser.h"
......@@ -331,6 +333,56 @@ void FileVideoCaptureDevice::StopAndDeAllocate() {
capture_thread_.Stop();
}
void FileVideoCaptureDevice::GetPhotoState(GetPhotoStateCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread());
auto photo_capabilities = mojo::CreateEmptyPhotoState();
int height = capture_format_.frame_size.height();
photo_capabilities->height = mojom::Range::New(height, height, height, 0);
int width = capture_format_.frame_size.width();
photo_capabilities->width = mojom::Range::New(width, width, width, 0);
std::move(callback).Run(std::move(photo_capabilities));
}
void FileVideoCaptureDevice::SetPhotoOptions(mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread());
if (settings->has_height &&
settings->height != capture_format_.frame_size.height()) {
return;
}
if (settings->has_width &&
settings->width != capture_format_.frame_size.width()) {
return;
}
if (settings->has_torch && settings->torch)
return;
if (settings->has_red_eye_reduction && settings->red_eye_reduction)
return;
if (settings->has_exposure_compensation || settings->has_color_temperature ||
settings->has_iso || settings->has_brightness || settings->has_contrast ||
settings->has_saturation || settings->has_sharpness ||
settings->has_zoom || settings->has_fill_light_mode) {
return;
}
std::move(callback).Run(true);
}
void FileVideoCaptureDevice::TakePhoto(TakePhotoCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread());
base::AutoLock lock(lock_);
take_photo_callbacks_.push(std::move(callback));
}
void FileVideoCaptureDevice::OnAllocateAndStart(
const VideoCaptureParams& params,
std::unique_ptr<VideoCaptureDevice::Client> client) {
......@@ -365,6 +417,7 @@ void FileVideoCaptureDevice::OnCaptureTask() {
DCHECK(capture_thread_.task_runner()->BelongsToCurrentThread());
if (!client_)
return;
base::AutoLock lock(lock_);
// Give the captured frame to the client.
int frame_size = 0;
......@@ -376,6 +429,19 @@ void FileVideoCaptureDevice::OnCaptureTask() {
first_ref_time_ = current_time;
client_->OnIncomingCapturedData(frame_ptr, frame_size, capture_format_, 0,
current_time, current_time - first_ref_time_);
// Process waiting photo callbacks
while (!take_photo_callbacks_.empty()) {
auto cb = std::move(take_photo_callbacks_.front());
take_photo_callbacks_.pop();
mojom::BlobPtr blob = Blobify(frame_ptr, frame_size, capture_format_);
if (!blob)
continue;
std::move(cb).Run(std::move(blob));
}
// Reschedule next CaptureTask.
const base::TimeDelta frame_interval =
base::TimeDelta::FromMicroseconds(1E6 / capture_format_.frame_rate);
......
......@@ -51,6 +51,10 @@ class CAPTURE_EXPORT FileVideoCaptureDevice : public VideoCaptureDevice {
const VideoCaptureParams& params,
std::unique_ptr<VideoCaptureDevice::Client> client) override;
void StopAndDeAllocate() override;
void GetPhotoState(GetPhotoStateCallback callback) override;
void SetPhotoOptions(mojom::PhotoSettingsPtr settings,
SetPhotoOptionsCallback callback) override;
void TakePhoto(TakePhotoCallback callback) override;
private:
// Opens a given file |file_path| for reading, and stores collected format
......@@ -84,6 +88,11 @@ class CAPTURE_EXPORT FileVideoCaptureDevice : public VideoCaptureDevice {
// The system time when we receive the first frame.
base::TimeTicks first_ref_time_;
// Guards the below variables from concurrent access between methods running
// on the main thread and |capture_thread_|.
base::Lock lock_;
base::queue<TakePhotoCallback> take_photo_callbacks_;
DISALLOW_COPY_AND_ASSIGN(FileVideoCaptureDevice);
};
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <utility>
#include "base/test/scoped_task_environment.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/test_data_util.h"
#include "media/capture/video/file_video_capture_device.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::InvokeWithoutArgs;
namespace media {
namespace {
class MockClient : public VideoCaptureDevice::Client {
public:
void OnIncomingCapturedData(const uint8_t* data,
int length,
const VideoCaptureFormat& frame_format,
int clockwise_rotation,
base::TimeTicks reference_time,
base::TimeDelta timestamp,
int frame_feedback_id = 0) {}
MOCK_METHOD4(
ReserveOutputBuffer,
Buffer(const gfx::Size&, VideoPixelFormat, VideoPixelStorage, int));
void OnIncomingCapturedBuffer(Buffer buffer,
const VideoCaptureFormat& format,
base::TimeTicks reference_,
base::TimeDelta timestamp) override {}
void OnIncomingCapturedBufferExt(
Buffer buffer,
const VideoCaptureFormat& format,
base::TimeTicks reference_time,
base::TimeDelta timestamp,
gfx::Rect visible_rect,
const VideoFrameMetadata& additional_metadata) override {}
MOCK_METHOD4(
ResurrectLastOutputBuffer,
Buffer(const gfx::Size&, VideoPixelFormat, VideoPixelStorage, int));
MOCK_METHOD2(OnError, void(const base::Location&, const std::string&));
double GetBufferPoolUtilization() const override { return 0.0; }
MOCK_METHOD0(OnStarted, void());
};
class MockImageCaptureClient {
public:
// GMock doesn't support move-only arguments, so we use this forward method.
void DoOnGetPhotoState(mojom::PhotoStatePtr state) {
state_ = std::move(state);
}
const mojom::PhotoState* state() { return state_.get(); }
MOCK_METHOD1(OnCorrectSetPhotoOptions, void(bool));
// GMock doesn't support move-only arguments, so we use this forward method.
void DoOnPhotoTaken(mojom::BlobPtr blob) {
EXPECT_TRUE(blob);
OnCorrectPhotoTaken();
}
MOCK_METHOD0(OnCorrectPhotoTaken, void(void));
private:
mojom::PhotoStatePtr state_;
};
} // namespace
class FileVideoCaptureDeviceTest : public ::testing::Test {
protected:
FileVideoCaptureDeviceTest() : client_(new MockClient()) {}
void SetUp() override {
EXPECT_CALL(*client_, OnError(_, _)).Times(0);
EXPECT_CALL(*client_, OnStarted());
device_ = std::make_unique<FileVideoCaptureDevice>(
GetTestDataFilePath("bear.mjpeg"));
device_->AllocateAndStart(VideoCaptureParams(), std::move(client_));
}
void TearDown() override { device_->StopAndDeAllocate(); }
std::unique_ptr<MockClient> client_;
MockImageCaptureClient image_capture_client_;
std::unique_ptr<VideoCaptureDevice> device_;
VideoCaptureFormat last_format_;
base::test::ScopedTaskEnvironment scoped_task_environment_;
};
TEST_F(FileVideoCaptureDeviceTest, GetPhotoState) {
VideoCaptureDevice::GetPhotoStateCallback scoped_get_callback =
base::BindOnce(&MockImageCaptureClient::DoOnGetPhotoState,
base::Unretained(&image_capture_client_));
device_->GetPhotoState(std::move(scoped_get_callback));
const mojom::PhotoState* state = image_capture_client_.state();
EXPECT_TRUE(state);
}
TEST_F(FileVideoCaptureDeviceTest, SetPhotoOptions) {
mojom::PhotoSettingsPtr photo_settings = mojom::PhotoSettings::New();
VideoCaptureDevice::SetPhotoOptionsCallback scoped_set_callback =
base::BindOnce(&MockImageCaptureClient::OnCorrectSetPhotoOptions,
base::Unretained(&image_capture_client_));
EXPECT_CALL(image_capture_client_, OnCorrectSetPhotoOptions(true)).Times(1);
device_->SetPhotoOptions(std::move(photo_settings),
std::move(scoped_set_callback));
}
TEST_F(FileVideoCaptureDeviceTest, TakePhoto) {
VideoCaptureDevice::TakePhotoCallback scoped_callback =
base::BindOnce(&MockImageCaptureClient::DoOnPhotoTaken,
base::Unretained(&image_capture_client_));
base::RunLoop run_loop;
base::Closure quit_closure = BindToCurrentLoop(run_loop.QuitClosure());
EXPECT_CALL(image_capture_client_, OnCorrectPhotoTaken())
.Times(1)
.WillOnce(InvokeWithoutArgs([quit_closure]() { quit_closure.Run(); }));
device_->TakePhoto(std::move(scoped_callback));
run_loop.Run();
}
} // namespace media
\ No newline at end of file
......@@ -25,6 +25,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "media/base/timestamp_constants.h"
#include "media/capture/mojo/image_capture_types.h"
#import "media/capture/video/mac/video_capture_device_avfoundation_mac.h"
#include "ui/gfx/geometry/size.h"
......@@ -392,27 +393,14 @@ void VideoCaptureDeviceMac::TakePhoto(TakePhotoCallback callback) {
void VideoCaptureDeviceMac::GetPhotoState(GetPhotoStateCallback callback) {
DCHECK(task_runner_->BelongsToCurrentThread());
auto photo_state = mojom::PhotoState::New();
auto photo_state = mojo::CreateEmptyPhotoState();
photo_state->exposure_compensation = mojom::Range::New();
photo_state->color_temperature = mojom::Range::New();
photo_state->iso = mojom::Range::New();
photo_state->brightness = mojom::Range::New();
photo_state->contrast = mojom::Range::New();
photo_state->saturation = mojom::Range::New();
photo_state->sharpness = mojom::Range::New();
photo_state->zoom = mojom::Range::New();
photo_state->red_eye_reduction = mojom::RedEyeReduction::NEVER;
photo_state->height = mojom::Range::New(
capture_format_.frame_size.height(), capture_format_.frame_size.height(),
capture_format_.frame_size.height(), 0 /* step */);
photo_state->width = mojom::Range::New(
capture_format_.frame_size.width(), capture_format_.frame_size.width(),
capture_format_.frame_size.width(), 0 /* step */);
photo_state->torch = false;
std::move(callback).Run(std::move(photo_state));
}
......
......@@ -283,9 +283,10 @@ class CAPTURE_EXPORT VideoCaptureDevice
SetPhotoOptionsCallback callback);
// Asynchronously takes a photo, possibly reconfiguring the capture objects
// and/or interrupting the capture flow. Runs |callback| on the thread
// where TakePhoto() is called, if the photo was successfully taken. On
// failure, drops callback without invoking it.
// and/or interrupting the capture flow. Runs |callback|, if the photo was
// successfully taken. On failure, drops callback without invoking it.
// Note that |callback| may be runned on a thread different than the thread
// where TakePhoto() was called.
using TakePhotoCallback = base::OnceCallback<void(mojom::BlobPtr blob)>;
virtual void TakePhoto(TakePhotoCallback callback);
......
......@@ -19,6 +19,7 @@
#include "base/synchronization/waitable_event.h"
#include "base/win/scoped_co_mem.h"
#include "base/win/windows_version.h"
#include "media/capture/mojo/image_capture_types.h"
#include "media/capture/video/blob_utils.h"
#include "media/capture/video/win/capability_list_win.h"
#include "media/capture/video/win/sink_filter_win.h"
......@@ -774,7 +775,7 @@ void VideoCaptureDeviceMFWin::GetPhotoState(GetPhotoStateCallback callback) {
return;
}
auto photo_capabilities = mojom::PhotoState::New();
auto photo_capabilities = mojo::CreateEmptyPhotoState();
gfx::Size current_size;
GetFrameSizeFromMediaType(current_media_type.Get(), &current_size);
......@@ -790,17 +791,6 @@ void VideoCaptureDeviceMFWin::GetPhotoState(GetPhotoStateCallback callback) {
photo_capabilities->width = mojom::Range::New(
max_size.width(), min_size.width(), current_size.width(), 1);
photo_capabilities->exposure_compensation = mojom::Range::New();
photo_capabilities->color_temperature = mojom::Range::New();
photo_capabilities->iso = mojom::Range::New();
photo_capabilities->brightness = mojom::Range::New();
photo_capabilities->contrast = mojom::Range::New();
photo_capabilities->saturation = mojom::Range::New();
photo_capabilities->sharpness = mojom::Range::New();
photo_capabilities->zoom = mojom::Range::New();
photo_capabilities->red_eye_reduction = mojom::RedEyeReduction::NEVER;
photo_capabilities->torch = false;
std::move(callback).Run(std::move(photo_capabilities));
}
......
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