Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Unified Diff: media/capture/video/fake_video_capture_device.cc

Issue 2715513008: Make FakeVideoCaptureDeviceFactory configurable to arbitrary fake device configurations (Closed)
Patch Set: Fix compiler warning. Fix WebRtcDepthCaptureBrowserTest. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/capture/video/fake_video_capture_device.cc
diff --git a/media/capture/video/fake_video_capture_device.cc b/media/capture/video/fake_video_capture_device.cc
index 7e46f68cab708272d74618b7b1b964b765df1556..e899464164485b20a98e97a941570a9b4a6e3210 100644
--- a/media/capture/video/fake_video_capture_device.cc
+++ b/media/capture/video/fake_video_capture_device.cc
@@ -29,6 +29,7 @@
namespace media {
namespace {
+
// Sweep at 600 deg/sec.
static const float kPacmanAngularVelocity = 600;
// Beep every 500 ms.
@@ -39,54 +40,76 @@ static const float kGradientFrequency = 1.f / 5;
static const double kMinZoom = 100.0;
static const double kMaxZoom = 400.0;
static const double kZoomStep = 1.0;
-static const double kInitialZoom = 100.0;
-
-static const gfx::Size kSupportedSizesOrderedByIncreasingWidth[] = {
- gfx::Size(96, 96), gfx::Size(320, 240), gfx::Size(640, 480),
- gfx::Size(1280, 720), gfx::Size(1920, 1080)};
-static const int kSupportedSizesCount =
- arraysize(kSupportedSizesOrderedByIncreasingWidth);
-
-static gfx::Size SnapToSupportedSize(const gfx::Size& requested_size) {
- for (const gfx::Size& supported_size :
- kSupportedSizesOrderedByIncreasingWidth) {
- if (requested_size.width() <= supported_size.width())
- return supported_size;
- }
- return kSupportedSizesOrderedByIncreasingWidth[kSupportedSizesCount - 1];
-}
-
-// Represents the current state of a FakeVideoCaptureDevice.
-// This is a separate struct because read-access to it is shared with several
-// collaborating classes.
-struct FakeDeviceState {
- FakeDeviceState(float zoom, float frame_rate, VideoPixelFormat pixel_format)
- : zoom(zoom),
- format(gfx::Size(), frame_rate, pixel_format, PIXEL_STORAGE_CPU) {}
- uint32_t zoom;
- VideoCaptureFormat format;
+enum class PixelFormatMatchType {
+ EXACT,
+ SUPPORTED_THROUGH_CONVERSION,
+ INCOMPATIBLE
};
-// Paints a "pacman-like" animated circle including textual information such
-// as a frame count and timer.
-class PacmanFramePainter {
- public:
- enum class Format { I420, SK_N32, Y16 };
- PacmanFramePainter(Format pixel_format,
- const FakeDeviceState* fake_device_state);
-
- void PaintFrame(base::TimeDelta elapsed_time, uint8_t* target_buffer);
+PixelFormatMatchType DetermineFormatMatchType(
+ media::VideoPixelFormat supported_format,
+ media::VideoPixelFormat requested_format) {
+ if (requested_format == media::PIXEL_FORMAT_I420) {
emircan 2017/03/01 18:58:58 Merge to a single if statement.
chfremer 2017/03/01 21:55:48 Done.
+ if (supported_format == media::PIXEL_FORMAT_MJPEG)
+ return PixelFormatMatchType::SUPPORTED_THROUGH_CONVERSION;
+ }
+ return (requested_format == supported_format)
+ ? PixelFormatMatchType::EXACT
+ : PixelFormatMatchType::INCOMPATIBLE;
+}
- private:
- void DrawGradientSquares(base::TimeDelta elapsed_time,
- uint8_t* target_buffer);
+bool CurrentFormatMatchIsWorseThanBest(PixelFormatMatchType current_match,
+ PixelFormatMatchType best_match) {
+ if (current_match == PixelFormatMatchType::INCOMPATIBLE) {
emircan 2017/03/01 18:58:58 I don't think comparing like this is scalable. Can
chfremer 2017/03/01 21:55:48 Done.
+ return best_match == PixelFormatMatchType::EXACT ||
+ best_match == PixelFormatMatchType::SUPPORTED_THROUGH_CONVERSION;
+ }
+ if (current_match == PixelFormatMatchType::SUPPORTED_THROUGH_CONVERSION)
+ return best_match == PixelFormatMatchType::EXACT;
+ return false;
+}
- void DrawPacman(base::TimeDelta elapsed_time, uint8_t* target_buffer);
+int FindIndexOfClosestSupportedFormat(
+ const VideoCaptureFormat& requested_format,
+ const VideoCaptureFormats& supported_formats) {
+ int best_index = 0;
+ PixelFormatMatchType best_format_match = PixelFormatMatchType::INCOMPATIBLE;
+ int best_width_mismatch = std::numeric_limits<int>::max();
+ float best_frame_rate_mismatch = std::numeric_limits<float>::max();
+ for (int i = 0; i < static_cast<int>(supported_formats.size()); i++) {
+ const auto& supported_format = supported_formats[i];
+ PixelFormatMatchType current_format_match = DetermineFormatMatchType(
+ supported_format.pixel_format, requested_format.pixel_format);
+ if (CurrentFormatMatchIsWorseThanBest(current_format_match,
+ best_format_match)) {
+ continue;
+ }
+ if (supported_format.frame_size.width() <
+ requested_format.frame_size.width())
+ continue;
+ const int current_width_mismatch = supported_format.frame_size.width() -
+ requested_format.frame_size.width();
+ if (current_width_mismatch > best_width_mismatch)
+ continue;
+ const float current_frame_rate_mismatch =
+ std::abs(supported_format.frame_rate - requested_format.frame_rate);
+ if (current_width_mismatch < best_width_mismatch) {
+ best_width_mismatch = current_width_mismatch;
+ best_frame_rate_mismatch = current_frame_rate_mismatch;
+ best_index = i;
+ continue;
+ }
+ DCHECK_EQ(best_frame_rate_mismatch, current_frame_rate_mismatch);
+ if (current_frame_rate_mismatch < best_frame_rate_mismatch) {
+ best_frame_rate_mismatch = current_frame_rate_mismatch;
+ best_index = i;
+ }
+ }
+ return best_index;
+}
- const Format pixel_format_;
- const FakeDeviceState* fake_device_state_ = nullptr;
-};
+} // anonymous namespace
// Paints and delivers frames to a client, which is set via Initialize().
class FrameDeliverer {
@@ -100,10 +123,6 @@ class FrameDeliverer {
client_ = std::move(client);
device_state_ = device_state;
}
- virtual void Uninitialize() {
- client_.reset();
- device_state_ = nullptr;
- }
virtual void PaintAndDeliverNextFrame(base::TimeDelta timestamp_to_paint) = 0;
protected:
@@ -134,7 +153,6 @@ class OwnBufferFrameDeliverer : public FrameDeliverer {
void Initialize(VideoPixelFormat pixel_format,
std::unique_ptr<VideoCaptureDevice::Client> client,
const FakeDeviceState* device_state) override;
- void Uninitialize() override;
void PaintAndDeliverNextFrame(base::TimeDelta timestamp_to_paint) override;
private:
@@ -158,7 +176,6 @@ class JpegEncodingFrameDeliverer : public FrameDeliverer {
~JpegEncodingFrameDeliverer() override;
// Implementation of FrameDeliveryStrategy
- void Uninitialize() override;
void PaintAndDeliverNextFrame(base::TimeDelta timestamp_to_paint) override;
private:
@@ -166,129 +183,57 @@ class JpegEncodingFrameDeliverer : public FrameDeliverer {
std::vector<unsigned char> jpeg_buffer_;
};
-// Implements the photo functionality of a VideoCaptureDevice
-class FakePhotoDevice {
- public:
- FakePhotoDevice(std::unique_ptr<PacmanFramePainter> painter,
- const FakeDeviceState* fake_device_state);
- ~FakePhotoDevice();
-
- void GetPhotoCapabilities(
- VideoCaptureDevice::GetPhotoCapabilitiesCallback callback);
- void TakePhoto(VideoCaptureDevice::TakePhotoCallback callback,
- base::TimeDelta elapsed_time);
-
- private:
- const std::unique_ptr<PacmanFramePainter> painter_;
- const FakeDeviceState* const fake_device_state_;
-};
-
-// Implementation of VideoCaptureDevice that generates test frames. This is
-// useful for testing the video capture components without having to use real
-// devices. The implementation schedules delayed tasks to itself to generate and
-// deliver frames at the requested rate.
-class FakeVideoCaptureDevice : public VideoCaptureDevice {
- public:
- FakeVideoCaptureDevice(
- std::unique_ptr<FrameDeliverer> frame_delivery_strategy,
- std::unique_ptr<FakePhotoDevice> photo_device,
- std::unique_ptr<FakeDeviceState> device_state);
- ~FakeVideoCaptureDevice() override;
-
- // VideoCaptureDevice implementation.
- void AllocateAndStart(const VideoCaptureParams& params,
- std::unique_ptr<Client> client) override;
- void StopAndDeAllocate() override;
- void GetPhotoCapabilities(GetPhotoCapabilitiesCallback callback) override;
- void SetPhotoOptions(mojom::PhotoSettingsPtr settings,
- SetPhotoOptionsCallback callback) override;
- void TakePhoto(TakePhotoCallback callback) override;
-
- private:
- void BeepAndScheduleNextCapture(base::TimeTicks expected_execution_time);
- void OnNextFrameDue(base::TimeTicks expected_execution_time, int session_id);
-
- const std::unique_ptr<FrameDeliverer> frame_deliverer_;
- const std::unique_ptr<FakePhotoDevice> photo_device_;
- const std::unique_ptr<FakeDeviceState> device_state_;
- int current_session_id_ = 0;
-
- // Time when the next beep occurs.
- base::TimeDelta beep_time_;
- // Time since the fake video started rendering frames.
- base::TimeDelta elapsed_time_;
-
- base::ThreadChecker thread_checker_;
-
- // FakeVideoCaptureDevice post tasks to itself for frame construction and
- // needs to deal with asynchronous StopAndDeallocate().
- base::WeakPtrFactory<FakeVideoCaptureDevice> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeVideoCaptureDevice);
-};
-
-} // anonymous namespace
-
-// static
-void FakeVideoCaptureDeviceMaker::GetSupportedSizes(
- std::vector<gfx::Size>* supported_sizes) {
- for (int i = 0; i < kSupportedSizesCount; i++)
- supported_sizes->push_back(kSupportedSizesOrderedByIncreasingWidth[i]);
-}
+FrameDelivererFactory::FrameDelivererFactory(
+ FakeVideoCaptureDevice::DeliveryMode delivery_mode,
+ const FakeDeviceState* device_state)
+ : delivery_mode_(delivery_mode), device_state_(device_state) {}
-// static
-std::unique_ptr<VideoCaptureDevice> FakeVideoCaptureDeviceMaker::MakeInstance(
- PixelFormat pixel_format,
- DeliveryMode delivery_mode,
- float frame_rate) {
- auto device_state = base::MakeUnique<FakeDeviceState>(
- kInitialZoom, frame_rate,
- static_cast<media::VideoPixelFormat>(pixel_format));
+std::unique_ptr<FrameDeliverer> FrameDelivererFactory::CreateFrameDeliverer(
+ const VideoCaptureFormat& format) {
PacmanFramePainter::Format painter_format;
- switch (pixel_format) {
- case PixelFormat::I420:
+ switch (format.pixel_format) {
+ case PIXEL_FORMAT_I420:
painter_format = PacmanFramePainter::Format::I420;
break;
- case PixelFormat::Y16:
+ case PIXEL_FORMAT_Y16:
painter_format = PacmanFramePainter::Format::Y16;
break;
- case PixelFormat::MJPEG:
+ case PIXEL_FORMAT_MJPEG:
painter_format = PacmanFramePainter::Format::SK_N32;
break;
+ default:
+ NOTREACHED();
+ painter_format = PacmanFramePainter::Format::I420;
+ }
+ auto frame_painter =
+ base::MakeUnique<PacmanFramePainter>(painter_format, device_state_);
+
+ FakeVideoCaptureDevice::DeliveryMode delivery_mode = delivery_mode_;
+ if (format.pixel_format == PIXEL_FORMAT_MJPEG &&
+ delivery_mode_ ==
+ FakeVideoCaptureDevice::DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS) {
+ DLOG(WARNING) << "PIXEL_FORMAT_MJPEG cannot be used in combination with "
+ << "USE_CLIENT_PROVIDED_BUFFERS. Switching to "
+ "USE_DEVICE_INTERNAL_BUFFERS.";
emircan 2017/03/01 18:58:58 We should still return an error here to propagate
chfremer 2017/03/01 21:55:48 I tried out your suggestions but then ended up rev
emircan 2017/03/02 20:28:18 Sounds good.
+ delivery_mode =
+ FakeVideoCaptureDevice::DeliveryMode::USE_DEVICE_INTERNAL_BUFFERS;
}
- auto video_frame_painter =
- base::MakeUnique<PacmanFramePainter>(painter_format, device_state.get());
- std::unique_ptr<FrameDeliverer> frame_delivery_strategy;
switch (delivery_mode) {
- case DeliveryMode::USE_DEVICE_INTERNAL_BUFFERS:
- if (pixel_format == PixelFormat::MJPEG) {
- frame_delivery_strategy = base::MakeUnique<JpegEncodingFrameDeliverer>(
- std::move(video_frame_painter));
+ case FakeVideoCaptureDevice::DeliveryMode::USE_DEVICE_INTERNAL_BUFFERS:
+ if (format.pixel_format == PIXEL_FORMAT_MJPEG) {
+ return base::MakeUnique<JpegEncodingFrameDeliverer>(
+ std::move(frame_painter));
} else {
- frame_delivery_strategy = base::MakeUnique<OwnBufferFrameDeliverer>(
- std::move(video_frame_painter));
- }
- break;
- case DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS:
- if (pixel_format == PixelFormat::MJPEG) {
- DLOG(ERROR) << "PixelFormat::MJPEG cannot be used in combination with "
- << "USE_CLIENT_PROVIDED_BUFFERS.";
- return nullptr;
+ return base::MakeUnique<OwnBufferFrameDeliverer>(
+ std::move(frame_painter));
}
- frame_delivery_strategy = base::MakeUnique<ClientBufferFrameDeliverer>(
- std::move(video_frame_painter));
- break;
+ case FakeVideoCaptureDevice::DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS:
+ return base::MakeUnique<ClientBufferFrameDeliverer>(
+ std::move(frame_painter));
}
-
- auto photo_frame_painter = base::MakeUnique<PacmanFramePainter>(
- PacmanFramePainter::Format::SK_N32, device_state.get());
- auto photo_device = base::MakeUnique<FakePhotoDevice>(
- std::move(photo_frame_painter), device_state.get());
-
- return base::MakeUnique<FakeVideoCaptureDevice>(
- std::move(frame_delivery_strategy), std::move(photo_device),
- std::move(device_state));
+ NOTREACHED();
+ return nullptr;
}
PacmanFramePainter::PacmanFramePainter(Format pixel_format,
@@ -427,9 +372,11 @@ void PacmanFramePainter::DrawPacman(base::TimeDelta elapsed_time,
}
}
-FakePhotoDevice::FakePhotoDevice(std::unique_ptr<PacmanFramePainter> painter,
- const FakeDeviceState* fake_device_state)
- : painter_(std::move(painter)), fake_device_state_(fake_device_state) {}
+FakePhotoDevice::FakePhotoDevice(
+ std::unique_ptr<PacmanFramePainter> sk_n32_painter,
+ const FakeDeviceState* fake_device_state)
+ : sk_n32_painter_(std::move(sk_n32_painter)),
+ fake_device_state_(fake_device_state) {}
FakePhotoDevice::~FakePhotoDevice() = default;
@@ -440,7 +387,7 @@ void FakePhotoDevice::TakePhoto(VideoCaptureDevice::TakePhotoCallback callback,
PIXEL_FORMAT_ARGB, fake_device_state_->format.frame_size);
std::unique_ptr<uint8_t[]> buffer(new uint8_t[required_sk_n32_buffer_size]);
memset(buffer.get(), 0, required_sk_n32_buffer_size);
- painter_->PaintFrame(elapsed_time, buffer.get());
+ sk_n32_painter_->PaintFrame(elapsed_time, buffer.get());
mojom::BlobPtr blob = mojom::Blob::New();
const gfx::PNGCodec::ColorFormat encoding_source_format =
(kN32_SkColorType == kRGBA_8888_SkColorType) ? gfx::PNGCodec::FORMAT_RGBA
@@ -459,10 +406,12 @@ void FakePhotoDevice::TakePhoto(VideoCaptureDevice::TakePhotoCallback callback,
}
FakeVideoCaptureDevice::FakeVideoCaptureDevice(
- std::unique_ptr<FrameDeliverer> frame_delivery_strategy,
+ const VideoCaptureFormats& supported_formats,
+ std::unique_ptr<FrameDelivererFactory> frame_deliverer_factory,
std::unique_ptr<FakePhotoDevice> photo_device,
std::unique_ptr<FakeDeviceState> device_state)
- : frame_deliverer_(std::move(frame_delivery_strategy)),
+ : supported_formats_(supported_formats),
+ frame_deliverer_factory_(std::move(frame_deliverer_factory)),
photo_device_(std::move(photo_device)),
device_state_(std::move(device_state)),
weak_factory_(this) {}
@@ -476,10 +425,16 @@ void FakeVideoCaptureDevice::AllocateAndStart(
std::unique_ptr<VideoCaptureDevice::Client> client) {
DCHECK(thread_checker_.CalledOnValidThread());
+ const int closest_supported_format_index = FindIndexOfClosestSupportedFormat(
+ params.requested_format, supported_formats_);
+ const VideoCaptureFormat& selected_format =
+ supported_formats_[closest_supported_format_index];
emircan 2017/03/01 18:58:58 Why don't we make the function FindClosestSupporte
chfremer 2017/03/01 21:55:48 Done.
+
beep_time_ = base::TimeDelta();
elapsed_time_ = base::TimeDelta();
- device_state_->format.frame_size =
- SnapToSupportedSize(params.requested_format.frame_size);
+ frame_deliverer_ =
+ frame_deliverer_factory_->CreateFrameDeliverer(selected_format);
+ device_state_->format.frame_size = selected_format.frame_size;
frame_deliverer_->Initialize(device_state_->format.pixel_format,
std::move(client), device_state_.get());
current_session_id_++;
@@ -491,7 +446,7 @@ void FakeVideoCaptureDevice::StopAndDeAllocate() {
// Invalidate WeakPtr to stop the perpetual scheduling of tasks.
weak_factory_.InvalidateWeakPtrs();
- frame_deliverer_->Uninitialize();
+ frame_deliverer_.reset();
}
void FakeVideoCaptureDevice::GetPhotoCapabilities(
@@ -574,11 +529,6 @@ void OwnBufferFrameDeliverer::Initialize(
pixel_format, device_state->format.frame_size)]);
}
-void OwnBufferFrameDeliverer::Uninitialize() {
- FrameDeliverer::Uninitialize();
- buffer_.reset();
-}
-
void OwnBufferFrameDeliverer::PaintAndDeliverNextFrame(
base::TimeDelta timestamp_to_paint) {
if (!client())
@@ -631,12 +581,6 @@ JpegEncodingFrameDeliverer::JpegEncodingFrameDeliverer(
JpegEncodingFrameDeliverer::~JpegEncodingFrameDeliverer() = default;
-void JpegEncodingFrameDeliverer::Uninitialize() {
- FrameDeliverer::Uninitialize();
- sk_n32_buffer_.clear();
- jpeg_buffer_.clear();
-}
-
void JpegEncodingFrameDeliverer::PaintAndDeliverNextFrame(
base::TimeDelta timestamp_to_paint) {
if (!client())

Powered by Google App Engine
This is Rietveld 408576698