diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-28 15:28:34 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-28 13:54:51 +0000 |
commit | 2a19c63448c84c1805fb1a585c3651318bb86ca7 (patch) | |
tree | eb17888e8531aa6ee5e85721bd553b832a7e5156 /chromium/media/capture | |
parent | b014812705fc80bff0a5c120dfcef88f349816dc (diff) | |
download | qtwebengine-chromium-2a19c63448c84c1805fb1a585c3651318bb86ca7.tar.gz |
BASELINE: Update Chromium to 69.0.3497.70
Change-Id: I2b7b56e4e7a8b26656930def0d4575dc32b900a0
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/media/capture')
76 files changed, 2262 insertions, 1092 deletions
diff --git a/chromium/media/capture/BUILD.gn b/chromium/media/capture/BUILD.gn index be5925b27b6..f9e2ccbb4f1 100644 --- a/chromium/media/capture/BUILD.gn +++ b/chromium/media/capture/BUILD.gn @@ -53,12 +53,8 @@ source_set("capture_device_specific") { "content/animated_content_sampler.h", "content/capture_resolution_chooser.cc", "content/capture_resolution_chooser.h", - "content/screen_capture_device_core.cc", - "content/screen_capture_device_core.h", "content/smooth_event_sampler.cc", "content/smooth_event_sampler.h", - "content/thread_safe_capture_oracle.cc", - "content/thread_safe_capture_oracle.h", "content/video_capture_oracle.cc", "content/video_capture_oracle.h", "video/blob_utils.cc", @@ -97,24 +93,8 @@ source_set("capture_device_specific") { component("capture_lib") { defines = [ "CAPTURE_IMPLEMENTATION" ] sources = [ - "video/linux/camera_config_chromeos.cc", - "video/linux/camera_config_chromeos.h", - "video/linux/v4l2_capture_delegate.cc", - "video/linux/v4l2_capture_delegate.h", - "video/linux/video_capture_device_chromeos.cc", - "video/linux/video_capture_device_chromeos.h", - "video/linux/video_capture_device_factory_linux.cc", - "video/linux/video_capture_device_factory_linux.h", - "video/linux/video_capture_device_linux.cc", - "video/linux/video_capture_device_linux.h", - "video/mac/video_capture_device_avfoundation_mac.h", - "video/mac/video_capture_device_avfoundation_mac.mm", - "video/mac/video_capture_device_decklink_mac.h", - "video/mac/video_capture_device_decklink_mac.mm", - "video/mac/video_capture_device_factory_mac.h", - "video/mac/video_capture_device_factory_mac.mm", - "video/mac/video_capture_device_mac.h", - "video/mac/video_capture_device_mac.mm", + "video/create_video_capture_device_factory.cc", + "video/create_video_capture_device_factory.h", "video/scoped_buffer_pool_reservation.h", "video/shared_memory_buffer_tracker.cc", "video/shared_memory_buffer_tracker.h", @@ -130,33 +110,14 @@ component("capture_lib") { "video/video_capture_device_client.cc", "video/video_capture_device_client.h", "video/video_capture_jpeg_decoder.h", + "video/video_capture_jpeg_decoder_impl.cc", + "video/video_capture_jpeg_decoder_impl.h", "video/video_capture_system.h", "video/video_capture_system_impl.cc", "video/video_capture_system_impl.h", "video/video_frame_receiver.h", "video/video_frame_receiver_on_task_runner.cc", "video/video_frame_receiver_on_task_runner.h", - "video/win/capability_list_win.cc", - "video/win/capability_list_win.h", - "video/win/filter_base_win.cc", - "video/win/filter_base_win.h", - "video/win/metrics.cc", - "video/win/metrics.h", - "video/win/pin_base_win.cc", - "video/win/pin_base_win.h", - "video/win/sink_filter_observer_win.h", - "video/win/sink_filter_win.cc", - "video/win/sink_filter_win.h", - "video/win/sink_input_pin_win.cc", - "video/win/sink_input_pin_win.h", - "video/win/video_capture_device_factory_win.cc", - "video/win/video_capture_device_factory_win.h", - "video/win/video_capture_device_mf_win.cc", - "video/win/video_capture_device_mf_win.h", - "video/win/video_capture_device_utils_win.cc", - "video/win/video_capture_device_utils_win.h", - "video/win/video_capture_device_win.cc", - "video/win/video_capture_device_win.h", "video_capturer_source.cc", "video_capturer_source.h", ] @@ -173,6 +134,7 @@ component("capture_lib") { "//media/capture/mojom:image_capture", "//media/capture/mojom:image_capture_types", "//media/capture/mojom:video_capture", + "//media/mojo/clients:jpeg_decode_accelerator", "//media/mojo/interfaces:interfaces", "//services/service_manager/public/cpp", "//third_party/libyuv", @@ -192,6 +154,16 @@ component("capture_lib") { } if (is_mac) { + sources += [ + "video/mac/video_capture_device_avfoundation_mac.h", + "video/mac/video_capture_device_avfoundation_mac.mm", + "video/mac/video_capture_device_decklink_mac.h", + "video/mac/video_capture_device_decklink_mac.mm", + "video/mac/video_capture_device_factory_mac.h", + "video/mac/video_capture_device_factory_mac.mm", + "video/mac/video_capture_device_mac.h", + "video/mac/video_capture_device_mac.mm", + ] deps += [ "//third_party/decklink" ] libs = [ "AVFoundation.framework", @@ -204,6 +176,29 @@ component("capture_lib") { } if (is_win) { + sources += [ + "video/win/capability_list_win.cc", + "video/win/capability_list_win.h", + "video/win/filter_base_win.cc", + "video/win/filter_base_win.h", + "video/win/metrics.cc", + "video/win/metrics.h", + "video/win/pin_base_win.cc", + "video/win/pin_base_win.h", + "video/win/sink_filter_observer_win.h", + "video/win/sink_filter_win.cc", + "video/win/sink_filter_win.h", + "video/win/sink_input_pin_win.cc", + "video/win/sink_input_pin_win.h", + "video/win/video_capture_device_factory_win.cc", + "video/win/video_capture_device_factory_win.h", + "video/win/video_capture_device_mf_win.cc", + "video/win/video_capture_device_mf_win.h", + "video/win/video_capture_device_utils_win.cc", + "video/win/video_capture_device_utils_win.h", + "video/win/video_capture_device_win.cc", + "video/win/video_capture_device_win.h", + ] deps += [ "//media/base/win" ] libs = [ "mf.lib", @@ -221,6 +216,25 @@ component("capture_lib") { configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] } + # This includes the case of ChromeOS + if (is_linux) { + sources += [ + "video/linux/camera_config_chromeos.cc", + "video/linux/camera_config_chromeos.h", + "video/linux/v4l2_capture_delegate.cc", + "video/linux/v4l2_capture_delegate.h", + "video/linux/v4l2_capture_device.h", + "video/linux/v4l2_capture_device_impl.cc", + "video/linux/v4l2_capture_device_impl.h", + "video/linux/video_capture_device_chromeos.cc", + "video/linux/video_capture_device_chromeos.h", + "video/linux/video_capture_device_factory_linux.cc", + "video/linux/video_capture_device_factory_linux.h", + "video/linux/video_capture_device_linux.cc", + "video/linux/video_capture_device_linux.h", + ] + } + if (is_chromeos) { sources += [ "video/chromeos/camera_3a_controller.cc", @@ -248,10 +262,11 @@ component("capture_lib") { "video/chromeos/video_capture_device_factory_chromeos.cc", "video/chromeos/video_capture_device_factory_chromeos.h", ] + public_deps += [ "//media/capture/video/chromeos/public" ] deps += [ "//chromeos:chromeos", "//media/capture/video/chromeos/mojo:cros_camera", - "//mojo/edk", + "//third_party/libdrm", "//third_party/libsync", ] } @@ -286,7 +301,10 @@ test("capture_unittests") { "video/fake_video_capture_device_unittest.cc", "video/file_video_capture_device_unittest.cc", "video/linux/camera_config_chromeos_unittest.cc", + "video/linux/fake_v4l2_impl.cc", + "video/linux/fake_v4l2_impl.h", "video/linux/v4l2_capture_delegate_unittest.cc", + "video/linux/video_capture_device_factory_linux_unittest.cc", "video/mac/video_capture_device_factory_mac_unittest.mm", "video/mock_gpu_memory_buffer_manager.cc", "video/mock_gpu_memory_buffer_manager.h", @@ -308,7 +326,7 @@ test("capture_unittests") { "//media:test_support", "//media/capture/mojom:image_capture", "//media/capture/mojom:image_capture_types", - "//mojo/edk", + "//mojo/core/embedder", "//testing/gmock", "//testing/gtest", "//ui/gfx:test_support", @@ -358,7 +376,7 @@ test("capture_unittests") { deps += [ "//chromeos:chromeos", "//media/capture/video/chromeos/mojo:cros_camera", - "//mojo/edk", + "//mojo/core/embedder", "//third_party/libdrm", "//third_party/libsync", "//third_party/minigbm", diff --git a/chromium/media/capture/DEPS b/chromium/media/capture/DEPS index d415fec5261..809f1c1109f 100644 --- a/chromium/media/capture/DEPS +++ b/chromium/media/capture/DEPS @@ -1,3 +1,3 @@ specific_include_rules = { - "run_all_unittests.cc": [ "+mojo/edk/embedder" ], + "run_all_unittests.cc": [ "+mojo/core/embedder" ], } diff --git a/chromium/media/capture/content/android/BUILD.gn b/chromium/media/capture/content/android/BUILD.gn index 92ff80e2ea3..521a0f0a51f 100644 --- a/chromium/media/capture/content/android/BUILD.gn +++ b/chromium/media/capture/content/android/BUILD.gn @@ -14,14 +14,18 @@ source_set("android") { sources = [ "screen_capture_machine_android.cc", "screen_capture_machine_android.h", + "thread_safe_capture_oracle.cc", + "thread_safe_capture_oracle.h", ] configs += [ "//media:media_config" ] deps = [ ":screen_capture_jni_headers", + "//media", "//media/capture:capture_device_specific", "//media/capture/mojom:image_capture", "//third_party/libyuv", "//ui/gfx:color_space", + "//ui/gfx/geometry", ] } diff --git a/chromium/media/capture/content/android/screen_capture_machine_android.cc b/chromium/media/capture/content/android/screen_capture_machine_android.cc index 734048e68ac..be83b1379e5 100644 --- a/chromium/media/capture/content/android/screen_capture_machine_android.cc +++ b/chromium/media/capture/content/android/screen_capture_machine_android.cc @@ -4,10 +4,15 @@ #include "media/capture/content/android/screen_capture_machine_android.h" +#include <utility> + #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" #include "jni/ScreenCapture_jni.h" +#include "media/base/video_frame.h" +#include "media/capture/content/android/thread_safe_capture_oracle.h" #include "media/capture/content/video_capture_oracle.h" +#include "media/capture/video_capture_types.h" #include "third_party/libyuv/include/libyuv.h" using base::android::AttachCurrentThread; @@ -94,7 +99,7 @@ void ScreenCaptureMachineAndroid::OnRGBAFrameAvailable( frame->visible_rect().height(), libyuv::kFilterBilinear); } - capture_frame_cb.Run(frame, start_time, true); + std::move(capture_frame_cb).Run(frame, start_time, true); lastFrame_ = frame; } @@ -177,7 +182,7 @@ void ScreenCaptureMachineAndroid::OnI420FrameAvailable( frame->visible_rect().height(), libyuv::kFilterBilinear); } - capture_frame_cb.Run(frame, start_time, true); + std::move(capture_frame_cb).Run(frame, start_time, true); lastFrame_ = frame; } @@ -225,20 +230,18 @@ void ScreenCaptureMachineAndroid::OnOrientationChange( } } -void ScreenCaptureMachineAndroid::Start( - const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, - const VideoCaptureParams& params, - const base::Callback<void(bool)> callback) { +bool ScreenCaptureMachineAndroid::Start( + scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy, + const VideoCaptureParams& params) { DCHECK(oracle_proxy.get()); - oracle_proxy_ = oracle_proxy; + oracle_proxy_ = std::move(oracle_proxy); j_capture_.Reset( createScreenCaptureMachineAndroid(reinterpret_cast<intptr_t>(this))); if (j_capture_.obj() == nullptr) { DLOG(ERROR) << "Failed to createScreenCaptureAndroid"; - callback.Run(false); - return; + return false; } DCHECK(params.requested_format.frame_size.GetArea()); @@ -251,24 +254,19 @@ void ScreenCaptureMachineAndroid::Start( params.requested_format.frame_size.height()); if (!ret) { DLOG(ERROR) << "Failed to init ScreenCaptureAndroid"; - callback.Run(ret); - return; + return false; } ret = Java_ScreenCapture_startPrompt(AttachCurrentThread(), j_capture_); - // Must wait for user input to start capturing before we can report back - // device started state. However, if the user-prompt failed to show, report - // a failed start immediately. - if (!ret) - callback.Run(ret); + // NOTE: Result of user prompt will be delivered to OnActivityResult(), and + // this will report the device started/error state via the |oracle_proxy_|. + return !!ret; } -void ScreenCaptureMachineAndroid::Stop(const base::Closure& callback) { +void ScreenCaptureMachineAndroid::Stop() { if (j_capture_.obj() != nullptr) { Java_ScreenCapture_stopCapture(AttachCurrentThread(), j_capture_); } - - callback.Run(); } // ScreenCapture on Android works in a passive way and there are no captured @@ -306,7 +304,7 @@ void ScreenCaptureMachineAndroid::MaybeCaptureForRefresh() { frame->stride(VideoFrame::kVPlane), frame->visible_rect().width(), frame->visible_rect().height(), libyuv::kFilterBilinear); - capture_frame_cb.Run(frame, start_time, true); + std::move(capture_frame_cb).Run(frame, start_time, true); } } // namespace media diff --git a/chromium/media/capture/content/android/screen_capture_machine_android.h b/chromium/media/capture/content/android/screen_capture_machine_android.h index 775e6d6c00c..4b118341f62 100644 --- a/chromium/media/capture/content/android/screen_capture_machine_android.h +++ b/chromium/media/capture/content/android/screen_capture_machine_android.h @@ -9,16 +9,20 @@ #include <memory> #include "base/android/scoped_java_ref.h" +#include "base/memory/scoped_refptr.h" #include "media/capture/capture_export.h" -#include "media/capture/content/screen_capture_device_core.h" namespace media { +class ThreadSafeCaptureOracle; +struct VideoCaptureParams; +class VideoFrame; + // ScreenCaptureMachineAndroid captures 32bit RGB or YUV420 triplanar. -class CAPTURE_EXPORT ScreenCaptureMachineAndroid : public VideoCaptureMachine { +class CAPTURE_EXPORT ScreenCaptureMachineAndroid { public: ScreenCaptureMachineAndroid(); - ~ScreenCaptureMachineAndroid() override; + virtual ~ScreenCaptureMachineAndroid(); static base::android::ScopedJavaLocalRef<jobject> createScreenCaptureMachineAndroid(jlong nativeScreenCaptureMachineAndroid); @@ -58,12 +62,14 @@ class CAPTURE_EXPORT ScreenCaptureMachineAndroid : public VideoCaptureMachine { const base::android::JavaRef<jobject>& obj, jint rotation); - // VideoCaptureMachine overrides. - void Start(const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, - const media::VideoCaptureParams& params, - const base::Callback<void(bool)> callback) override; - void Stop(const base::Closure& callback) override; - void MaybeCaptureForRefresh() override; + // Starts/Stops capturing. + bool Start(scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy, + const VideoCaptureParams& params); + void Stop(); + + // If there is a cached frame, and the oracle allows sending another frame + // right now, the cached captured frame is redelivered. + void MaybeCaptureForRefresh(); private: // Indicates the orientation of the device. diff --git a/chromium/media/capture/content/thread_safe_capture_oracle.cc b/chromium/media/capture/content/android/thread_safe_capture_oracle.cc index 4d07bb7cdf6..ef8732f591b 100644 --- a/chromium/media/capture/content/thread_safe_capture_oracle.cc +++ b/chromium/media/capture/content/android/thread_safe_capture_oracle.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "media/capture/content/thread_safe_capture_oracle.h" +#include "media/capture/content/android/thread_safe_capture_oracle.h" #include <stdint.h> @@ -13,7 +13,6 @@ #include "base/bits.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" -#include "base/synchronization/lock.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" #include "media/base/video_frame.h" @@ -44,11 +43,8 @@ struct ThreadSafeCaptureOracle::InFlightFrameCapture { ThreadSafeCaptureOracle::ThreadSafeCaptureOracle( std::unique_ptr<VideoCaptureDevice::Client> client, - const VideoCaptureParams& params, - bool enable_auto_throttling) - : client_(std::move(client)), - oracle_(enable_auto_throttling), - params_(params) { + const VideoCaptureParams& params) + : client_(std::move(client)), oracle_(false), params_(params) { DCHECK_GE(params.requested_format.frame_rate, 1e-6f); oracle_.SetMinCapturePeriod(base::TimeDelta::FromMicroseconds( static_cast<int64_t>(1000000.0 / params.requested_format.frame_rate + @@ -168,8 +164,8 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture( return false; } - *callback = base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame, this, - base::Passed(&capture)); + *callback = base::BindOnce(&ThreadSafeCaptureOracle::DidCaptureFrame, this, + base::Passed(&capture)); return true; } @@ -217,9 +213,6 @@ void ThreadSafeCaptureOracle::DidCaptureFrame( const bool should_deliver_frame = oracle_.CompleteCapture(capture->frame_number, success, &reference_time); - // The following is used by - // chrome/browser/extension/api/cast_streaming/performance_test.cc, in - // addition to the usual runtime tracing. TRACE_EVENT_ASYNC_END2("gpu.capture", "Capture", capture->buffer.id, "success", should_deliver_frame, "timestamp", (reference_time - base::TimeTicks()).InMicroseconds()); diff --git a/chromium/media/capture/content/thread_safe_capture_oracle.h b/chromium/media/capture/content/android/thread_safe_capture_oracle.h index cab73733cae..65e62f66044 100644 --- a/chromium/media/capture/content/thread_safe_capture_oracle.h +++ b/chromium/media/capture/content/android/thread_safe_capture_oracle.h @@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_CAPTURE_CONTENT_THREAD_SAFE_CAPTURE_ORACLE_H_ -#define MEDIA_CAPTURE_CONTENT_THREAD_SAFE_CAPTURE_ORACLE_H_ +#ifndef MEDIA_CAPTURE_CONTENT_ANDROID_THREAD_SAFE_CAPTURE_ORACLE_H_ +#define MEDIA_CAPTURE_CONTENT_ANDROID_THREAD_SAFE_CAPTURE_ORACLE_H_ #include <memory> #include <string> #include "base/memory/ref_counted.h" -#include "media/base/video_frame.h" +#include "base/synchronization/lock.h" #include "media/capture/capture_export.h" #include "media/capture/content/video_capture_oracle.h" #include "media/capture/video/video_capture_buffer_handle.h" @@ -23,6 +23,7 @@ namespace media { struct VideoCaptureParams; class VideoFrame; +class VideoFrameMetadata; // Thread-safe, refcounted proxy to the VideoCaptureOracle. This proxy wraps // the VideoCaptureOracle, which decides which frames to capture, and a @@ -32,16 +33,15 @@ class CAPTURE_EXPORT ThreadSafeCaptureOracle : public base::RefCountedThreadSafe<ThreadSafeCaptureOracle> { public: ThreadSafeCaptureOracle(std::unique_ptr<VideoCaptureDevice::Client> client, - const VideoCaptureParams& params, - bool enable_auto_throttling); + const VideoCaptureParams& params); // Called when a captured frame is available or an error has occurred. // If |success| is true then |frame| is valid and |timestamp| indicates when // the frame was painted. // If |success| is false, all other parameters are invalid. - typedef base::Callback<void(scoped_refptr<VideoFrame> frame, - base::TimeTicks timestamp, - bool success)> + typedef base::OnceCallback<void(scoped_refptr<VideoFrame> frame, + base::TimeTicks timestamp, + bool success)> CaptureFrameCallback; // Record a change |event| along with its |damage_rect| and |event_time|, and @@ -60,18 +60,6 @@ class CAPTURE_EXPORT ThreadSafeCaptureOracle scoped_refptr<VideoFrame>* storage, CaptureFrameCallback* callback); - base::TimeDelta min_capture_period() const { - return oracle_.min_capture_period(); - } - - base::TimeTicks last_time_animation_was_detected() const { - return oracle_.last_time_animation_was_detected(); - } - - gfx::Size max_frame_size() const { - return params_.requested_format.frame_size; - } - // Returns the current capture resolution. gfx::Size GetCaptureSize() const; @@ -125,4 +113,4 @@ class CAPTURE_EXPORT ThreadSafeCaptureOracle } // namespace media -#endif // MEDIA_CAPTURE_CONTENT_THREAD_SAFE_CAPTURE_ORACLE_H_ +#endif // MEDIA_CAPTURE_CONTENT_ANDROID_THREAD_SAFE_CAPTURE_ORACLE_H_ diff --git a/chromium/media/capture/content/screen_capture_device_core.cc b/chromium/media/capture/content/screen_capture_device_core.cc deleted file mode 100644 index 5ae39399c9e..00000000000 --- a/chromium/media/capture/content/screen_capture_device_core.cc +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2014 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/content/screen_capture_device_core.h" - -#include <memory> -#include <utility> - -#include "base/bind.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "base/threading/thread_checker.h" - -namespace media { - -namespace { - -void DeleteCaptureMachine( - std::unique_ptr<VideoCaptureMachine> capture_machine) { - capture_machine.reset(); -} - -} // namespace - -VideoCaptureMachine::VideoCaptureMachine() = default; - -VideoCaptureMachine::~VideoCaptureMachine() = default; - -bool VideoCaptureMachine::IsAutoThrottlingEnabled() const { - return false; -} - -void ScreenCaptureDeviceCore::AllocateAndStart( - const VideoCaptureParams& params, - std::unique_ptr<VideoCaptureDevice::Client> client) { - DCHECK(thread_checker_.CalledOnValidThread()); - - if (state_ != kIdle) { - DVLOG(1) << "Allocate() invoked when not in state Idle."; - return; - } - - if (params.requested_format.pixel_format != PIXEL_FORMAT_I420) { - client->OnError( - FROM_HERE, - base::StringPrintf( - "unsupported format: %s", - VideoCaptureFormat::ToString(params.requested_format).c_str())); - return; - } - - oracle_proxy_ = new ThreadSafeCaptureOracle( - std::move(client), params, capture_machine_->IsAutoThrottlingEnabled()); - - capture_machine_->Start( - oracle_proxy_, params, - base::Bind(&ScreenCaptureDeviceCore::CaptureStarted, AsWeakPtr())); - - TransitionStateTo(kCapturing); -} - -void ScreenCaptureDeviceCore::RequestRefreshFrame() { - DCHECK(thread_checker_.CalledOnValidThread()); - - if (state_ != kCapturing) - return; - - capture_machine_->MaybeCaptureForRefresh(); -} - -void ScreenCaptureDeviceCore::Suspend() { - DCHECK(thread_checker_.CalledOnValidThread()); - - if (state_ != kCapturing) - return; - - TransitionStateTo(kSuspended); - - capture_machine_->Suspend(); -} - -void ScreenCaptureDeviceCore::Resume() { - DCHECK(thread_checker_.CalledOnValidThread()); - - if (state_ != kSuspended) - return; - - TransitionStateTo(kCapturing); - - capture_machine_->Resume(); -} - -void ScreenCaptureDeviceCore::StopAndDeAllocate() { - DCHECK(thread_checker_.CalledOnValidThread()); - - if (state_ != kCapturing && state_ != kSuspended) - return; - - oracle_proxy_->Stop(); - oracle_proxy_ = NULL; - - TransitionStateTo(kIdle); - - capture_machine_->Stop(base::DoNothing()); -} - -void ScreenCaptureDeviceCore::OnConsumerReportingUtilization( - int frame_feedback_id, - double utilization) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(oracle_proxy_); - oracle_proxy_->OnConsumerReportingUtilization(frame_feedback_id, utilization); -} - -void ScreenCaptureDeviceCore::CaptureStarted(bool success) { - DCHECK(thread_checker_.CalledOnValidThread()); - if (!success) - Error(FROM_HERE, "Failed to start capture machine."); - else if (oracle_proxy_) - oracle_proxy_->ReportStarted(); -} - -ScreenCaptureDeviceCore::ScreenCaptureDeviceCore( - std::unique_ptr<VideoCaptureMachine> capture_machine) - : state_(kIdle), capture_machine_(std::move(capture_machine)) { - DCHECK(capture_machine_.get()); -} - -ScreenCaptureDeviceCore::~ScreenCaptureDeviceCore() { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(state_ != kCapturing && state_ != kSuspended); - if (capture_machine_) { - capture_machine_->Stop( - base::Bind(&DeleteCaptureMachine, base::Passed(&capture_machine_))); - } - DVLOG(1) << "ScreenCaptureDeviceCore@" << this << " destroying."; -} - -void ScreenCaptureDeviceCore::TransitionStateTo(State next_state) { - DCHECK(thread_checker_.CalledOnValidThread()); - -#ifndef NDEBUG - static const char* kStateNames[] = {"Idle", "Capturing", "Suspended", - "Error"}; - static_assert(arraysize(kStateNames) == kLastCaptureState, - "Different number of states and textual descriptions"); - DVLOG(1) << "State change: " << kStateNames[state_] << " --> " - << kStateNames[next_state]; -#endif - - state_ = next_state; -} - -void ScreenCaptureDeviceCore::Error(const base::Location& from_here, - const std::string& reason) { - DCHECK(thread_checker_.CalledOnValidThread()); - - if (state_ == kIdle) - return; - - if (oracle_proxy_) - oracle_proxy_->ReportError(from_here, reason); - - StopAndDeAllocate(); - TransitionStateTo(kError); -} - -} // namespace media diff --git a/chromium/media/capture/content/screen_capture_device_core.h b/chromium/media/capture/content/screen_capture_device_core.h deleted file mode 100644 index 5f5bdcbc32f..00000000000 --- a/chromium/media/capture/content/screen_capture_device_core.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2014 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_CONTENT_SCREEN_CAPTURE_DEVICE_CORE_H_ -#define MEDIA_CAPTURE_CONTENT_SCREEN_CAPTURE_DEVICE_CORE_H_ - -#include <memory> -#include <string> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_checker.h" -#include "media/capture/capture_export.h" -#include "media/capture/content/thread_safe_capture_oracle.h" -#include "media/capture/video/video_capture_device.h" - -namespace base { -class Location; -} // namespace base - -namespace media { - -struct VideoCaptureParams; - -class ThreadSafeCaptureOracle; - -// Keeps track of the video capture source frames and executes copying. -class CAPTURE_EXPORT VideoCaptureMachine { - public: - VideoCaptureMachine(); - virtual ~VideoCaptureMachine(); - - // Starts capturing. - // |callback| is invoked with true if succeeded. Otherwise, with false. - virtual void Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, - const VideoCaptureParams& params, - const base::Callback<void(bool)> callback) = 0; - - // Suspend/Resume frame delivery. Implementations of these are optional. - virtual void Suspend() {} - virtual void Resume() {} - - // Stops capturing. - // |callback| is invoked after the capturing has stopped. - virtual void Stop(const base::Closure& callback) = 0; - - // Returns true if the video capture is configured to monitor end-to-end - // system utilization, and alter frame sizes and/or frame rates to mitigate - // overloading or under-utilization. - virtual bool IsAutoThrottlingEnabled() const; - - // The implementation of this method should consult the oracle, using the - // kRefreshRequest event type, to decide whether to initiate a new frame - // capture, and then do so if the oracle agrees. - virtual void MaybeCaptureForRefresh() = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(VideoCaptureMachine); -}; - -// The "meat" of a content video capturer. -// -// Separating this from the "shell classes" WebContentsVideoCaptureDevice and -// DesktopCaptureDeviceAura allows safe destruction without needing to block any -// threads, as well as code sharing. -// -// ScreenCaptureDeviceCore manages a simple state machine and the pipeline -// (see notes at top of this file). It times the start of successive captures -// and facilitates the processing of each through the stages of the -// pipeline. -class CAPTURE_EXPORT ScreenCaptureDeviceCore - : public base::SupportsWeakPtr<ScreenCaptureDeviceCore> { - public: - ScreenCaptureDeviceCore(std::unique_ptr<VideoCaptureMachine> capture_machine); - virtual ~ScreenCaptureDeviceCore(); - - // Asynchronous requests to change ScreenCaptureDeviceCore state. - void AllocateAndStart(const VideoCaptureParams& params, - std::unique_ptr<VideoCaptureDevice::Client> client); - void RequestRefreshFrame(); - void Suspend(); - void Resume(); - void StopAndDeAllocate(); - void OnConsumerReportingUtilization(int frame_feedback_id, - double utilization); - - private: - // Flag indicating current state. - enum State { kIdle, kCapturing, kSuspended, kError, kLastCaptureState }; - - void TransitionStateTo(State next_state); - - // Called back in response to StartCaptureMachine(). |success| is true if - // capture machine succeeded to start. - void CaptureStarted(bool success); - - // Stops capturing and notifies client_ of an error state. - void Error(const base::Location& from_here, const std::string& reason); - - // Tracks that all activity occurs on the media stream manager's thread. - base::ThreadChecker thread_checker_; - - // Current lifecycle state. - State state_; - - // Tracks the CaptureMachine that's doing work on our behalf - // on the device thread or UI thread. - // This value should never be dereferenced by this class. - std::unique_ptr<VideoCaptureMachine> capture_machine_; - - // Our thread-safe capture oracle which serves as the gateway to the video - // capture pipeline. Besides the VideoCaptureDevice itself, it is the only - // component of the system with direct access to |client_|. - scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; - - DISALLOW_COPY_AND_ASSIGN(ScreenCaptureDeviceCore); -}; - -} // namespace media - -#endif // MEDIA_CAPTURE_CONTENT_SCREEN_CAPTURE_DEVICE_CORE_H_ diff --git a/chromium/media/capture/mojom/video_capture_types.mojom b/chromium/media/capture/mojom/video_capture_types.mojom index 414b5ca327f..b59c87abfcb 100644 --- a/chromium/media/capture/mojom/video_capture_types.mojom +++ b/chromium/media/capture/mojom/video_capture_types.mojom @@ -50,6 +50,12 @@ enum PowerLineFrequency { HZ_60 }; +enum VideoFacingMode { + NONE, + USER, + ENVIRONMENT +}; + enum VideoCaptureApi { LINUX_V4L2_SINGLE_PLANE, WIN_MEDIA_FOUNDATION, @@ -61,6 +67,7 @@ enum VideoCaptureApi { ANDROID_API2_LEGACY, ANDROID_API2_FULL, ANDROID_API2_LIMITED, + VIRTUAL_DEVICE, UNKNOWN }; @@ -70,6 +77,18 @@ enum VideoCaptureTransportType { OTHER_TRANSPORT }; +enum VideoCaptureBufferType { + kSharedMemory, + + // Warning: This case is a workaround for compatibility with an older version + // of Mojo only and will be deleted as soon as the Mojo version of ChromiumOS + // becomes compatible with the |kSharedMemory|. + // TODO(chfremer): Remove this when https://crbug.com/857537 is resolved. + kSharedMemoryViaRawFileDescriptor, + + kMailboxHolder +}; + struct VideoCaptureFormat { gfx.mojom.Size frame_size; float frame_rate; @@ -78,6 +97,7 @@ struct VideoCaptureFormat { struct VideoCaptureParams { VideoCaptureFormat requested_format; + VideoCaptureBufferType buffer_type; ResolutionChangePolicy resolution_change_policy; PowerLineFrequency power_line_frequency; }; @@ -101,6 +121,7 @@ struct VideoCaptureDeviceDescriptor { string display_name; string device_id; string model_id; + VideoFacingMode facing_mode; VideoCaptureApi capture_api; VideoCaptureTransportType transport_type; VideoCaptureDeviceDescriptorCameraCalibration? camera_calibration; @@ -116,8 +137,14 @@ struct MailboxBufferHandleSet { array<gpu.mojom.MailboxHolder, 4> mailbox_holder; }; +struct SharedMemoryViaRawFileDescriptor { + handle file_descriptor_handle; + uint32 shared_memory_size_in_bytes; +}; + union VideoBufferHandle { handle<shared_buffer> shared_buffer_handle; + SharedMemoryViaRawFileDescriptor shared_memory_via_raw_file_descriptor; MailboxBufferHandleSet mailbox_handles; }; diff --git a/chromium/media/capture/mojom/video_capture_types.typemap b/chromium/media/capture/mojom/video_capture_types.typemap index 27b85993df2..cec8543cd92 100644 --- a/chromium/media/capture/mojom/video_capture_types.typemap +++ b/chromium/media/capture/mojom/video_capture_types.typemap @@ -33,6 +33,7 @@ type_mappings = [ "media.mojom.ResolutionChangePolicy=media::ResolutionChangePolicy", "media.mojom.PowerLineFrequency=media::PowerLineFrequency", "media.mojom.VideoCapturePixelFormat=media::VideoPixelFormat", + "media.mojom.VideoCaptureBufferType=media::VideoCaptureBufferType", "media.mojom.VideoCaptureFormat=media::VideoCaptureFormat", "media.mojom.VideoCaptureParams=media::VideoCaptureParams", "media.mojom.VideoCaptureDeviceDescriptorCameraCalibration=media::VideoCaptureDeviceDescriptor::CameraCalibration", diff --git a/chromium/media/capture/mojom/video_capture_types_mojom_traits.cc b/chromium/media/capture/mojom/video_capture_types_mojom_traits.cc index 396b0139456..f02c0ac60c3 100644 --- a/chromium/media/capture/mojom/video_capture_types_mojom_traits.cc +++ b/chromium/media/capture/mojom/video_capture_types_mojom_traits.cc @@ -234,6 +234,84 @@ bool EnumTraits<media::mojom::VideoCapturePixelFormat, } // static +media::mojom::VideoCaptureBufferType +EnumTraits<media::mojom::VideoCaptureBufferType, + media::VideoCaptureBufferType>::ToMojom(media::VideoCaptureBufferType + input) { + switch (input) { + case media::VideoCaptureBufferType::kSharedMemory: + return media::mojom::VideoCaptureBufferType::kSharedMemory; + case media::VideoCaptureBufferType::kSharedMemoryViaRawFileDescriptor: + return media::mojom::VideoCaptureBufferType:: + kSharedMemoryViaRawFileDescriptor; + case media::VideoCaptureBufferType::kMailboxHolder: + return media::mojom::VideoCaptureBufferType::kMailboxHolder; + } + NOTREACHED(); + return media::mojom::VideoCaptureBufferType::kSharedMemory; +} + +// static +bool EnumTraits<media::mojom::VideoCaptureBufferType, + media::VideoCaptureBufferType>:: + FromMojom(media::mojom::VideoCaptureBufferType input, + media::VideoCaptureBufferType* output) { + switch (input) { + case media::mojom::VideoCaptureBufferType::kSharedMemory: + *output = media::VideoCaptureBufferType::kSharedMemory; + return true; + case media::mojom::VideoCaptureBufferType:: + kSharedMemoryViaRawFileDescriptor: + *output = + media::VideoCaptureBufferType::kSharedMemoryViaRawFileDescriptor; + return true; + case media::mojom::VideoCaptureBufferType::kMailboxHolder: + *output = media::VideoCaptureBufferType::kMailboxHolder; + return true; + } + NOTREACHED(); + return false; +} + +// static +media::mojom::VideoFacingMode +EnumTraits<media::mojom::VideoFacingMode, media::VideoFacingMode>::ToMojom( + media::VideoFacingMode input) { + switch (input) { + case media::VideoFacingMode::MEDIA_VIDEO_FACING_NONE: + return media::mojom::VideoFacingMode::NONE; + case media::VideoFacingMode::MEDIA_VIDEO_FACING_USER: + return media::mojom::VideoFacingMode::USER; + case media::VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT: + return media::mojom::VideoFacingMode::ENVIRONMENT; + case media::VideoFacingMode::NUM_MEDIA_VIDEO_FACING_MODES: + NOTREACHED(); + return media::mojom::VideoFacingMode::NONE; + } + NOTREACHED(); + return media::mojom::VideoFacingMode::NONE; +} + +// static +bool EnumTraits<media::mojom::VideoFacingMode, media::VideoFacingMode>:: + FromMojom(media::mojom::VideoFacingMode input, + media::VideoFacingMode* output) { + switch (input) { + case media::mojom::VideoFacingMode::NONE: + *output = media::VideoFacingMode::MEDIA_VIDEO_FACING_NONE; + return true; + case media::mojom::VideoFacingMode::USER: + *output = media::VideoFacingMode::MEDIA_VIDEO_FACING_USER; + return true; + case media::mojom::VideoFacingMode::ENVIRONMENT: + *output = media::VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT; + return true; + } + NOTREACHED(); + return false; +} + +// static media::mojom::VideoCaptureApi EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi>::ToMojom( media::VideoCaptureApi input) { @@ -258,6 +336,8 @@ EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi>::ToMojom( return media::mojom::VideoCaptureApi::ANDROID_API2_FULL; case media::VideoCaptureApi::ANDROID_API2_LIMITED: return media::mojom::VideoCaptureApi::ANDROID_API2_LIMITED; + case media::VideoCaptureApi::VIRTUAL_DEVICE: + return media::mojom::VideoCaptureApi::VIRTUAL_DEVICE; case media::VideoCaptureApi::UNKNOWN: return media::mojom::VideoCaptureApi::UNKNOWN; } @@ -300,6 +380,9 @@ bool EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi>:: case media::mojom::VideoCaptureApi::ANDROID_API2_LIMITED: *output = media::VideoCaptureApi::ANDROID_API2_LIMITED; return true; + case media::mojom::VideoCaptureApi::VIRTUAL_DEVICE: + *output = media::VideoCaptureApi::VIRTUAL_DEVICE; + return true; case media::mojom::VideoCaptureApi::UNKNOWN: *output = media::VideoCaptureApi::UNKNOWN; return true; @@ -360,6 +443,8 @@ bool StructTraits<media::mojom::VideoCaptureParamsDataView, media::VideoCaptureParams* out) { if (!data.ReadRequestedFormat(&out->requested_format)) return false; + if (!data.ReadBufferType(&out->buffer_type)) + return false; if (!data.ReadResolutionChangePolicy(&out->resolution_change_policy)) return false; if (!data.ReadPowerLineFrequency(&out->power_line_frequency)) @@ -394,6 +479,8 @@ bool StructTraits<media::mojom::VideoCaptureDeviceDescriptorDataView, return false; if (!data.ReadModelId(&(output->model_id))) return false; + if (!data.ReadFacingMode(&(output->facing))) + return false; if (!data.ReadCaptureApi(&(output->capture_api))) return false; if (!data.ReadTransportType(&(output->transport_type))) diff --git a/chromium/media/capture/mojom/video_capture_types_mojom_traits.h b/chromium/media/capture/mojom/video_capture_types_mojom_traits.h index 4c9283c48da..1b7649a2c4a 100644 --- a/chromium/media/capture/mojom/video_capture_types_mojom_traits.h +++ b/chromium/media/capture/mojom/video_capture_types_mojom_traits.h @@ -5,6 +5,7 @@ #ifndef MEDIA_CAPTURE_MOJOM_VIDEO_CAPTURE_TYPES_MOJOM_TRAITS_H_ #define MEDIA_CAPTURE_MOJOM_VIDEO_CAPTURE_TYPES_MOJOM_TRAITS_H_ +#include "media/base/video_facing.h" #include "media/capture/mojom/video_capture_types.mojom.h" #include "media/capture/video/video_capture_device_descriptor.h" #include "media/capture/video/video_capture_device_info.h" @@ -41,6 +42,23 @@ struct EnumTraits<media::mojom::VideoCapturePixelFormat, }; template <> +struct EnumTraits<media::mojom::VideoCaptureBufferType, + media::VideoCaptureBufferType> { + static media::mojom::VideoCaptureBufferType ToMojom( + media::VideoCaptureBufferType buffer_type); + + static bool FromMojom(media::mojom::VideoCaptureBufferType input, + media::VideoCaptureBufferType* out); +}; + +template <> +struct EnumTraits<media::mojom::VideoFacingMode, media::VideoFacingMode> { + static media::mojom::VideoFacingMode ToMojom(media::VideoFacingMode input); + static bool FromMojom(media::mojom::VideoFacingMode input, + media::VideoFacingMode* output); +}; + +template <> struct EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi> { static media::mojom::VideoCaptureApi ToMojom(media::VideoCaptureApi input); static bool FromMojom(media::mojom::VideoCaptureApi input, @@ -84,6 +102,11 @@ struct StructTraits<media::mojom::VideoCaptureParamsDataView, return params.requested_format; } + static media::VideoCaptureBufferType buffer_type( + const media::VideoCaptureParams& params) { + return params.buffer_type; + } + static media::ResolutionChangePolicy resolution_change_policy( const media::VideoCaptureParams& params) { return params.resolution_change_policy; @@ -145,6 +168,11 @@ struct StructTraits<media::mojom::VideoCaptureDeviceDescriptorDataView, return input.model_id; } + static media::VideoFacingMode facing_mode( + const media::VideoCaptureDeviceDescriptor& input) { + return input.facing; + } + static media::VideoCaptureApi capture_api( const media::VideoCaptureDeviceDescriptor& input) { return input.capture_api; diff --git a/chromium/media/capture/run_all_unittests.cc b/chromium/media/capture/run_all_unittests.cc index d196bb67efc..9c4b2770c53 100644 --- a/chromium/media/capture/run_all_unittests.cc +++ b/chromium/media/capture/run_all_unittests.cc @@ -9,8 +9,8 @@ #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" #include "base/threading/thread.h" -#include "mojo/edk/embedder/embedder.h" -#include "mojo/edk/embedder/scoped_ipc_support.h" +#include "mojo/core/embedder/embedder.h" +#include "mojo/core/embedder/scoped_ipc_support.h" #include "testing/gtest/include/gtest/gtest.h" class MojoEnabledTestEnvironment final : public testing::Environment { @@ -20,12 +20,12 @@ class MojoEnabledTestEnvironment final : public testing::Environment { ~MojoEnabledTestEnvironment() final = default; void SetUp() final { - mojo::edk::Init(); + mojo::core::Init(); mojo_ipc_thread_.StartWithOptions( base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); - mojo_ipc_support_.reset(new mojo::edk::ScopedIPCSupport( + mojo_ipc_support_.reset(new mojo::core::ScopedIPCSupport( mojo_ipc_thread_.task_runner(), - mojo::edk::ScopedIPCSupport::ShutdownPolicy::FAST)); + mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST)); VLOG(1) << "Mojo initialized"; } @@ -36,7 +36,7 @@ class MojoEnabledTestEnvironment final : public testing::Environment { private: base::Thread mojo_ipc_thread_; - std::unique_ptr<mojo::edk::ScopedIPCSupport> mojo_ipc_support_; + std::unique_ptr<mojo::core::ScopedIPCSupport> mojo_ipc_support_; }; int main(int argc, char* argv[]) { diff --git a/chromium/media/capture/video/android/video_capture_device_factory_android.cc b/chromium/media/capture/video/android/video_capture_device_factory_android.cc index e1a0cba1908..ae4e875731b 100644 --- a/chromium/media/capture/video/android/video_capture_device_factory_android.cc +++ b/chromium/media/capture/video/android/video_capture_device_factory_android.cc @@ -154,14 +154,4 @@ bool VideoCaptureDeviceFactoryAndroid::IsLegacyOrDeprecatedDevice( AttachCurrentThread(), id)); } -// static -VideoCaptureDeviceFactory* -VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, - MojoJpegDecodeAcceleratorFactoryCB jda_factory, - MojoJpegEncodeAcceleratorFactoryCB jea_factory) { - return new VideoCaptureDeviceFactoryAndroid(); -} - } // namespace media diff --git a/chromium/media/capture/video/chromeos/DEPS b/chromium/media/capture/video/chromeos/DEPS index fe2df0dba85..f1958045109 100644 --- a/chromium/media/capture/video/chromeos/DEPS +++ b/chromium/media/capture/video/chromeos/DEPS @@ -1,5 +1,4 @@ include_rules = [ "+chromeos/dbus", - "+mojo/edk/embedder", "+third_party/libsync", ] diff --git a/chromium/media/capture/video/chromeos/camera_device_delegate.cc b/chromium/media/capture/video/chromeos/camera_device_delegate.cc index 8505fcf230b..ad245ae399b 100644 --- a/chromium/media/capture/video/chromeos/camera_device_delegate.cc +++ b/chromium/media/capture/video/chromeos/camera_device_delegate.cc @@ -9,6 +9,7 @@ #include <utility> #include <vector> +#include "base/posix/safe_strerror.h" #include "media/base/bind_to_current_loop.h" #include "media/capture/mojom/image_capture_types.h" #include "media/capture/video/blob_utils.h" @@ -18,8 +19,6 @@ #include "media/capture/video/chromeos/camera_hal_delegate.h" #include "media/capture/video/chromeos/camera_metadata_utils.h" #include "media/capture/video/chromeos/stream_buffer_manager.h" -#include "mojo/edk/embedder/embedder.h" -#include "mojo/edk/embedder/scoped_platform_handle.h" namespace media { @@ -288,7 +287,7 @@ void CameraDeviceDelegate::OnClosed(int32_t result) { device_context_->SetState(CameraDeviceContext::State::kStopped); if (result) { device_context_->LogToClient(std::string("Failed to close device: ") + - std::string(strerror(result))); + base::safe_strerror(-result)); } ResetMojoInterface(); device_context_ = nullptr; @@ -397,8 +396,8 @@ void CameraDeviceDelegate::OnInitialized(int32_t result) { } if (result) { device_context_->SetErrorState( - FROM_HERE, std::string("Failed to initialize camera device") + - std::string(strerror(result))); + FROM_HERE, std::string("Failed to initialize camera device: ") + + base::safe_strerror(-result)); return; } device_context_->SetState(CameraDeviceContext::State::kInitialized); @@ -471,7 +470,7 @@ void CameraDeviceDelegate::OnConfiguredStreams( if (result) { device_context_->SetErrorState( FROM_HERE, std::string("Failed to configure streams: ") + - std::string(strerror(result))); + base::safe_strerror(-result)); return; } if (!updated_config || diff --git a/chromium/media/capture/video/chromeos/camera_device_delegate_unittest.cc b/chromium/media/capture/video/chromeos/camera_device_delegate_unittest.cc index aa0f3c91fcc..aad0c9bac8b 100644 --- a/chromium/media/capture/video/chromeos/camera_device_delegate_unittest.cc +++ b/chromium/media/capture/video/chromeos/camera_device_delegate_unittest.cc @@ -128,7 +128,7 @@ class CameraDeviceDelegateTest : public ::testing::Test { hal_delegate_thread_("HalDelegateThread") {} void SetUp() override { - VideoCaptureDeviceFactoryChromeOS::SetBufferManagerForTesting( + VideoCaptureDeviceFactoryChromeOS::SetGpuBufferManager( &mock_gpu_memory_buffer_manager_); hal_delegate_thread_.Start(); camera_hal_delegate_ = diff --git a/chromium/media/capture/video/chromeos/camera_hal_delegate.cc b/chromium/media/capture/video/chromeos/camera_hal_delegate.cc index 3a33d9b8f89..a47b75b4332 100644 --- a/chromium/media/capture/video/chromeos/camera_hal_delegate.cc +++ b/chromium/media/capture/video/chromeos/camera_hal_delegate.cc @@ -12,6 +12,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/posix/safe_strerror.h" #include "base/strings/string_piece.h" #include "media/capture/video/chromeos/camera_buffer_factory.h" #include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" @@ -85,6 +86,7 @@ std::unique_ptr<VideoCaptureDevice> CameraHalDelegate::CreateDevice( if (!UpdateBuiltInCameraInfo()) { return capture_device; } + base::AutoLock lock(camera_info_lock_); if (camera_info_.find(device_descriptor.device_id) == camera_info_.end()) { LOG(ERROR) << "Invalid camera device: " << device_descriptor.device_id; return capture_device; @@ -103,6 +105,7 @@ void CameraHalDelegate::GetSupportedFormats( return; } std::string camera_id = device_descriptor.device_id; + base::AutoLock lock(camera_info_lock_); if (camera_info_.find(camera_id) == camera_info_.end() || camera_info_[camera_id].is_null()) { LOG(ERROR) << "Invalid camera_id: " << camera_id; @@ -168,13 +171,14 @@ void CameraHalDelegate::GetDeviceDescriptors( if (!UpdateBuiltInCameraInfo()) { return; } - for (size_t id = 0; id < num_builtin_cameras_; ++id) { - VideoCaptureDeviceDescriptor desc; - std::string camera_id = std::to_string(id); - const cros::mojom::CameraInfoPtr& camera_info = camera_info_[camera_id]; + base::AutoLock lock(camera_info_lock_); + for (const auto& it : camera_info_) { + const std::string& camera_id = it.first; + const cros::mojom::CameraInfoPtr& camera_info = it.second; if (!camera_info) { continue; } + VideoCaptureDeviceDescriptor desc; desc.device_id = camera_id; desc.capture_api = VideoCaptureApi::ANDROID_API2_LIMITED; desc.transport_type = VideoCaptureTransportType::OTHER_TRANSPORT; @@ -196,6 +200,7 @@ void CameraHalDelegate::GetDeviceDescriptors( } device_descriptors->push_back(desc); } + // TODO(shik): Report external camera first when lid is closed. // TODO(jcliang): Remove this after JS API supports query camera facing // (http://crbug.com/543997). std::sort(device_descriptors->begin(), device_descriptors->end()); @@ -248,6 +253,9 @@ void CameraHalDelegate::ResetMojoInterfaceOnIpcThread() { } builtin_camera_info_updated_.Reset(); camera_module_has_been_set_.Reset(); + + // Clear all cached camera info, especially external cameras. + camera_info_.clear(); } bool CameraHalDelegate::UpdateBuiltInCameraInfo() { @@ -279,7 +287,7 @@ void CameraHalDelegate::UpdateBuiltInCameraInfoOnIpcThread() { void CameraHalDelegate::OnGotNumberOfCamerasOnIpcThread(int32_t num_cameras) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - if (num_cameras <= 0) { + if (num_cameras < 0) { builtin_camera_info_updated_.Signal(); LOG(ERROR) << "Failed to get number of cameras: " << num_cameras; return; @@ -303,9 +311,16 @@ void CameraHalDelegate::OnSetCallbacksOnIpcThread(int32_t result) { if (result) { num_builtin_cameras_ = 0; builtin_camera_info_updated_.Signal(); - LOG(ERROR) << "Failed to set camera module callbacks: " << strerror(result); + LOG(ERROR) << "Failed to set camera module callbacks: " + << base::safe_strerror(-result); + return; + } + + if (num_builtin_cameras_ == 0) { + builtin_camera_info_updated_.Signal(); return; } + for (size_t camera_id = 0; camera_id < num_builtin_cameras_; ++camera_id) { GetCameraInfoOnIpcThread( camera_id, @@ -332,9 +347,25 @@ void CameraHalDelegate::OnGotCameraInfoOnIpcThread( } // In case of error |camera_info| is empty. SortCameraMetadata(&camera_info->static_camera_characteristics); + + base::AutoLock lock(camera_info_lock_); camera_info_[std::to_string(camera_id)] = std::move(camera_info); - if (camera_info_.size() == num_builtin_cameras_) { - builtin_camera_info_updated_.Signal(); + + if (camera_id < base::checked_cast<int32_t>(num_builtin_cameras_)) { + // |camera_info_| might contain some entries for external cameras as well, + // we should check all built-in cameras explicitly. + bool all_updated = [&]() { + for (size_t i = 0; i < num_builtin_cameras_; i++) { + if (camera_info_.find(std::to_string(i)) == camera_info_.end()) { + return false; + } + } + return true; + }(); + + if (all_updated) { + builtin_camera_info_updated_.Signal(); + } } } @@ -352,8 +383,30 @@ void CameraHalDelegate::CameraDeviceStatusChange( int32_t camera_id, cros::mojom::CameraDeviceStatus new_status) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); - // TODO(jcliang): Handle status change for external cameras. - NOTIMPLEMENTED() << "CameraDeviceStatusChange is not implemented"; + VLOG(1) << "camera_id = " << camera_id << ", new_status = " << new_status; + base::AutoLock lock(camera_info_lock_); + auto it = camera_info_.find(std::to_string(camera_id)); + switch (new_status) { + case cros::mojom::CameraDeviceStatus::CAMERA_DEVICE_STATUS_PRESENT: + if (it == camera_info_.end()) { + GetCameraInfoOnIpcThread( + camera_id, + base::BindOnce(&CameraHalDelegate::OnGotCameraInfoOnIpcThread, this, + camera_id)); + } else { + LOG(WARNING) << "Ignore duplicated camera_id = " << camera_id; + } + break; + case cros::mojom::CameraDeviceStatus::CAMERA_DEVICE_STATUS_NOT_PRESENT: + if (it != camera_info_.end()) { + camera_info_.erase(it); + } else { + LOG(WARNING) << "Ignore nonexistent camera_id = " << camera_id; + } + break; + default: + NOTREACHED() << "Unexpected new status " << new_status; + } } void CameraHalDelegate::TorchModeStatusChange( diff --git a/chromium/media/capture/video/chromeos/camera_hal_delegate.h b/chromium/media/capture/video/chromeos/camera_hal_delegate.h index b8c0745e063..19050a1d91b 100644 --- a/chromium/media/capture/video/chromeos/camera_hal_delegate.h +++ b/chromium/media/capture/video/chromeos/camera_hal_delegate.h @@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/sequence_checker.h" #include "base/single_thread_task_runner.h" +#include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "media/capture/video/chromeos/mojo/camera3.mojom.h" @@ -129,9 +130,11 @@ class CAPTURE_EXPORT CameraHalDelegate final // reported by the camera HAL, and |camera_info_| stores the camera info of // each camera device. They are modified only on |ipc_task_runner_|. They // are also read in GetSupportedFormats and GetDeviceDescriptors, in which the - // access is sequenced through UpdateBuiltInCameraInfo and - // |builtin_camera_info_updated_| to avoid race conditions. + // access is protected by |camera_info_lock_| and sequenced through + // UpdateBuiltInCameraInfo and |builtin_camera_info_updated_| to avoid race + // conditions. size_t num_builtin_cameras_; + base::Lock camera_info_lock_; std::unordered_map<std::string, cros::mojom::CameraInfoPtr> camera_info_; SEQUENCE_CHECKER(sequence_checker_); diff --git a/chromium/media/capture/video/chromeos/camera_hal_delegate_unittest.cc b/chromium/media/capture/video/chromeos/camera_hal_delegate_unittest.cc index 33349860f1c..4f1f101aa1a 100644 --- a/chromium/media/capture/video/chromeos/camera_hal_delegate_unittest.cc +++ b/chromium/media/capture/video/chromeos/camera_hal_delegate_unittest.cc @@ -31,7 +31,7 @@ class CameraHalDelegateTest : public ::testing::Test { hal_delegate_thread_("HalDelegateThread") {} void SetUp() override { - VideoCaptureDeviceFactoryChromeOS::SetBufferManagerForTesting( + VideoCaptureDeviceFactoryChromeOS::SetGpuBufferManager( &mock_gpu_memory_buffer_manager_); hal_delegate_thread_.Start(); camera_hal_delegate_ = diff --git a/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc index 50eb9cb16a8..ade9c3e55ce 100644 --- a/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc +++ b/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc @@ -14,15 +14,14 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/posix/eintr_wrapper.h" +#include "base/rand_util.h" #include "base/single_thread_task_runner.h" +#include "base/strings/string_number_conversions.h" #include "base/synchronization/waitable_event.h" -#include "mojo/edk/embedder/embedder.h" -#include "mojo/edk/embedder/named_platform_handle.h" -#include "mojo/edk/embedder/named_platform_handle_utils.h" -#include "mojo/edk/embedder/outgoing_broker_client_invitation.h" -#include "mojo/edk/embedder/platform_channel_pair.h" -#include "mojo/edk/embedder/platform_channel_utils_posix.h" -#include "mojo/edk/embedder/scoped_platform_handle.h" +#include "mojo/public/cpp/platform/named_platform_channel.h" +#include "mojo/public/cpp/platform/platform_channel.h" +#include "mojo/public/cpp/platform/socket_utils_posix.h" +#include "mojo/public/cpp/system/invitation.h" namespace media { @@ -32,6 +31,12 @@ const base::FilePath::CharType kArcCamera3SocketPath[] = "/var/run/camera/camera3.sock"; const char kArcCameraGroup[] = "arc-camera"; +std::string GenerateRandomToken() { + char random_bytes[16]; + base::RandBytes(random_bytes, 16); + return base::HexEncode(random_bytes, 16); +} + // Creates a pipe. Returns true on success, otherwise false. // On success, |read_fd| will be set to the fd of the read side, and // |write_fd| will be set to the one of write side. @@ -211,10 +216,10 @@ void CameraHalDispatcherImpl::CreateSocket(base::WaitableEvent* started) { DCHECK(blocking_io_task_runner_->BelongsToCurrentThread()); base::FilePath socket_path(kArcCamera3SocketPath); - mojo::edk::ScopedInternalPlatformHandle socket_fd = - mojo::edk::CreateServerHandle( - mojo::edk::NamedPlatformHandle(socket_path.value())); - if (!socket_fd.is_valid()) { + mojo::NamedPlatformChannel::Options options; + options.server_name = socket_path.value(); + mojo::NamedPlatformChannel channel(options); + if (!channel.server_endpoint().is_valid()) { LOG(ERROR) << "Failed to create the socket file: " << kArcCamera3SocketPath; started->Signal(); return; @@ -253,13 +258,13 @@ void CameraHalDispatcherImpl::CreateSocket(base::WaitableEvent* started) { blocking_io_task_runner_->PostTask( FROM_HERE, base::BindOnce(&CameraHalDispatcherImpl::StartServiceLoop, - base::Unretained(this), base::Passed(&socket_fd), + base::Unretained(this), + channel.TakeServerEndpoint().TakePlatformHandle().TakeFD(), base::Unretained(started))); } -void CameraHalDispatcherImpl::StartServiceLoop( - mojo::edk::ScopedInternalPlatformHandle socket_fd, - base::WaitableEvent* started) { +void CameraHalDispatcherImpl::StartServiceLoop(base::ScopedFD socket_fd, + base::WaitableEvent* started) { DCHECK(blocking_io_task_runner_->BelongsToCurrentThread()); DCHECK(!proxy_fd_.is_valid()); DCHECK(!cancel_pipe_.is_valid()); @@ -277,34 +282,35 @@ void CameraHalDispatcherImpl::StartServiceLoop( VLOG(1) << "CameraHalDispatcherImpl started; waiting for incoming connection"; while (true) { - if (!WaitForSocketReadable(proxy_fd_.get().handle, cancel_fd.get())) { + if (!WaitForSocketReadable(proxy_fd_.get(), cancel_fd.get())) { VLOG(1) << "Quit CameraHalDispatcherImpl IO thread"; return; } - mojo::edk::ScopedInternalPlatformHandle accepted_fd; - if (mojo::edk::ServerAcceptConnection(proxy_fd_, &accepted_fd, false) && + base::ScopedFD accepted_fd; + if (mojo::AcceptSocketConnection(proxy_fd_.get(), &accepted_fd, false) && accepted_fd.is_valid()) { VLOG(1) << "Accepted a connection"; // Hardcode pid 0 since it is unused in mojo. const base::ProcessHandle kUnusedChildProcessHandle = 0; - mojo::edk::PlatformChannelPair channel_pair; - mojo::edk::OutgoingBrokerClientInvitation invitation; + mojo::PlatformChannel channel; + mojo::OutgoingInvitation invitation; - std::string token = mojo::edk::GenerateRandomToken(); + // Generate an arbitrary 32-byte string, as we use this length as a + // protocol version identifier. + std::string token = GenerateRandomToken(); mojo::ScopedMessagePipeHandle pipe = invitation.AttachMessagePipe(token); + mojo::OutgoingInvitation::Send(std::move(invitation), + kUnusedChildProcessHandle, + channel.TakeLocalEndpoint()); - invitation.Send( - kUnusedChildProcessHandle, - mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy, - channel_pair.PassServerHandle())); - - std::vector<mojo::edk::ScopedInternalPlatformHandle> handles; - handles.emplace_back(channel_pair.PassClientHandle()); + auto remote_endpoint = channel.TakeRemoteEndpoint(); + std::vector<base::ScopedFD> fds; + fds.emplace_back(remote_endpoint.TakePlatformHandle().TakeFD()); struct iovec iov = {const_cast<char*>(token.c_str()), token.length()}; - ssize_t result = mojo::edk::PlatformChannelSendmsgWithHandles( - accepted_fd, &iov, 1, handles); + ssize_t result = + mojo::SendmsgWithHandles(accepted_fd.get(), &iov, 1, fds); if (result == -1) { PLOG(ERROR) << "sendmsg()"; } else { diff --git a/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.h b/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.h index 7470f777b4b..1eecadcc781 100644 --- a/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.h +++ b/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.h @@ -8,14 +8,15 @@ #include <memory> #include <set> +#include "base/files/scoped_file.h" #include "base/memory/singleton.h" #include "base/threading/thread.h" #include "media/capture/capture_export.h" #include "media/capture/video/chromeos/mojo/cros_camera_service.mojom.h" #include "media/capture/video/video_capture_device_factory.h" -#include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/bindings/interface_ptr_set.h" +#include "mojo/public/cpp/platform/platform_channel_server_endpoint.h" namespace base { @@ -78,8 +79,7 @@ class CAPTURE_EXPORT CameraHalDispatcherImpl final // Waits for incoming connections (from HAL process or from client processes). // Runs on |blocking_io_thread_|. - void StartServiceLoop(mojo::edk::ScopedInternalPlatformHandle socket_fd, - base::WaitableEvent* started); + void StartServiceLoop(base::ScopedFD socket_fd, base::WaitableEvent* started); void AddClientObserverOnProxyThread( std::unique_ptr<CameraClientObserver> observer); @@ -95,7 +95,7 @@ class CAPTURE_EXPORT CameraHalDispatcherImpl final void StopOnProxyThread(); - mojo::edk::ScopedInternalPlatformHandle proxy_fd_; + base::ScopedFD proxy_fd_; base::ScopedFD cancel_pipe_; base::Thread proxy_thread_; diff --git a/chromium/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc b/chromium/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc index 020ca137016..eab11a8e646 100644 --- a/chromium/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc +++ b/chromium/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc @@ -150,7 +150,9 @@ class GpuMemoryBufferImplGbm : public gfx::GpuMemoryBuffer { gfx::GpuMemoryBufferId GetId() const override { return handle_.id; } - gfx::GpuMemoryBufferHandle GetHandle() const override { return handle_; } + gfx::GpuMemoryBufferHandle GetHandle() const override { + return gfx::CloneHandleForIPC(handle_); + } ClientBuffer AsClientBuffer() override { return reinterpret_cast<ClientBuffer>(this); diff --git a/chromium/media/capture/video/chromeos/mojo/camera_metadata_tags.mojom b/chromium/media/capture/video/chromeos/mojo/camera_metadata_tags.mojom index d4543e7bb73..4fcfad8dcd7 100644 --- a/chromium/media/capture/video/chromeos/mojo/camera_metadata_tags.mojom +++ b/chromium/media/capture/video/chromeos/mojo/camera_metadata_tags.mojom @@ -1,5 +1,5 @@ /* - * Copyright 2017 The Android Open Source Project + * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,7 +55,9 @@ enum CameraMetadataSection { ANDROID_SYNC = 0x17, ANDROID_REPROCESS = 0x18, ANDROID_DEPTH = 0x19, - ANDROID_SECTION_COUNT = 0x1A, + ANDROID_LOGICAL_MULTI_CAMERA = 0x1A, + ANDROID_DISTORTION_CORRECTION = 0x1B, + ANDROID_SECTION_COUNT = 0x1C, VENDOR_SECTION = 0x8000 }; @@ -92,6 +94,10 @@ enum CameraMetadataSectionStart { ANDROID_SYNC_START = 0x170000, ANDROID_REPROCESS_START = 0x180000, ANDROID_DEPTH_START = 0x190000, + ANDROID_LOGICAL_MULTI_CAMERA_START + = 0x1A0000, + ANDROID_DISTORTION_CORRECTION_START + = 0x1B0000, // Mojom maps enum to int32_t in C++. This causes problem on the VENDOR_SECTION_START // below as 0x80000000 would generate -Wc++11-narrowing warnings while compiling the @@ -155,6 +161,7 @@ enum CameraMetadataTag { ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE, ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST, ANDROID_CONTROL_ENABLE_ZSL, + ANDROID_CONTROL_AF_SCENE_CHANGE, ANDROID_CONTROL_END, ANDROID_DEMOSAIC_MODE = 0x20000, // ANDROID_DEMOSAIC_START, ANDROID_DEMOSAIC_END, @@ -198,6 +205,8 @@ enum CameraMetadataTag { ANDROID_LENS_STATE, ANDROID_LENS_INTRINSIC_CALIBRATION, ANDROID_LENS_RADIAL_DISTORTION, + ANDROID_LENS_POSE_REFERENCE, + ANDROID_LENS_DISTORTION, ANDROID_LENS_END, ANDROID_LENS_INFO_AVAILABLE_APERTURES = 0x90000, // ANDROID_LENS_INFO_START, ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES, @@ -234,6 +243,8 @@ enum CameraMetadataTag { ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, + ANDROID_REQUEST_AVAILABLE_SESSION_KEYS, + ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS, ANDROID_REQUEST_END, ANDROID_SCALER_CROP_REGION = 0xD0000, // ANDROID_SCALER_START, ANDROID_SCALER_AVAILABLE_FORMATS, @@ -315,6 +326,10 @@ enum CameraMetadataTag { ANDROID_STATISTICS_SCENE_FLICKER, ANDROID_STATISTICS_HOT_PIXEL_MAP, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, + ANDROID_STATISTICS_OIS_DATA_MODE, + ANDROID_STATISTICS_OIS_TIMESTAMPS, + ANDROID_STATISTICS_OIS_X_SHIFTS, + ANDROID_STATISTICS_OIS_Y_SHIFTS, ANDROID_STATISTICS_END, ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES = 0x120000, // ANDROID_STATISTICS_INFO_START, @@ -325,6 +340,7 @@ enum CameraMetadataTag { ANDROID_STATISTICS_INFO_SHARPNESS_MAP_SIZE, ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, + ANDROID_STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES, ANDROID_STATISTICS_INFO_END, ANDROID_TONEMAP_CURVE_BLUE = 0x130000, // ANDROID_TONEMAP_START, ANDROID_TONEMAP_CURVE_GREEN, @@ -339,6 +355,7 @@ enum CameraMetadataTag { ANDROID_LED_AVAILABLE_LEDS, ANDROID_LED_END, ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL = 0x150000, // ANDROID_INFO_START, + ANDROID_INFO_VERSION, ANDROID_INFO_END, ANDROID_BLACK_LEVEL_LOCK = 0x160000, // ANDROID_BLACK_LEVEL_START, ANDROID_BLACK_LEVEL_END, @@ -354,6 +371,12 @@ enum CameraMetadataTag { ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS, ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE, ANDROID_DEPTH_END, + ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS = 0x1A0000, // ANDROID_LOGICAL_MULTI_CAMERA_START, + ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE, + ANDROID_LOGICAL_MULTI_CAMERA_END, + ANDROID_DISTORTION_CORRECTION_MODE = 0x1B0000, // ANDROID_DISTORTION_CORRECTION_START, + ANDROID_DISTORTION_CORRECTION_AVAILABLE_MODES, + ANDROID_DISTORTION_CORRECTION_END, }; /** @@ -395,6 +418,7 @@ enum AndroidControlAeMode { ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH, ANDROID_CONTROL_AE_MODE_ON_ALWAYS_FLASH, ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE, + ANDROID_CONTROL_AE_MODE_ON_EXTERNAL_FLASH, }; // ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER @@ -449,6 +473,7 @@ enum AndroidControlCaptureIntent { ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT, ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG, ANDROID_CONTROL_CAPTURE_INTENT_MANUAL, + ANDROID_CONTROL_CAPTURE_INTENT_MOTION_TRACKING, }; // ANDROID_CONTROL_EFFECT_MODE @@ -551,6 +576,12 @@ enum AndroidControlEnableZsl { ANDROID_CONTROL_ENABLE_ZSL_TRUE, }; +// ANDROID_CONTROL_AF_SCENE_CHANGE +enum AndroidControlAfSceneChange { + ANDROID_CONTROL_AF_SCENE_CHANGE_NOT_DETECTED, + ANDROID_CONTROL_AF_SCENE_CHANGE_DETECTED, +}; + // ANDROID_DEMOSAIC_MODE enum AndroidDemosaicMode { ANDROID_DEMOSAIC_MODE_FAST, @@ -613,6 +644,12 @@ enum AndroidLensState { ANDROID_LENS_STATE_MOVING, }; +// ANDROID_LENS_POSE_REFERENCE +enum AndroidLensPoseReference { + ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA, + ANDROID_LENS_POSE_REFERENCE_GYROSCOPE, +}; + // ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION enum AndroidLensInfoFocusDistanceCalibration { ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED, @@ -659,6 +696,9 @@ enum AndroidRequestAvailableCapabilities { ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING, ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT, ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO, + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING, + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA, + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME, }; // ANDROID_SCALER_AVAILABLE_FORMATS @@ -783,6 +823,12 @@ enum AndroidStatisticsLensShadingMapMode { ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON, }; +// ANDROID_STATISTICS_OIS_DATA_MODE +enum AndroidStatisticsOisDataMode { + ANDROID_STATISTICS_OIS_DATA_MODE_OFF, + ANDROID_STATISTICS_OIS_DATA_MODE_ON, +}; + // ANDROID_TONEMAP_MODE enum AndroidTonemapMode { ANDROID_TONEMAP_MODE_CONTRAST_CURVE, @@ -815,6 +861,7 @@ enum AndroidInfoSupportedHardwareLevel { ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL, ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY, ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3, + ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL, }; // ANDROID_BLACK_LEVEL_LOCK @@ -846,3 +893,16 @@ enum AndroidDepthDepthIsExclusive { ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE_FALSE, ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE_TRUE, }; + +// ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE +enum AndroidLogicalMultiCameraSensorSyncType { + ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE, + ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED, +}; + +// ANDROID_DISTORTION_CORRECTION_MODE +enum AndroidDistortionCorrectionMode { + ANDROID_DISTORTION_CORRECTION_MODE_OFF, + ANDROID_DISTORTION_CORRECTION_MODE_FAST, + ANDROID_DISTORTION_CORRECTION_MODE_HIGH_QUALITY, +}; diff --git a/chromium/media/capture/video/chromeos/pixel_format_utils.cc b/chromium/media/capture/video/chromeos/pixel_format_utils.cc index 6f9d4e3645c..a4197a81921 100644 --- a/chromium/media/capture/video/chromeos/pixel_format_utils.cc +++ b/chromium/media/capture/video/chromeos/pixel_format_utils.cc @@ -4,7 +4,7 @@ #include "media/capture/video/chromeos/pixel_format_utils.h" -#include <libdrm/drm_fourcc.h> +#include <drm_fourcc.h> namespace media { diff --git a/chromium/media/capture/video/chromeos/public/BUILD.gn b/chromium/media/capture/video/chromeos/public/BUILD.gn new file mode 100644 index 00000000000..092ba2c6fc2 --- /dev/null +++ b/chromium/media/capture/video/chromeos/public/BUILD.gn @@ -0,0 +1,14 @@ +# 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. + +source_set("public") { + sources = [ + "cros_features.cc", + "cros_features.h", + ] + + public_deps = [ + "//base", + ] +} diff --git a/chromium/media/capture/video/chromeos/public/cros_features.cc b/chromium/media/capture/video/chromeos/public/cros_features.cc new file mode 100644 index 00000000000..4658f93134c --- /dev/null +++ b/chromium/media/capture/video/chromeos/public/cros_features.cc @@ -0,0 +1,19 @@ +// 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/video/chromeos/public/cros_features.h" + +#include "base/files/file_util.h" + +namespace media { + +bool ShouldUseCrosCameraService() { + // Checks whether the Chrome OS binary which provides the HAL v3 camera + // service is installed on the device. If the binary exists we assume the + // device is using the new camera HAL v3 stack. + const base::FilePath kCrosCameraService("/usr/bin/cros_camera_service"); + return base::PathExists(kCrosCameraService); +} + +} // namespace media diff --git a/chromium/media/capture/video/chromeos/public/cros_features.h b/chromium/media/capture/video/chromeos/public/cros_features.h new file mode 100644 index 00000000000..94797d4d8a5 --- /dev/null +++ b/chromium/media/capture/video/chromeos/public/cros_features.h @@ -0,0 +1,16 @@ +// 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_VIDEO_CHROMEOS_PUBLIC_CROS_FEATURES_H_ +#define MEDIA_CAPTURE_VIDEO_CHROMEOS_PUBLIC_CROS_FEATURES_H_ + +namespace media { + +// A run-time check for whether or not we should use the OS-level camera +// service on ChromeOS for video capture. +bool ShouldUseCrosCameraService(); + +} // namespace media + +#endif // MEDIA_CAPTURE_VIDEO_CHROMEOS_PUBLIC_CROS_FEATURES_H_ diff --git a/chromium/media/capture/video/chromeos/stream_buffer_manager.cc b/chromium/media/capture/video/chromeos/stream_buffer_manager.cc index 2cd54bb1114..ad4af81973f 100644 --- a/chromium/media/capture/video/chromeos/stream_buffer_manager.cc +++ b/chromium/media/capture/video/chromeos/stream_buffer_manager.cc @@ -7,11 +7,12 @@ #include <sync/sync.h> #include <memory> +#include "base/posix/safe_strerror.h" #include "media/capture/video/chromeos/camera_buffer_factory.h" #include "media/capture/video/chromeos/camera_device_context.h" #include "media/capture/video/chromeos/camera_metadata_utils.h" -#include "mojo/edk/embedder/embedder.h" -#include "mojo/edk/embedder/scoped_platform_handle.h" +#include "mojo/public/cpp/platform/platform_handle.h" +#include "mojo/public/cpp/system/platform_handle.h" namespace media { @@ -318,24 +319,19 @@ void StreamBufferManager::RegisterBuffer(StreamType stream_type) { size_t num_planes = buffer_handle.planes.size(); std::vector<StreamCaptureInterface::Plane> planes(num_planes); for (size_t i = 0; i < num_planes; ++i) { - // Wrap the platform handle. - MojoHandle wrapped_handle; // There is only one fd. int dup_fd = dup(buffer_handle.fds[0].fd); if (dup_fd == -1) { device_context_->SetErrorState(FROM_HERE, "Failed to dup fd"); return; } - MojoResult result = mojo::edk::CreateInternalPlatformHandleWrapper( - mojo::edk::ScopedInternalPlatformHandle( - mojo::edk::InternalPlatformHandle(dup_fd)), - &wrapped_handle); - if (result != MOJO_RESULT_OK) { + planes[i].fd = + mojo::WrapPlatformHandle(mojo::PlatformHandle(base::ScopedFD(dup_fd))); + if (!planes[i].fd.is_valid()) { device_context_->SetErrorState(FROM_HERE, "Failed to wrap gpu memory handle"); return; } - planes[i].fd.reset(mojo::Handle(wrapped_handle)); planes[i].stride = buffer_handle.planes[i].stride; planes[i].offset = buffer_handle.planes[i].offset; } @@ -367,7 +363,7 @@ void StreamBufferManager::OnRegisteredBuffer(StreamType stream_type, if (result) { device_context_->SetErrorState(FROM_HERE, std::string("Failed to register buffer: ") + - std::string(strerror(result))); + base::safe_strerror(-result)); return; } stream_context_[stream_type]->registered_buffers.push(buffer_id); @@ -439,8 +435,8 @@ void StreamBufferManager::OnProcessedCaptureRequest(int32_t result) { } if (result) { device_context_->SetErrorState( - FROM_HERE, std::string("Process capture request failed") + - std::string(strerror(result))); + FROM_HERE, std::string("Process capture request failed: ") + + base::safe_strerror(-result)); return; } // Keeps the preview stream going. @@ -702,15 +698,14 @@ void StreamBufferManager::SubmitCaptureResult(uint32_t frame_number, // Wait on release fence before delivering the result buffer to client. if (stream_buffer->release_fence.is_valid()) { const int kSyncWaitTimeoutMs = 1000; - mojo::edk::ScopedInternalPlatformHandle fence; - MojoResult result = mojo::edk::PassWrappedInternalPlatformHandle( - stream_buffer->release_fence.release().value(), &fence); - if (result != MOJO_RESULT_OK) { + mojo::PlatformHandle fence = + mojo::UnwrapPlatformHandle(std::move(stream_buffer->release_fence)); + if (!fence.is_valid()) { device_context_->SetErrorState(FROM_HERE, "Failed to unwrap release fence fd"); return; } - if (!sync_wait(fence.get().handle, kSyncWaitTimeoutMs)) { + if (!sync_wait(fence.GetFD().get(), kSyncWaitTimeoutMs)) { device_context_->SetErrorState(FROM_HERE, "Sync wait on release fence timed out"); return; diff --git a/chromium/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc b/chromium/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc index dbd982e71b5..6fb9ccac642 100644 --- a/chromium/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc +++ b/chromium/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc @@ -4,10 +4,8 @@ #include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h" -#include "base/files/file_util.h" #include "base/memory/ptr_util.h" #include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" -#include "media/capture/video/linux/video_capture_device_factory_linux.h" namespace media { @@ -18,20 +16,14 @@ gpu::GpuMemoryBufferManager* g_gpu_buffer_manager = nullptr; } // namespace VideoCaptureDeviceFactoryChromeOS::VideoCaptureDeviceFactoryChromeOS( - scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_screen_observer, - gpu::GpuMemoryBufferManager* gpu_buffer_manager, - MojoJpegDecodeAcceleratorFactoryCB jda_factory, - MojoJpegEncodeAcceleratorFactoryCB jea_factory) + scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_screen_observer) : task_runner_for_screen_observer_(task_runner_for_screen_observer), camera_hal_ipc_thread_("CameraHalIpcThread"), - initialized_(Init(std::move(jda_factory), std::move(jea_factory))) { - g_gpu_buffer_manager = gpu_buffer_manager; -} + initialized_(Init()) {} VideoCaptureDeviceFactoryChromeOS::~VideoCaptureDeviceFactoryChromeOS() { camera_hal_delegate_->Reset(); camera_hal_ipc_thread_.Stop(); - g_gpu_buffer_manager = nullptr; } std::unique_ptr<VideoCaptureDevice> @@ -49,9 +41,6 @@ void VideoCaptureDeviceFactoryChromeOS::GetSupportedFormats( const VideoCaptureDeviceDescriptor& device_descriptor, VideoCaptureFormats* supported_formats) { DCHECK(thread_checker_.CalledOnValidThread()); - if (!initialized_) { - return; - } camera_hal_delegate_->GetSupportedFormats(device_descriptor, supported_formats); } @@ -66,38 +55,25 @@ void VideoCaptureDeviceFactoryChromeOS::GetDeviceDescriptors( } // static -bool VideoCaptureDeviceFactoryChromeOS::ShouldEnable() { - // Checks whether the Chrome OS binary which provides the HAL v3 camera - // service is installed on the device. If the binary exists we assume the - // device is using the new camera HAL v3 stack. - const base::FilePath kCrosCameraService("/usr/bin/cros_camera_service"); - return base::PathExists(kCrosCameraService); -} - -// static gpu::GpuMemoryBufferManager* VideoCaptureDeviceFactoryChromeOS::GetBufferManager() { return g_gpu_buffer_manager; } // static -void VideoCaptureDeviceFactoryChromeOS::SetBufferManagerForTesting( +void VideoCaptureDeviceFactoryChromeOS::SetGpuBufferManager( gpu::GpuMemoryBufferManager* buffer_manager) { g_gpu_buffer_manager = buffer_manager; } -bool VideoCaptureDeviceFactoryChromeOS::Init( - MojoJpegDecodeAcceleratorFactoryCB jda_factory, - MojoJpegEncodeAcceleratorFactoryCB jea_factory) { +bool VideoCaptureDeviceFactoryChromeOS::Init() { if (!camera_hal_ipc_thread_.Start()) { LOG(ERROR) << "Module thread failed to start"; return false; } - if (!CameraHalDispatcherImpl::GetInstance()->IsStarted() && - !CameraHalDispatcherImpl::GetInstance()->Start(std::move(jda_factory), - std::move(jea_factory))) { - LOG(ERROR) << "Failed to start CameraHalDispatcherImpl"; + if (!CameraHalDispatcherImpl::GetInstance()->IsStarted()) { + LOG(ERROR) << "CameraHalDispatcherImpl is not started"; return false; } @@ -107,31 +83,4 @@ bool VideoCaptureDeviceFactoryChromeOS::Init( return true; } -#if defined(OS_CHROMEOS) -// static -VideoCaptureDeviceFactory* -VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( - scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_screen_observer, - gpu::GpuMemoryBufferManager* gpu_buffer_manager, - MojoJpegDecodeAcceleratorFactoryCB jda_factory, - MojoJpegEncodeAcceleratorFactoryCB jea_factory) { - // On Chrome OS we have to support two use cases: - // - // 1. For devices that have the camera HAL v3 service running on Chrome OS, - // we use the HAL v3 capture device which VideoCaptureDeviceFactoryChromeOS - // provides. - // 2. Existing devices that use UVC cameras need to use the V4L2 capture - // device which VideoCaptureDeviceFacotoryLinux provides; there are also - // some special devices that may never be able to implement a camera HAL - // v3. - if (VideoCaptureDeviceFactoryChromeOS::ShouldEnable()) { - return new VideoCaptureDeviceFactoryChromeOS( - task_runner_for_screen_observer, gpu_buffer_manager, - std::move(jda_factory), std::move(jea_factory)); - } else { - return new VideoCaptureDeviceFactoryLinux(task_runner_for_screen_observer); - } -} -#endif - } // namespace media diff --git a/chromium/media/capture/video/chromeos/video_capture_device_factory_chromeos.h b/chromium/media/capture/video/chromeos/video_capture_device_factory_chromeos.h index 4507469bb03..bc452c30b03 100644 --- a/chromium/media/capture/video/chromeos/video_capture_device_factory_chromeos.h +++ b/chromium/media/capture/video/chromeos/video_capture_device_factory_chromeos.h @@ -19,10 +19,7 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryChromeOS final public: explicit VideoCaptureDeviceFactoryChromeOS( scoped_refptr<base::SingleThreadTaskRunner> - task_runner_for_screen_observer, - gpu::GpuMemoryBufferManager* gpu_buffer_manager, - MojoJpegDecodeAcceleratorFactoryCB jda_factory, - MojoJpegEncodeAcceleratorFactoryCB jea_factory); + task_runner_for_screen_observer); ~VideoCaptureDeviceFactoryChromeOS() override; @@ -35,21 +32,13 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryChromeOS final void GetDeviceDescriptors( VideoCaptureDeviceDescriptors* device_descriptors) final; - // A run-time check for whether we should enable - // VideoCaptureDeviceFactoryChromeOS on the device. - static bool ShouldEnable(); - static gpu::GpuMemoryBufferManager* GetBufferManager(); - - // For testing purpose only. - static void SetBufferManagerForTesting( - gpu::GpuMemoryBufferManager* buffer_manager); + static void SetGpuBufferManager(gpu::GpuMemoryBufferManager* buffer_manager); private: // Initializes the factory. The factory is functional only after this call // succeeds. - bool Init(MojoJpegDecodeAcceleratorFactoryCB jda_factory, - MojoJpegEncodeAcceleratorFactoryCB jea_factory); + bool Init(); const scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_screen_observer_; diff --git a/chromium/media/capture/video/create_video_capture_device_factory.cc b/chromium/media/capture/video/create_video_capture_device_factory.cc new file mode 100644 index 00000000000..9ca6f8c3e1a --- /dev/null +++ b/chromium/media/capture/video/create_video_capture_device_factory.cc @@ -0,0 +1,91 @@ +// 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/video/create_video_capture_device_factory.h" + +#include "base/command_line.h" +#include "build/build_config.h" +#include "media/base/media_switches.h" +#include "media/capture/video/fake_video_capture_device_factory.h" +#include "media/capture/video/file_video_capture_device_factory.h" + +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +#include "media/capture/video/linux/video_capture_device_factory_linux.h" +#elif defined(OS_CHROMEOS) +#include "media/capture/video/chromeos/public/cros_features.h" +#include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h" +#include "media/capture/video/linux/video_capture_device_factory_linux.h" +#elif defined(OS_WIN) +#include "media/capture/video/win/video_capture_device_factory_win.h" +#elif defined(OS_MACOSX) +#include "media/capture/video/mac/video_capture_device_factory_mac.h" +#elif defined(OS_ANDROID) +#include "media/capture/video/android/video_capture_device_factory_android.h" +#endif + +namespace media { + +namespace { + +std::unique_ptr<VideoCaptureDeviceFactory> +CreatePlatformSpecificVideoCaptureDeviceFactory( + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) + return std::make_unique<VideoCaptureDeviceFactoryLinux>(ui_task_runner); +#elif defined(OS_CHROMEOS) + // On Chrome OS we have to support two use cases: + // + // 1. For devices that have the camera HAL v3 service running on Chrome OS, + // we use the HAL v3 capture device which VideoCaptureDeviceFactoryChromeOS + // provides. + // 2. Existing devices that use UVC cameras need to use the V4L2 capture + // device which VideoCaptureDeviceFacotoryLinux provides; there are also + // some special devices that may never be able to implement a camera HAL + // v3. + if (ShouldUseCrosCameraService()) { + return std::make_unique<VideoCaptureDeviceFactoryChromeOS>(ui_task_runner); + } else { + return std::make_unique<VideoCaptureDeviceFactoryLinux>(ui_task_runner); + } +#elif defined(OS_WIN) + return std::make_unique<VideoCaptureDeviceFactoryWin>(); +#elif defined(OS_MACOSX) + return std::make_unique<VideoCaptureDeviceFactoryMac>(); +#elif defined(OS_ANDROID) + return std::make_unique<VideoCaptureDeviceFactoryAndroid>(); +#else + NOTIMPLEMENTED(); + return nullptr; +#endif +} + +} // anonymous namespace + +std::unique_ptr<VideoCaptureDeviceFactory> CreateVideoCaptureDeviceFactory( + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { + const base::CommandLine* command_line = + base::CommandLine::ForCurrentProcess(); + // Use a Fake or File Video Device Factory if the command line flags are + // present, otherwise use the normal, platform-dependent, device factory. + if (command_line->HasSwitch(switches::kUseFakeDeviceForMediaStream)) { + if (command_line->HasSwitch(switches::kUseFileForFakeVideoCapture)) { + return std::make_unique<FileVideoCaptureDeviceFactory>(); + } else { + std::vector<FakeVideoCaptureDeviceSettings> config; + FakeVideoCaptureDeviceFactory::ParseFakeDevicesConfigFromOptionsString( + command_line->GetSwitchValueASCII( + switches::kUseFakeDeviceForMediaStream), + &config); + auto result = std::make_unique<FakeVideoCaptureDeviceFactory>(); + result->SetToCustomDevicesConfig(config); + return std::move(result); + } + } else { + // |ui_task_runner| is needed for the Linux ChromeOS factory to retrieve + // screen rotations. + return CreatePlatformSpecificVideoCaptureDeviceFactory(ui_task_runner); + } +} + +} // namespace media diff --git a/chromium/media/capture/video/create_video_capture_device_factory.h b/chromium/media/capture/video/create_video_capture_device_factory.h new file mode 100644 index 00000000000..7199bf800e3 --- /dev/null +++ b/chromium/media/capture/video/create_video_capture_device_factory.h @@ -0,0 +1,22 @@ +// 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_VIDEO_CREATE_VIDEO_CAPTURE_DEVICE_FACTORY_H_ +#define MEDIA_CAPTURE_VIDEO_CREATE_VIDEO_CAPTURE_DEVICE_FACTORY_H_ + +#include <memory> + +#include "base/single_thread_task_runner.h" +#include "media/capture/capture_export.h" +#include "media/capture/video/video_capture_device_factory.h" + +namespace media { + +std::unique_ptr<VideoCaptureDeviceFactory> CAPTURE_EXPORT +CreateVideoCaptureDeviceFactory( + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); + +} // namespace media + +#endif // MEDIA_CAPTURE_VIDEO_CREATE_VIDEO_CAPTURE_DEVICE_FACTORY_H_ diff --git a/chromium/media/capture/video/linux/camera_config_chromeos.h b/chromium/media/capture/video/linux/camera_config_chromeos.h index 3b3bb395995..df4556e40a2 100644 --- a/chromium/media/capture/video/linux/camera_config_chromeos.h +++ b/chromium/media/capture/video/linux/camera_config_chromeos.h @@ -61,16 +61,6 @@ class CAPTURE_EXPORT CameraConfigChromeOS { CAPTURE_EXPORT VideoFacingMode GetCameraFacing(const std::string& device_id, const std::string& model_id) const; - // Get the orientation of the camera. The value is the angle that the camera - // image needs to be rotated clockwise so it shows correctly on the display in - // its natural orientation. It should be 0, 90, 180, or 270. - // - // For example, suppose a device has a naturally tall screen. The back-facing - // camera sensor is mounted in landscape. You are looking at the screen. If - // the top side of the camera sensor is aligned with the right edge of the - // screen in natural orientation, the value should be 90. If the top side of a - // front-facing camera sensor is aligned with the right of the screen, the - // value should be 270. int GetOrientation(const std::string& device_id, const std::string& model_id) const; diff --git a/chromium/media/capture/video/linux/fake_v4l2_impl.cc b/chromium/media/capture/video/linux/fake_v4l2_impl.cc new file mode 100644 index 00000000000..2c33b40820a --- /dev/null +++ b/chromium/media/capture/video/linux/fake_v4l2_impl.cc @@ -0,0 +1,198 @@ +// 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/video/linux/fake_v4l2_impl.h" + +#include <linux/videodev2.h> +#include <string.h> + +#include "base/stl_util.h" + +#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) + +namespace media { + +static const int kInvalidId = -1; +static const int kSuccessReturnValue = 0; +static const int kErrorReturnValue = -1; + +class FakeV4L2Impl::OpenedDevice { + public: + explicit OpenedDevice(const std::string& device_id, int open_flags) + : device_id_(device_id), open_flags_(open_flags) {} + + const std::string& device_id() const { return device_id_; } + int open_flags() const { return open_flags_; } + + private: + const std::string device_id_; + const int open_flags_; +}; + +FakeV4L2Impl::FakeV4L2Impl() : next_id_to_return_from_open_(1) {} + +FakeV4L2Impl::~FakeV4L2Impl() = default; + +void FakeV4L2Impl::AddDevice(const std::string& device_name, + const FakeV4L2DeviceConfig& config) { + device_configs_.emplace(device_name, config); +} + +int FakeV4L2Impl::open(const char* device_name, int flags) { + std::string device_name_as_string(device_name); + if (!base::ContainsKey(device_configs_, device_name_as_string)) + return kInvalidId; + + auto id_iter = device_name_to_open_id_map_.find(device_name_as_string); + if (id_iter != device_name_to_open_id_map_.end()) { + // Device is already open + return kInvalidId; + } + + auto device_id = next_id_to_return_from_open_++; + device_name_to_open_id_map_.emplace(device_name_as_string, device_id); + opened_devices_.emplace( + device_id, std::make_unique<OpenedDevice>(device_name_as_string, flags)); + return device_id; +} + +int FakeV4L2Impl::close(int fd) { + auto device_iter = opened_devices_.find(fd); + if (device_iter == opened_devices_.end()) + return kErrorReturnValue; + device_name_to_open_id_map_.erase(device_iter->second->device_id()); + opened_devices_.erase(device_iter->first); + return kSuccessReturnValue; +} + +int FakeV4L2Impl::ioctl(int fd, int request, void* argp) { + auto device_iter = opened_devices_.find(fd); + if (device_iter == opened_devices_.end()) + return EBADF; + auto& opened_device = device_iter->second; + auto& device_config = device_configs_.at(opened_device->device_id()); + + switch (request) { + case VIDIOC_ENUM_FMT: { + auto* fmtdesc = reinterpret_cast<v4l2_fmtdesc*>(argp); + if (fmtdesc->index > 0u) { + // We only support a single format for now. + return EINVAL; + } + if (fmtdesc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + // We only support video capture. + return EINVAL; + } + fmtdesc->flags = 0u; + strcpy(reinterpret_cast<char*>(fmtdesc->description), "YUV420"); + fmtdesc->pixelformat = V4L2_PIX_FMT_YUV420; + memset(fmtdesc->reserved, 0, 4); + return kSuccessReturnValue; + } + case VIDIOC_QUERYCAP: { + auto* cap = reinterpret_cast<v4l2_capability*>(argp); + strcpy(reinterpret_cast<char*>(cap->driver), "FakeV4L2"); + CHECK(device_config.descriptor.display_name().size() < 31); + strcpy(reinterpret_cast<char*>(cap->driver), + device_config.descriptor.display_name().c_str()); + cap->bus_info[0] = 0; + // Provide arbitrary version info + cap->version = KERNEL_VERSION(1, 0, 0); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE; + memset(cap->reserved, 0, 4); + return kSuccessReturnValue; + } + case VIDIOC_STREAMON: + case VIDIOC_STREAMOFF: + NOTIMPLEMENTED(); + return kSuccessReturnValue; + case VIDIOC_CROPCAP: + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + case VIDIOC_ENCODER_CMD: + case VIDIOC_TRY_ENCODER_CMD: + case VIDIOC_ENUMAUDIO: + case VIDIOC_ENUMAUDOUT: + case VIDIOC_ENUM_FRAMESIZES: + case VIDIOC_ENUM_FRAMEINTERVALS: + case VIDIOC_ENUMINPUT: + case VIDIOC_ENUMOUTPUT: + case VIDIOC_ENUMSTD: + case VIDIOC_G_AUDIO: + case VIDIOC_S_AUDIO: + case VIDIOC_G_AUDOUT: + case VIDIOC_S_AUDOUT: + case VIDIOC_G_CROP: + case VIDIOC_S_CROP: + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: + case VIDIOC_G_ENC_INDEX: + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_TRY_EXT_CTRLS: + case VIDIOC_G_FBUF: + case VIDIOC_S_FBUF: + case VIDIOC_G_FMT: + case VIDIOC_S_FMT: + case VIDIOC_TRY_FMT: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + case VIDIOC_G_INPUT: + case VIDIOC_S_INPUT: + case VIDIOC_G_JPEGCOMP: + case VIDIOC_S_JPEGCOMP: + case VIDIOC_G_MODULATOR: + case VIDIOC_S_MODULATOR: + case VIDIOC_G_OUTPUT: + case VIDIOC_S_OUTPUT: + case VIDIOC_G_PARM: + case VIDIOC_S_PARM: + case VIDIOC_G_PRIORITY: + case VIDIOC_S_PRIORITY: + case VIDIOC_G_SLICED_VBI_CAP: + case VIDIOC_G_STD: + case VIDIOC_S_STD: + case VIDIOC_G_TUNER: + case VIDIOC_S_TUNER: + case VIDIOC_LOG_STATUS: + case VIDIOC_OVERLAY: + case VIDIOC_QBUF: + case VIDIOC_DQBUF: + case VIDIOC_QUERYBUF: + case VIDIOC_QUERYCTRL: + case VIDIOC_QUERYMENU: + case VIDIOC_QUERYSTD: + case VIDIOC_REQBUFS: + case VIDIOC_S_HW_FREQ_SEEK: + // Unsupported |request| code. + NOTREACHED() << "Unsupported request code " << request; + return kErrorReturnValue; + } + + // Invalid |request|. + NOTREACHED(); + return kErrorReturnValue; +} + +void* FakeV4L2Impl::mmap(void* start, + size_t length, + int prot, + int flags, + int fd, + off_t offset) { + NOTREACHED(); + return nullptr; +} + +int FakeV4L2Impl::munmap(void* start, size_t length) { + NOTREACHED(); + return kErrorReturnValue; +} + +int FakeV4L2Impl::poll(struct pollfd* ufds, unsigned int nfds, int timeout) { + NOTREACHED(); + return kErrorReturnValue; +} + +} // namespace media diff --git a/chromium/media/capture/video/linux/fake_v4l2_impl.h b/chromium/media/capture/video/linux/fake_v4l2_impl.h new file mode 100644 index 00000000000..1dd4b6c1c0c --- /dev/null +++ b/chromium/media/capture/video/linux/fake_v4l2_impl.h @@ -0,0 +1,62 @@ +// 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_VIDEO_LINUX_FAKE_V4L2_IMPL_H_ +#define MEDIA_CAPTURE_VIDEO_LINUX_FAKE_V4L2_IMPL_H_ + +#include <map> +#include <string> + +#include "media/capture/capture_export.h" +#include "media/capture/video/linux/v4l2_capture_device.h" +#include "media/capture/video/video_capture_device_descriptor.h" + +namespace media { + +struct FakeV4L2DeviceConfig { + FakeV4L2DeviceConfig(const VideoCaptureDeviceDescriptor& descriptor) + : descriptor(descriptor) {} + + const VideoCaptureDeviceDescriptor descriptor; +}; + +// Implementation of V4L2CaptureDevice interface that allows configuring fake +// devices useful for testing. +class CAPTURE_EXPORT FakeV4L2Impl : public V4L2CaptureDevice { + public: + FakeV4L2Impl(); + + void AddDevice(const std::string& device_name, + const FakeV4L2DeviceConfig& config); + + // Implementation of V4L2CaptureDevice interface: + int open(const char* device_name, int flags) override; + int close(int fd) override; + int ioctl(int fd, int request, void* argp) override; + void* mmap(void* start, + size_t length, + int prot, + int flags, + int fd, + off_t offset) override; + + int munmap(void* start, size_t length) override; + int poll(struct pollfd* ufds, unsigned int nfds, int timeout) override; + + protected: + ~FakeV4L2Impl() override; + + private: + class OpenedDevice; + + int next_id_to_return_from_open_; + std::map<std::string, FakeV4L2DeviceConfig> device_configs_; + std::map<std::string, int> device_name_to_open_id_map_; + std::map<int /*value returned by open()*/, std::unique_ptr<OpenedDevice>> + opened_devices_; +}; + +} // namespace media + +#endif // MEDIA_CAPTURE_VIDEO_LINUX_FAKE_V4L2_IMPL_H_ diff --git a/chromium/media/capture/video/linux/v4l2_capture_delegate.cc b/chromium/media/capture/video/linux/v4l2_capture_delegate.cc index ce969d7e40a..c152e8c2822 100644 --- a/chromium/media/capture/video/linux/v4l2_capture_delegate.cc +++ b/chromium/media/capture/video/linux/v4l2_capture_delegate.cc @@ -55,8 +55,9 @@ const int kMjpegHeight = 480; // Typical framerate, in fps const int kTypicalFramerate = 30; -// V4L2 color formats supported by V4L2CaptureDelegate derived classes. -// This list is ordered by precedence of use -- but see caveats for MJPEG. +// V4L2CaptureDevice color formats supported by V4L2CaptureDelegate derived +// classes. This list is ordered by precedence of use -- but see caveats for +// MJPEG. static struct { uint32_t fourcc; VideoPixelFormat pixel_format; @@ -124,44 +125,6 @@ static std::string FourccToString(uint32_t fourcc) { (fourcc >> 16) & 0xFF, (fourcc >> 24) & 0xFF); } -// Running ioctl() on some devices, especially shortly after (re)opening the -// device file descriptor or (re)starting streaming, can fail but works after -// retrying (https://crbug.com/670262). -// Returns false if the |request| ioctl fails too many times. -static bool RunIoctl(int fd, int request, void* argp) { - int num_retries = 0; - for (; HANDLE_EINTR(ioctl(fd, request, argp)) < 0 && - num_retries < kMaxIOCtrlRetries; - ++num_retries) { - DPLOG(WARNING) << "ioctl"; - } - DPLOG_IF(ERROR, num_retries != kMaxIOCtrlRetries); - return num_retries != kMaxIOCtrlRetries; -} - -// Creates a mojom::RangePtr with the (min, max, current, step) values of the -// control associated with |control_id|. Returns an empty Range otherwise. -static mojom::RangePtr RetrieveUserControlRange(int device_fd, int control_id) { - mojom::RangePtr capability = mojom::Range::New(); - - v4l2_queryctrl range = {}; - range.id = control_id; - range.type = V4L2_CTRL_TYPE_INTEGER; - if (!RunIoctl(device_fd, VIDIOC_QUERYCTRL, &range)) - return mojom::Range::New(); - capability->max = range.maximum; - capability->min = range.minimum; - capability->step = range.step; - - v4l2_control current = {}; - current.id = control_id; - if (!RunIoctl(device_fd, VIDIOC_G_CTRL, ¤t)) - return mojom::Range::New(); - capability->current = current.value; - - return capability; -} - // Determines if |control_id| is special, i.e. controls another one's state. static bool IsSpecialControl(int control_id) { switch (control_id) { @@ -203,114 +166,12 @@ static bool IsBlacklistedControl(int control_id) { return false; } -// Sets all user control to their default. Some controls are enabled by another -// flag, usually having the word "auto" in the name, see IsSpecialControl(). -// These flags are preset beforehand, then set to their defaults individually -// afterwards. -static void ResetUserAndCameraControlsToDefault(int device_fd) { - // Set V4L2_CID_AUTO_WHITE_BALANCE to false first. - v4l2_control auto_white_balance = {}; - auto_white_balance.id = V4L2_CID_AUTO_WHITE_BALANCE; - auto_white_balance.value = false; - if (!RunIoctl(device_fd, VIDIOC_S_CTRL, &auto_white_balance)) - return; - - std::vector<struct v4l2_ext_control> special_camera_controls; - // Set V4L2_CID_EXPOSURE_AUTO to V4L2_EXPOSURE_MANUAL. - v4l2_ext_control auto_exposure = {}; - auto_exposure.id = V4L2_CID_EXPOSURE_AUTO; - auto_exposure.value = V4L2_EXPOSURE_MANUAL; - special_camera_controls.push_back(auto_exposure); - // Set V4L2_CID_EXPOSURE_AUTO_PRIORITY to false. - v4l2_ext_control priority_auto_exposure = {}; - priority_auto_exposure.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY; - priority_auto_exposure.value = false; - special_camera_controls.push_back(priority_auto_exposure); - // Set V4L2_CID_FOCUS_AUTO to false. - v4l2_ext_control auto_focus = {}; - auto_focus.id = V4L2_CID_FOCUS_AUTO; - auto_focus.value = false; - special_camera_controls.push_back(auto_focus); - - struct v4l2_ext_controls ext_controls = {}; - ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS; - ext_controls.count = special_camera_controls.size(); - ext_controls.controls = special_camera_controls.data(); - if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0) - DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS"; - - std::vector<struct v4l2_ext_control> camera_controls; - for (const auto& control : kControls) { - std::vector<struct v4l2_ext_control> camera_controls; - - v4l2_queryctrl range = {}; - range.id = control.control_base | V4L2_CTRL_FLAG_NEXT_CTRL; - while (0 == HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range))) { - if (V4L2_CTRL_ID2CLASS(range.id) != V4L2_CTRL_ID2CLASS(control.class_id)) - break; - range.id |= V4L2_CTRL_FLAG_NEXT_CTRL; - - if (IsSpecialControl(range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL)) - continue; - if (IsBlacklistedControl(range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL)) - continue; - - struct v4l2_ext_control ext_control = {}; - ext_control.id = range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL; - ext_control.value = range.default_value; - camera_controls.push_back(ext_control); - } - - if (!camera_controls.empty()) { - struct v4l2_ext_controls ext_controls = {}; - ext_controls.ctrl_class = control.class_id; - ext_controls.count = camera_controls.size(); - ext_controls.controls = camera_controls.data(); - if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0) - DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS"; - } - } - - // Now set the special flags to the default values - v4l2_queryctrl range = {}; - range.id = V4L2_CID_AUTO_WHITE_BALANCE; - HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)); - auto_white_balance.value = range.default_value; - HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_CTRL, &auto_white_balance)); - - special_camera_controls.clear(); - memset(&range, 0, sizeof(struct v4l2_queryctrl)); - range.id = V4L2_CID_EXPOSURE_AUTO; - HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)); - auto_exposure.value = range.default_value; - special_camera_controls.push_back(auto_exposure); - - memset(&range, 0, sizeof(struct v4l2_queryctrl)); - range.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY; - HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)); - priority_auto_exposure.value = range.default_value; - special_camera_controls.push_back(priority_auto_exposure); - - memset(&range, 0, sizeof(struct v4l2_queryctrl)); - range.id = V4L2_CID_FOCUS_AUTO; - HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)); - auto_focus.value = range.default_value; - special_camera_controls.push_back(auto_focus); - - memset(&ext_controls, 0, sizeof(struct v4l2_ext_controls)); - ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS; - ext_controls.count = special_camera_controls.size(); - ext_controls.controls = special_camera_controls.data(); - if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0) - DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS"; -} - -// Class keeping track of a SPLANE V4L2 buffer, mmap()ed on construction and -// munmap()ed on destruction. +// Class keeping track of a SPLANE V4L2CaptureDevice buffer, mmap()ed on +// construction and munmap()ed on destruction. class V4L2CaptureDelegate::BufferTracker : public base::RefCounted<BufferTracker> { public: - BufferTracker(); + BufferTracker(V4L2CaptureDevice* v4l2); // Abstract method to mmap() given |fd| according to |buffer|. bool Init(int fd, const v4l2_buffer& buffer); @@ -325,6 +186,7 @@ class V4L2CaptureDelegate::BufferTracker friend class base::RefCounted<BufferTracker>; virtual ~BufferTracker(); + V4L2CaptureDevice* const v4l2_; uint8_t* start_; size_t length_; size_t payload_size_; @@ -368,13 +230,39 @@ std::list<uint32_t> V4L2CaptureDelegate::GetListOfUsableFourCcs( return supported_formats; } +V4L2CaptureDelegate::ScopedV4L2DeviceFD::ScopedV4L2DeviceFD( + V4L2CaptureDevice* v4l2) + : device_fd_(kInvalidId), v4l2_(v4l2) {} + +V4L2CaptureDelegate::ScopedV4L2DeviceFD::~ScopedV4L2DeviceFD() { + if (is_valid()) + reset(); +} + +int V4L2CaptureDelegate::ScopedV4L2DeviceFD::get() { + return device_fd_; +} + +void V4L2CaptureDelegate::ScopedV4L2DeviceFD::reset(int fd /*= kInvalidId*/) { + if (is_valid()) + v4l2_->close(device_fd_); + device_fd_ = fd; +} + +bool V4L2CaptureDelegate::ScopedV4L2DeviceFD::is_valid() { + return device_fd_ != kInvalidId; +} + V4L2CaptureDelegate::V4L2CaptureDelegate( + V4L2CaptureDevice* v4l2, const VideoCaptureDeviceDescriptor& device_descriptor, const scoped_refptr<base::SingleThreadTaskRunner>& v4l2_task_runner, int power_line_frequency) - : v4l2_task_runner_(v4l2_task_runner), + : v4l2_(v4l2), + v4l2_task_runner_(v4l2_task_runner), device_descriptor_(device_descriptor), power_line_frequency_(power_line_frequency), + device_fd_(v4l2), is_capturing_(false), timeout_count_(0), rotation_(0), @@ -391,20 +279,23 @@ void V4L2CaptureDelegate::AllocateAndStart( // Need to open camera with O_RDWR after Linux kernel 3.3. device_fd_.reset( - HANDLE_EINTR(open(device_descriptor_.device_id.c_str(), O_RDWR))); + HANDLE_EINTR(v4l2_->open(device_descriptor_.device_id.c_str(), O_RDWR))); if (!device_fd_.is_valid()) { - SetErrorState(FROM_HERE, "Failed to open V4L2 device driver file."); + SetErrorState(FROM_HERE, + "Failed to open V4L2CaptureDevice device driver file."); return; } ResetUserAndCameraControlsToDefault(device_fd_.get()); v4l2_capability cap = {}; - if (!((HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYCAP, &cap)) == 0) && + if (!((HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_QUERYCAP, &cap)) == + 0) && ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)))) { device_fd_.reset(); - SetErrorState(FROM_HERE, "This is not a V4L2 video capture device"); + SetErrorState(FROM_HERE, + "This is not a V4L2CaptureDevice video capture device"); return; } @@ -416,7 +307,8 @@ void V4L2CaptureDelegate::AllocateAndStart( v4l2_fmtdesc fmtdesc = {}; fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - for (; HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) == 0; + for (; HANDLE_EINTR( + v4l2_->ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) == 0; ++fmtdesc.index) { best = std::find(desired_v4l2_formats.begin(), best, fmtdesc.pixelformat); } @@ -428,7 +320,8 @@ void V4L2CaptureDelegate::AllocateAndStart( DVLOG(1) << "Chosen pixel format is " << FourccToString(*best); FillV4L2Format(&video_fmt_, width, height, *best); - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt_)) < 0) { + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt_)) < + 0) { SetErrorState(FROM_HERE, "Failed to set video capture format"); return; } @@ -443,7 +336,8 @@ void V4L2CaptureDelegate::AllocateAndStart( v4l2_streamparm streamparm = {}; streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // The following line checks that the driver knows about framerate get/set. - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) { + if (HANDLE_EINTR( + v4l2_->ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) { // Now check if the device is able to accept a capture framerate set. if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { // |frame_rate| is float, approximate by a fraction. @@ -452,8 +346,8 @@ void V4L2CaptureDelegate::AllocateAndStart( (frame_rate) ? (frame_rate * kFrameRatePrecision) : (kTypicalFramerate * kFrameRatePrecision); - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) < - 0) { + if (HANDLE_EINTR( + v4l2_->ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) < 0) { SetErrorState(FROM_HERE, "Failed to set camera framerate"); return; } @@ -474,7 +368,7 @@ void V4L2CaptureDelegate::AllocateAndStart( control.id = V4L2_CID_POWER_LINE_FREQUENCY; control.value = power_line_frequency_; const int retval = - HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &control)); + HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_S_CTRL, &control)); if (retval != 0) DVLOG(1) << "Error setting power line frequency removal"; } @@ -486,8 +380,10 @@ void V4L2CaptureDelegate::AllocateAndStart( v4l2_requestbuffers r_buffer; FillV4L2RequestBuffer(&r_buffer, kNumVideoBuffers); - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) { - SetErrorState(FROM_HERE, "Error requesting MMAP buffers from V4L2"); + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < + 0) { + SetErrorState(FROM_HERE, + "Error requesting MMAP buffers from V4L2CaptureDevice"); return; } for (unsigned int i = 0; i < r_buffer.count; ++i) { @@ -498,8 +394,8 @@ void V4L2CaptureDelegate::AllocateAndStart( } v4l2_buf_type capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &capture_type)) < - 0) { + if (HANDLE_EINTR( + v4l2_->ioctl(device_fd_.get(), VIDIOC_STREAMON, &capture_type)) < 0) { SetErrorState(FROM_HERE, "VIDIOC_STREAMON failed"); return; } @@ -517,8 +413,8 @@ void V4L2CaptureDelegate::StopAndDeAllocate() { // The order is important: stop streaming, clear |buffer_pool_|, // thus munmap()ing the v4l2_buffers, and then return them to the OS. v4l2_buf_type capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &capture_type)) < - 0) { + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_STREAMOFF, + &capture_type)) < 0) { SetErrorState(FROM_HERE, "VIDIOC_STREAMOFF failed"); return; } @@ -527,7 +423,8 @@ void V4L2CaptureDelegate::StopAndDeAllocate() { v4l2_requestbuffers r_buffer; FillV4L2RequestBuffer(&r_buffer, 0); - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < + 0) SetErrorState(FROM_HERE, "Failed to VIDIOC_REQBUFS with count = 0"); // At this point we can close the device. @@ -569,8 +466,8 @@ void V4L2CaptureDelegate::GetPhotoState( photo_capabilities->current_focus_mode = MeteringMode::NONE; v4l2_control auto_focus_current = {}; auto_focus_current.id = V4L2_CID_FOCUS_AUTO; - if (HANDLE_EINTR( - ioctl(device_fd_.get(), VIDIOC_G_CTRL, &auto_focus_current)) >= 0) { + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_G_CTRL, + &auto_focus_current)) >= 0) { photo_capabilities->current_focus_mode = auto_focus_current.value ? MeteringMode::CONTINUOUS : MeteringMode::MANUAL; @@ -588,8 +485,8 @@ void V4L2CaptureDelegate::GetPhotoState( photo_capabilities->current_exposure_mode = MeteringMode::NONE; v4l2_control exposure_current = {}; exposure_current.id = V4L2_CID_EXPOSURE_AUTO; - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_CTRL, &exposure_current)) >= - 0) { + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_G_CTRL, + &exposure_current)) >= 0) { photo_capabilities->current_exposure_mode = exposure_current.value == V4L2_EXPOSURE_MANUAL ? MeteringMode::MANUAL @@ -616,8 +513,8 @@ void V4L2CaptureDelegate::GetPhotoState( photo_capabilities->current_white_balance_mode = MeteringMode::NONE; v4l2_control white_balance_current = {}; white_balance_current.id = V4L2_CID_AUTO_WHITE_BALANCE; - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_CTRL, - &white_balance_current)) >= 0) { + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_G_CTRL, + &white_balance_current)) >= 0) { photo_capabilities->current_white_balance_mode = white_balance_current.value ? MeteringMode::CONTINUOUS : MeteringMode::MANUAL; @@ -656,7 +553,8 @@ void V4L2CaptureDelegate::SetPhotoOptions( v4l2_control zoom_current = {}; zoom_current.id = V4L2_CID_ZOOM_ABSOLUTE; zoom_current.value = settings->zoom; - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &zoom_current)) < 0) + if (HANDLE_EINTR( + v4l2_->ioctl(device_fd_.get(), VIDIOC_S_CTRL, &zoom_current)) < 0) DPLOG(ERROR) << "setting zoom to " << settings->zoom; } @@ -667,20 +565,22 @@ void V4L2CaptureDelegate::SetPhotoOptions( white_balance_set.id = V4L2_CID_AUTO_WHITE_BALANCE; white_balance_set.value = settings->white_balance_mode == mojom::MeteringMode::CONTINUOUS; - HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &white_balance_set)); + HANDLE_EINTR( + v4l2_->ioctl(device_fd_.get(), VIDIOC_S_CTRL, &white_balance_set)); } if (settings->has_color_temperature) { v4l2_control auto_white_balance_current = {}; auto_white_balance_current.id = V4L2_CID_AUTO_WHITE_BALANCE; - const int result = HANDLE_EINTR( - ioctl(device_fd_.get(), VIDIOC_G_CTRL, &auto_white_balance_current)); + const int result = HANDLE_EINTR(v4l2_->ioctl( + device_fd_.get(), VIDIOC_G_CTRL, &auto_white_balance_current)); // Color temperature can only be applied if Auto White Balance is off. if (result >= 0 && !auto_white_balance_current.value) { v4l2_control set_temperature = {}; set_temperature.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE; set_temperature.value = settings->color_temperature; - HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &set_temperature)); + HANDLE_EINTR( + v4l2_->ioctl(device_fd_.get(), VIDIOC_S_CTRL, &set_temperature)); } } @@ -693,20 +593,22 @@ void V4L2CaptureDelegate::SetPhotoOptions( settings->exposure_mode == mojom::MeteringMode::CONTINUOUS ? V4L2_EXPOSURE_APERTURE_PRIORITY : V4L2_EXPOSURE_MANUAL; - HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &exposure_mode_set)); + HANDLE_EINTR( + v4l2_->ioctl(device_fd_.get(), VIDIOC_S_CTRL, &exposure_mode_set)); } if (settings->has_exposure_compensation) { v4l2_control auto_exposure_current = {}; auto_exposure_current.id = V4L2_CID_EXPOSURE_AUTO; const int result = HANDLE_EINTR( - ioctl(device_fd_.get(), VIDIOC_G_CTRL, &auto_exposure_current)); + v4l2_->ioctl(device_fd_.get(), VIDIOC_G_CTRL, &auto_exposure_current)); // Exposure Compensation can only be applied if Auto Exposure is off. if (result >= 0 && auto_exposure_current.value == V4L2_EXPOSURE_MANUAL) { v4l2_control set_exposure = {}; set_exposure.id = V4L2_CID_EXPOSURE_ABSOLUTE; set_exposure.value = settings->exposure_compensation; - HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &set_exposure)); + HANDLE_EINTR( + v4l2_->ioctl(device_fd_.get(), VIDIOC_S_CTRL, &set_exposure)); } } @@ -714,28 +616,32 @@ void V4L2CaptureDelegate::SetPhotoOptions( v4l2_control current = {}; current.id = V4L2_CID_BRIGHTNESS; current.value = settings->brightness; - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, ¤t)) < 0) + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_S_CTRL, ¤t)) < + 0) DPLOG(ERROR) << "setting brightness to " << settings->brightness; } if (settings->has_contrast) { v4l2_control current = {}; current.id = V4L2_CID_CONTRAST; current.value = settings->contrast; - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, ¤t)) < 0) + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_S_CTRL, ¤t)) < + 0) DPLOG(ERROR) << "setting contrast to " << settings->contrast; } if (settings->has_saturation) { v4l2_control current = {}; current.id = V4L2_CID_SATURATION; current.value = settings->saturation; - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, ¤t)) < 0) + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_S_CTRL, ¤t)) < + 0) DPLOG(ERROR) << "setting saturation to " << settings->saturation; } if (settings->has_sharpness) { v4l2_control current = {}; current.id = V4L2_CID_SHARPNESS; current.value = settings->sharpness; - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, ¤t)) < 0) + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_S_CTRL, ¤t)) < + 0) DPLOG(ERROR) << "setting sharpness to " << settings->sharpness; } @@ -754,16 +660,162 @@ base::WeakPtr<V4L2CaptureDelegate> V4L2CaptureDelegate::GetWeakPtr() { V4L2CaptureDelegate::~V4L2CaptureDelegate() = default; +// Running v4l2_->ioctl() on some devices, especially shortly after (re)opening +// the device file descriptor or (re)starting streaming, can fail but works +// after retrying (https://crbug.com/670262). Returns false if the |request| +// ioctl fails too many times. +bool V4L2CaptureDelegate::RunIoctl(int fd, int request, void* argp) { + int num_retries = 0; + for (; HANDLE_EINTR(v4l2_->ioctl(fd, request, argp)) < 0 && + num_retries < kMaxIOCtrlRetries; + ++num_retries) { + DPLOG(WARNING) << "ioctl"; + } + DPLOG_IF(ERROR, num_retries != kMaxIOCtrlRetries); + return num_retries != kMaxIOCtrlRetries; +} + +// Creates a mojom::RangePtr with the (min, max, current, step) values of the +// control associated with |control_id|. Returns an empty Range otherwise. +mojom::RangePtr V4L2CaptureDelegate::RetrieveUserControlRange(int device_fd, + int control_id) { + mojom::RangePtr capability = mojom::Range::New(); + + v4l2_queryctrl range = {}; + range.id = control_id; + range.type = V4L2_CTRL_TYPE_INTEGER; + if (!RunIoctl(device_fd, VIDIOC_QUERYCTRL, &range)) + return mojom::Range::New(); + capability->max = range.maximum; + capability->min = range.minimum; + capability->step = range.step; + + v4l2_control current = {}; + current.id = control_id; + if (!RunIoctl(device_fd, VIDIOC_G_CTRL, ¤t)) + return mojom::Range::New(); + capability->current = current.value; + + return capability; +} + +// Sets all user control to their default. Some controls are enabled by another +// flag, usually having the word "auto" in the name, see IsSpecialControl(). +// These flags are preset beforehand, then set to their defaults individually +// afterwards. +void V4L2CaptureDelegate::ResetUserAndCameraControlsToDefault(int device_fd) { + // Set V4L2_CID_AUTO_WHITE_BALANCE to false first. + v4l2_control auto_white_balance = {}; + auto_white_balance.id = V4L2_CID_AUTO_WHITE_BALANCE; + auto_white_balance.value = false; + if (!RunIoctl(device_fd, VIDIOC_S_CTRL, &auto_white_balance)) + return; + + std::vector<struct v4l2_ext_control> special_camera_controls; + // Set V4L2_CID_EXPOSURE_AUTO to V4L2_EXPOSURE_MANUAL. + v4l2_ext_control auto_exposure = {}; + auto_exposure.id = V4L2_CID_EXPOSURE_AUTO; + auto_exposure.value = V4L2_EXPOSURE_MANUAL; + special_camera_controls.push_back(auto_exposure); + // Set V4L2_CID_EXPOSURE_AUTO_PRIORITY to false. + v4l2_ext_control priority_auto_exposure = {}; + priority_auto_exposure.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY; + priority_auto_exposure.value = false; + special_camera_controls.push_back(priority_auto_exposure); + // Set V4L2_CID_FOCUS_AUTO to false. + v4l2_ext_control auto_focus = {}; + auto_focus.id = V4L2_CID_FOCUS_AUTO; + auto_focus.value = false; + special_camera_controls.push_back(auto_focus); + + struct v4l2_ext_controls ext_controls = {}; + ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS; + ext_controls.count = special_camera_controls.size(); + ext_controls.controls = special_camera_controls.data(); + if (HANDLE_EINTR(v4l2_->ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < + 0) + DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS"; + + std::vector<struct v4l2_ext_control> camera_controls; + for (const auto& control : kControls) { + std::vector<struct v4l2_ext_control> camera_controls; + + v4l2_queryctrl range = {}; + range.id = control.control_base | V4L2_CTRL_FLAG_NEXT_CTRL; + while (0 == + HANDLE_EINTR(v4l2_->ioctl(device_fd, VIDIOC_QUERYCTRL, &range))) { + if (V4L2_CTRL_ID2CLASS(range.id) != V4L2_CTRL_ID2CLASS(control.class_id)) + break; + range.id |= V4L2_CTRL_FLAG_NEXT_CTRL; + + if (IsSpecialControl(range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL)) + continue; + if (IsBlacklistedControl(range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL)) + continue; + + struct v4l2_ext_control ext_control = {}; + ext_control.id = range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL; + ext_control.value = range.default_value; + camera_controls.push_back(ext_control); + } + + if (!camera_controls.empty()) { + struct v4l2_ext_controls ext_controls = {}; + ext_controls.ctrl_class = control.class_id; + ext_controls.count = camera_controls.size(); + ext_controls.controls = camera_controls.data(); + if (HANDLE_EINTR( + v4l2_->ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0) + DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS"; + } + } + + // Now set the special flags to the default values + v4l2_queryctrl range = {}; + range.id = V4L2_CID_AUTO_WHITE_BALANCE; + HANDLE_EINTR(v4l2_->ioctl(device_fd, VIDIOC_QUERYCTRL, &range)); + auto_white_balance.value = range.default_value; + HANDLE_EINTR(v4l2_->ioctl(device_fd, VIDIOC_S_CTRL, &auto_white_balance)); + + special_camera_controls.clear(); + memset(&range, 0, sizeof(struct v4l2_queryctrl)); + range.id = V4L2_CID_EXPOSURE_AUTO; + HANDLE_EINTR(v4l2_->ioctl(device_fd, VIDIOC_QUERYCTRL, &range)); + auto_exposure.value = range.default_value; + special_camera_controls.push_back(auto_exposure); + + memset(&range, 0, sizeof(struct v4l2_queryctrl)); + range.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY; + HANDLE_EINTR(v4l2_->ioctl(device_fd, VIDIOC_QUERYCTRL, &range)); + priority_auto_exposure.value = range.default_value; + special_camera_controls.push_back(priority_auto_exposure); + + memset(&range, 0, sizeof(struct v4l2_queryctrl)); + range.id = V4L2_CID_FOCUS_AUTO; + HANDLE_EINTR(v4l2_->ioctl(device_fd, VIDIOC_QUERYCTRL, &range)); + auto_focus.value = range.default_value; + special_camera_controls.push_back(auto_focus); + + memset(&ext_controls, 0, sizeof(struct v4l2_ext_controls)); + ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS; + ext_controls.count = special_camera_controls.size(); + ext_controls.controls = special_camera_controls.data(); + if (HANDLE_EINTR(v4l2_->ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < + 0) + DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS"; +} + bool V4L2CaptureDelegate::MapAndQueueBuffer(int index) { v4l2_buffer buffer; FillV4L2Buffer(&buffer, index); - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYBUF, &buffer)) < 0) { - DLOG(ERROR) << "Error querying status of a MMAP V4L2 buffer"; + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_QUERYBUF, &buffer)) < + 0) { + DLOG(ERROR) << "Error querying status of a MMAP V4L2CaptureDevice buffer"; return false; } - const scoped_refptr<BufferTracker> buffer_tracker(new BufferTracker()); + const scoped_refptr<BufferTracker> buffer_tracker(new BufferTracker(v4l2_)); if (!buffer_tracker->Init(device_fd_.get(), buffer)) { DLOG(ERROR) << "Error creating BufferTracker"; return false; @@ -771,8 +823,9 @@ bool V4L2CaptureDelegate::MapAndQueueBuffer(int index) { buffer_tracker_pool_.push_back(buffer_tracker); // Enqueue the buffer in the drivers incoming queue. - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) { - DLOG(ERROR) << "Error enqueuing a V4L2 buffer back into the driver"; + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) { + DLOG(ERROR) + << "Error enqueuing a V4L2CaptureDevice buffer back into the driver"; return false; } return true; @@ -786,7 +839,8 @@ void V4L2CaptureDelegate::DoCapture() { pollfd device_pfd = {}; device_pfd.fd = device_fd_.get(); device_pfd.events = POLLIN; - const int result = HANDLE_EINTR(poll(&device_pfd, 1, kCaptureTimeoutMs)); + const int result = + HANDLE_EINTR(v4l2_->poll(&device_pfd, 1, kCaptureTimeoutMs)); if (result < 0) { SetErrorState(FROM_HERE, "Poll failed"); return; @@ -810,7 +864,8 @@ void V4L2CaptureDelegate::DoCapture() { v4l2_buffer buffer; FillV4L2Buffer(&buffer, 0); - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) < 0) { + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) < + 0) { SetErrorState(FROM_HERE, "Failed to dequeue capture buffer"); return; } @@ -856,7 +911,8 @@ void V4L2CaptureDelegate::DoCapture() { std::move(cb).Run(std::move(blob)); } - if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) { + if (HANDLE_EINTR(v4l2_->ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < + 0) { SetErrorState(FROM_HERE, "Failed to enqueue capture buffer"); return; } @@ -873,23 +929,24 @@ void V4L2CaptureDelegate::SetErrorState(const base::Location& from_here, client_->OnError(from_here, reason); } -V4L2CaptureDelegate::BufferTracker::BufferTracker() = default; +V4L2CaptureDelegate::BufferTracker::BufferTracker(V4L2CaptureDevice* v4l2) + : v4l2_(v4l2) {} V4L2CaptureDelegate::BufferTracker::~BufferTracker() { if (start_ == nullptr) return; - const int result = munmap(start_, length_); - PLOG_IF(ERROR, result < 0) << "Error munmap()ing V4L2 buffer"; + const int result = v4l2_->munmap(start_, length_); + PLOG_IF(ERROR, result < 0) << "Error munmap()ing V4L2CaptureDevice buffer"; } bool V4L2CaptureDelegate::BufferTracker::Init(int fd, const v4l2_buffer& buffer) { // Some devices require mmap() to be called with both READ and WRITE. // See http://crbug.com/178582. - void* const start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, buffer.m.offset); + void* const start = v4l2_->mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, buffer.m.offset); if (start == MAP_FAILED) { - DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace"; + DLOG(ERROR) << "Error mmap()ing a V4L2CaptureDevice buffer into userspace"; return false; } start_ = static_cast<uint8_t*>(start); diff --git a/chromium/media/capture/video/linux/v4l2_capture_delegate.h b/chromium/media/capture/video/linux/v4l2_capture_delegate.h index 37f1964b088..5a246a3b7d0 100644 --- a/chromium/media/capture/video/linux/v4l2_capture_delegate.h +++ b/chromium/media/capture/video/linux/v4l2_capture_delegate.h @@ -12,6 +12,7 @@ #include "base/files/scoped_file.h" #include "base/macros.h" #include "build/build_config.h" +#include "media/capture/video/linux/v4l2_capture_device_impl.h" #include "media/capture/video/video_capture_device.h" #if defined(OS_OPENBSD) @@ -26,9 +27,10 @@ class Location; namespace media { -// Class doing the actual Linux capture using V4L2 API. V4L2 SPLANE/MPLANE -// capture specifics are implemented in derived classes. Created on the owner's -// thread, otherwise living, operating and destroyed on |v4l2_task_runner_|. +// Class doing the actual Linux capture using V4L2CaptureDevice API. +// V4L2CaptureDevice SPLANE/MPLANE capture specifics are implemented in derived +// classes. Created on the owner's thread, otherwise living, operating and +// destroyed on |v4l2_task_runner_|. class CAPTURE_EXPORT V4L2CaptureDelegate final { public: // Retrieves the #planes for a given |fourcc|, or 0 if unknown. @@ -42,6 +44,7 @@ class CAPTURE_EXPORT V4L2CaptureDelegate final { static std::list<uint32_t> GetListOfUsableFourCcs(bool prefer_mjpeg); V4L2CaptureDelegate( + V4L2CaptureDevice* v4l2, const VideoCaptureDeviceDescriptor& device_descriptor, const scoped_refptr<base::SingleThreadTaskRunner>& v4l2_task_runner, int power_line_frequency); @@ -68,9 +71,28 @@ class CAPTURE_EXPORT V4L2CaptureDelegate final { friend class V4L2CaptureDelegateTest; class BufferTracker; - - // VIDIOC_QUERYBUFs a buffer from V4L2, creates a BufferTracker for it and - // enqueues it (VIDIOC_QBUF) back into V4L2. + class ScopedV4L2DeviceFD { + public: + static constexpr int kInvalidId = -1; + ScopedV4L2DeviceFD(V4L2CaptureDevice* v4l2); + ~ScopedV4L2DeviceFD(); + int get(); + void reset(int fd = kInvalidId); + bool is_valid(); + + private: + int device_fd_; + V4L2CaptureDevice* const v4l2_; + }; + + bool RunIoctl(int fd, int request, void* argp); + mojom::RangePtr RetrieveUserControlRange(int device_fd, int control_id); + void ResetUserAndCameraControlsToDefault(int device_fd); + + // void CloseDevice(); + + // VIDIOC_QUERYBUFs a buffer from V4L2CaptureDevice, creates a BufferTracker + // for it and enqueues it (VIDIOC_QBUF) back into V4L2CaptureDevice. bool MapAndQueueBuffer(int index); void DoCapture(); @@ -78,6 +100,7 @@ class CAPTURE_EXPORT V4L2CaptureDelegate final { void SetErrorState(const base::Location& from_here, const std::string& reason); + V4L2CaptureDevice* const v4l2_; const scoped_refptr<base::SingleThreadTaskRunner> v4l2_task_runner_; const VideoCaptureDeviceDescriptor device_descriptor_; const int power_line_frequency_; @@ -86,7 +109,7 @@ class CAPTURE_EXPORT V4L2CaptureDelegate final { VideoCaptureFormat capture_format_; v4l2_format video_fmt_; std::unique_ptr<VideoCaptureDevice::Client> client_; - base::ScopedFD device_fd_; + ScopedV4L2DeviceFD device_fd_; base::queue<VideoCaptureDevice::TakePhotoCallback> take_photo_callbacks_; diff --git a/chromium/media/capture/video/linux/v4l2_capture_delegate_unittest.cc b/chromium/media/capture/video/linux/v4l2_capture_delegate_unittest.cc index bbbd9b72b03..446aab373a7 100644 --- a/chromium/media/capture/video/linux/v4l2_capture_delegate_unittest.cc +++ b/chromium/media/capture/video/linux/v4l2_capture_delegate_unittest.cc @@ -221,7 +221,9 @@ class V4L2CaptureDelegateTest : public ::testing::Test { public: V4L2CaptureDelegateTest() : device_descriptor_("Device 0", "/dev/video0"), + v4l2_(new V4L2CaptureDeviceImpl()), delegate_(std::make_unique<V4L2CaptureDelegate>( + v4l2_.get(), device_descriptor_, base::ThreadTaskRunnerHandle::Get(), 50)) {} @@ -229,6 +231,7 @@ class V4L2CaptureDelegateTest : public ::testing::Test { base::test::ScopedTaskEnvironment scoped_task_environment_; VideoCaptureDeviceDescriptor device_descriptor_; + scoped_refptr<V4L2CaptureDevice> v4l2_; std::unique_ptr<V4L2CaptureDelegate> delegate_; }; diff --git a/chromium/media/capture/video/linux/v4l2_capture_device.h b/chromium/media/capture/video/linux/v4l2_capture_device.h new file mode 100644 index 00000000000..2c95357c9a2 --- /dev/null +++ b/chromium/media/capture/video/linux/v4l2_capture_device.h @@ -0,0 +1,44 @@ +// 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_VIDEO_LINUX_V4L2_CAPTURE_DEVICE_H_ +#define MEDIA_CAPTURE_VIDEO_LINUX_V4L2_CAPTURE_DEVICE_H_ + +#include <poll.h> +#include <sys/fcntl.h> + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" +#include "media/capture/capture_export.h" + +namespace media { + +// Interface for abstracting out the V4L2 API. This allows using a mock or fake +// implementation in testing. +class CAPTURE_EXPORT V4L2CaptureDevice + : public base::RefCounted<V4L2CaptureDevice> { + public: + virtual int open(const char* device_name, int flags) = 0; + virtual int close(int fd) = 0; + virtual int ioctl(int fd, int request, void* argp) = 0; + virtual void* mmap(void* start, + size_t length, + int prot, + int flags, + int fd, + off_t offset) = 0; + + virtual int munmap(void* start, size_t length) = 0; + virtual int poll(struct pollfd* ufds, unsigned int nfds, int timeout) = 0; + + protected: + virtual ~V4L2CaptureDevice() {} + + private: + friend class base::RefCounted<V4L2CaptureDevice>; +}; + +} // namespace media + +#endif // MEDIA_CAPTURE_VIDEO_LINUX_V4L2_CAPTURE_DEVICE_H_ diff --git a/chromium/media/capture/video/linux/v4l2_capture_device_impl.cc b/chromium/media/capture/video/linux/v4l2_capture_device_impl.cc new file mode 100644 index 00000000000..c9040f5dee6 --- /dev/null +++ b/chromium/media/capture/video/linux/v4l2_capture_device_impl.cc @@ -0,0 +1,48 @@ +// 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/video/linux/v4l2_capture_device_impl.h" + +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/poll.h> +#include <unistd.h> + +namespace media { + +V4L2CaptureDeviceImpl::~V4L2CaptureDeviceImpl() = default; + +int V4L2CaptureDeviceImpl::open(const char* device_name, int flags) { + return ::open(device_name, flags); +} + +int V4L2CaptureDeviceImpl::close(int fd) { + return ::close(fd); +} + +int V4L2CaptureDeviceImpl::ioctl(int fd, int request, void* argp) { + return ::ioctl(fd, request, argp); +} + +void* V4L2CaptureDeviceImpl::mmap(void* start, + size_t length, + int prot, + int flags, + int fd, + off_t offset) { + return ::mmap(start, length, prot, flags, fd, offset); +} + +int V4L2CaptureDeviceImpl::munmap(void* start, size_t length) { + return ::munmap(start, length); +} + +int V4L2CaptureDeviceImpl::poll(struct pollfd* ufds, + unsigned int nfds, + int timeout) { + return ::poll(ufds, nfds, timeout); +} + +} // namespace media diff --git a/chromium/media/capture/video/linux/v4l2_capture_device_impl.h b/chromium/media/capture/video/linux/v4l2_capture_device_impl.h new file mode 100644 index 00000000000..936c8b0938b --- /dev/null +++ b/chromium/media/capture/video/linux/v4l2_capture_device_impl.h @@ -0,0 +1,39 @@ +// 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_VIDEO_LINUX_V4L2_CAPTURE_DEVICE_IMPL_H_ +#define MEDIA_CAPTURE_VIDEO_LINUX_V4L2_CAPTURE_DEVICE_IMPL_H_ + +#include <poll.h> +#include <sys/fcntl.h> + +#include "media/capture/capture_export.h" +#include "media/capture/video/linux/v4l2_capture_device.h" + +namespace media { + +// Implementation of V4L2CaptureDevice interface that delegates to the actual +// V4L2 APIs. +class CAPTURE_EXPORT V4L2CaptureDeviceImpl : public V4L2CaptureDevice { + public: + int open(const char* device_name, int flags) override; + int close(int fd) override; + int ioctl(int fd, int request, void* argp) override; + void* mmap(void* start, + size_t length, + int prot, + int flags, + int fd, + off_t offset) override; + + int munmap(void* start, size_t length) override; + int poll(struct pollfd* ufds, unsigned int nfds, int timeout) override; + + private: + ~V4L2CaptureDeviceImpl() override; +}; + +} // namespace media + +#endif // MEDIA_CAPTURE_VIDEO_LINUX_V4L2_CAPTURE_DEVICE_IMPL_H_ diff --git a/chromium/media/capture/video/linux/video_capture_device_chromeos.cc b/chromium/media/capture/video/linux/video_capture_device_chromeos.cc index 329939be1f9..8d4ba37da13 100644 --- a/chromium/media/capture/video/linux/video_capture_device_chromeos.cc +++ b/chromium/media/capture/video/linux/video_capture_device_chromeos.cc @@ -17,36 +17,25 @@ namespace media { -static CameraConfigChromeOS* GetCameraConfig() { - static CameraConfigChromeOS* config = new CameraConfigChromeOS(); - return config; -} - VideoCaptureDeviceChromeOS::VideoCaptureDeviceChromeOS( + const ChromeOSDeviceCameraConfig& camera_config, scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, + scoped_refptr<V4L2CaptureDevice> v4l2, const VideoCaptureDeviceDescriptor& device_descriptor) - : VideoCaptureDeviceLinux(device_descriptor), + : VideoCaptureDeviceLinux(std::move(v4l2), device_descriptor), + camera_config_(camera_config), screen_observer_delegate_( - new ScreenObserverDelegate(this, ui_task_runner)), - lens_facing_( - GetCameraConfig()->GetCameraFacing(device_descriptor.device_id, - device_descriptor.model_id)), - camera_orientation_( - GetCameraConfig()->GetOrientation(device_descriptor.device_id, - device_descriptor.model_id)), - // External cameras have lens_facing as MEDIA_VIDEO_FACING_NONE. - // We don't want to rotate the frame even if the device rotates. - rotates_with_device_(lens_facing_ != - VideoFacingMode::MEDIA_VIDEO_FACING_NONE) {} + new ScreenObserverDelegate(this, ui_task_runner)) {} VideoCaptureDeviceChromeOS::~VideoCaptureDeviceChromeOS() { screen_observer_delegate_->RemoveObserver(); } void VideoCaptureDeviceChromeOS::SetRotation(int rotation) { - if (!rotates_with_device_) { + if (!camera_config_.rotates_with_device) { rotation = 0; - } else if (lens_facing_ == VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT) { + } else if (camera_config_.lens_facing == + VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT) { // Original frame when |rotation| = 0 // ----------------------- // | * | @@ -82,7 +71,7 @@ void VideoCaptureDeviceChromeOS::SetRotation(int rotation) { } // Take into account camera orientation w.r.t. the display. External cameras // would have camera_orientation_ as 0. - rotation = (rotation + camera_orientation_) % 360; + rotation = (rotation + camera_config_.camera_orientation) % 360; VideoCaptureDeviceLinux::SetRotation(rotation); } diff --git a/chromium/media/capture/video/linux/video_capture_device_chromeos.h b/chromium/media/capture/video/linux/video_capture_device_chromeos.h index d9e738ed2f2..ffb6a377bc7 100644 --- a/chromium/media/capture/video/linux/video_capture_device_chromeos.h +++ b/chromium/media/capture/video/linux/video_capture_device_chromeos.h @@ -8,7 +8,6 @@ #include "base/macros.h" #include "base/single_thread_task_runner.h" #include "media/capture/video/chromeos/display_rotation_observer.h" -#include "media/capture/video/linux/camera_config_chromeos.h" #include "media/capture/video/linux/video_capture_device_linux.h" namespace display { @@ -17,14 +16,32 @@ class Display; namespace media { +struct ChromeOSDeviceCameraConfig { + ChromeOSDeviceCameraConfig(VideoFacingMode lens_facing, + int camera_orientation) + : lens_facing(lens_facing), + camera_orientation(camera_orientation), + // External cameras have lens_facing as MEDIA_VIDEO_FACING_NONE. + // We don't want to rotate the frame even if the device rotates. + rotates_with_device(lens_facing != + VideoFacingMode::MEDIA_VIDEO_FACING_NONE) {} + + const VideoFacingMode lens_facing; + const int camera_orientation; + // Whether the incoming frames should rotate when the device rotates. + const bool rotates_with_device; +}; + // This class is functionally the same as VideoCaptureDeviceLinux, with the // exception that it is aware of the orientation of the internal Display. When // the internal Display is rotated, the frames captured are rotated to match. class VideoCaptureDeviceChromeOS : public VideoCaptureDeviceLinux, public DisplayRotationObserver { public: - explicit VideoCaptureDeviceChromeOS( + VideoCaptureDeviceChromeOS( + const ChromeOSDeviceCameraConfig& camera_config, scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, + scoped_refptr<V4L2CaptureDevice> v4l2, const VideoCaptureDeviceDescriptor& device_descriptor); ~VideoCaptureDeviceChromeOS() override; @@ -34,11 +51,8 @@ class VideoCaptureDeviceChromeOS : public VideoCaptureDeviceLinux, private: // DisplayRotationObserver implementation. void SetDisplayRotation(const display::Display& display) override; + const ChromeOSDeviceCameraConfig camera_config_; scoped_refptr<ScreenObserverDelegate> screen_observer_delegate_; - const VideoFacingMode lens_facing_; - const int camera_orientation_; - // Whether the incoming frames should rotate when the device rotates. - const bool rotates_with_device_; DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureDeviceChromeOS); }; diff --git a/chromium/media/capture/video/linux/video_capture_device_factory_linux.cc b/chromium/media/capture/video/linux/video_capture_device_factory_linux.cc index 3699cb953ec..99c9912010e 100644 --- a/chromium/media/capture/video/linux/video_capture_device_factory_linux.cc +++ b/chromium/media/capture/video/linux/video_capture_device_factory_linux.cc @@ -44,6 +44,13 @@ const char kPidPathTemplate[] = "/sys/class/video4linux/%s/device/../idProduct"; const char kInterfacePathTemplate[] = "/sys/class/video4linux/%s/device/interface"; +#if defined(OS_CHROMEOS) +static CameraConfigChromeOS* GetCameraConfig() { + static CameraConfigChromeOS* config = new CameraConfigChromeOS(); + return config; +} +#endif + bool ReadIdFile(const std::string& path, std::string* id) { char id_buf[kVidPidSize]; FILE* file = fopen(path.c_str(), "rb"); @@ -57,155 +64,110 @@ bool ReadIdFile(const std::string& path, std::string* id) { return true; } -bool HasUsableFormats(int fd, uint32_t capabilities) { - if (!(capabilities & V4L2_CAP_VIDEO_CAPTURE)) - return false; - - const std::list<uint32_t>& usable_fourccs = - VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false); - v4l2_fmtdesc fmtdesc = {}; - fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0; - ++fmtdesc.index) { - if (std::find(usable_fourccs.begin(), usable_fourccs.end(), - fmtdesc.pixelformat) != usable_fourccs.end()) { - return true; - } - } - - DLOG(ERROR) << "No usable formats found"; - return false; +std::string ExtractFileNameFromDeviceId(const std::string& device_id) { + // |unique_id| is of the form "/dev/video2". |file_name| is "video2". + const char kDevDir[] = "/dev/"; + DCHECK(base::StartsWith(device_id, kDevDir, base::CompareCase::SENSITIVE)); + return device_id.substr(strlen(kDevDir), device_id.length()); } -std::list<float> GetFrameRateList(int fd, - uint32_t fourcc, - uint32_t width, - uint32_t height) { - std::list<float> frame_rates; - - v4l2_frmivalenum frame_interval = {}; - frame_interval.pixel_format = fourcc; - frame_interval.width = width; - frame_interval.height = height; - for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval)) == - 0; - ++frame_interval.index) { - if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { - if (frame_interval.discrete.numerator != 0) { - frame_rates.push_back( - frame_interval.discrete.denominator / - static_cast<float>(frame_interval.discrete.numerator)); - } - } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS || - frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { - // TODO(mcasas): see http://crbug.com/249953, support these devices. - NOTIMPLEMENTED_LOG_ONCE(); - break; +class DevVideoFilePathsDeviceProvider + : public VideoCaptureDeviceFactoryLinux::DeviceProvider { + public: + void GetDeviceIds(std::vector<std::string>* target_container) override { + const base::FilePath path("/dev/"); + base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES, + "video*"); + while (!enumerator.Next().empty()) { + const base::FileEnumerator::FileInfo info = enumerator.GetInfo(); + target_container->emplace_back(path.value() + info.GetName().value()); } } - // Some devices, e.g. Kinect, do not enumerate any frame rates, see - // http://crbug.com/412284. Set their frame_rate to zero. - if (frame_rates.empty()) - frame_rates.push_back(0); - return frame_rates; -} -void GetSupportedFormatsForV4L2BufferType( - int fd, - VideoCaptureFormats* supported_formats) { - v4l2_fmtdesc v4l2_format = {}; - v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &v4l2_format)) == 0; - ++v4l2_format.index) { - VideoCaptureFormat supported_format; - supported_format.pixel_format = - VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat( - v4l2_format.pixelformat); + std::string GetDeviceModelId(const std::string& device_id) override { + const std::string file_name = ExtractFileNameFromDeviceId(device_id); + std::string usb_id; + const std::string vid_path = + base::StringPrintf(kVidPathTemplate, file_name.c_str()); + if (!ReadIdFile(vid_path, &usb_id)) + return usb_id; - if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) - continue; + usb_id.append(":"); + const std::string pid_path = + base::StringPrintf(kPidPathTemplate, file_name.c_str()); + if (!ReadIdFile(pid_path, &usb_id)) + usb_id.clear(); - v4l2_frmsizeenum frame_size = {}; - frame_size.pixel_format = v4l2_format.pixelformat; - for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size)) == 0; - ++frame_size.index) { - if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { - supported_format.frame_size.SetSize(frame_size.discrete.width, - frame_size.discrete.height); - } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE || - frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { - // TODO(mcasas): see http://crbug.com/249953, support these devices. - NOTIMPLEMENTED_LOG_ONCE(); - } + return usb_id; + } - const std::list<float> frame_rates = GetFrameRateList( - fd, v4l2_format.pixelformat, frame_size.discrete.width, - frame_size.discrete.height); - for (const auto& frame_rate : frame_rates) { - supported_format.frame_rate = frame_rate; - supported_formats->push_back(supported_format); - DVLOG(1) << VideoCaptureFormat::ToString(supported_format); - } + std::string GetDeviceDisplayName(const std::string& device_id) override { + const std::string file_name = ExtractFileNameFromDeviceId(device_id); + const std::string interface_path = + base::StringPrintf(kInterfacePathTemplate, file_name.c_str()); + std::string display_name; + if (!base::ReadFileToStringWithMaxSize(base::FilePath(interface_path), + &display_name, + kMaxInterfaceNameSize)) { + return std::string(); } + return display_name; } -} -std::string ExtractFileNameFromDeviceId(const std::string& device_id) { - // |unique_id| is of the form "/dev/video2". |file_name| is "video2". - const char kDevDir[] = "/dev/"; - DCHECK(base::StartsWith(device_id, kDevDir, base::CompareCase::SENSITIVE)); - return device_id.substr(strlen(kDevDir), device_id.length()); -} - -std::string GetDeviceModelId(const std::string& device_id) { - const std::string file_name = ExtractFileNameFromDeviceId(device_id); - std::string usb_id; - const std::string vid_path = - base::StringPrintf(kVidPathTemplate, file_name.c_str()); - if (!ReadIdFile(vid_path, &usb_id)) - return usb_id; - - usb_id.append(":"); - const std::string pid_path = - base::StringPrintf(kPidPathTemplate, file_name.c_str()); - if (!ReadIdFile(pid_path, &usb_id)) - usb_id.clear(); - - return usb_id; -} + VideoFacingMode GetCameraFacing(const std::string& device_id, + const std::string& model_id) override { +#if defined(OS_CHROMEOS) + return GetCameraConfig()->GetCameraFacing(device_id, model_id); +#else + NOTREACHED(); + return MEDIA_VIDEO_FACING_NONE; +#endif + } -std::string GetDeviceDisplayName(const std::string& device_id) { - const std::string file_name = ExtractFileNameFromDeviceId(device_id); - const std::string interface_path = - base::StringPrintf(kInterfacePathTemplate, file_name.c_str()); - std::string display_name; - if (!base::ReadFileToStringWithMaxSize(base::FilePath(interface_path), - &display_name, - kMaxInterfaceNameSize)) { - return std::string(); + int GetOrientation(const std::string& device_id, + const std::string& model_id) override { +#if defined(OS_CHROMEOS) + return GetCameraConfig()->GetOrientation(device_id, model_id); +#else + NOTREACHED(); + return 0; +#endif } - return display_name; -} +}; } // namespace VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux( scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) - : ui_task_runner_(ui_task_runner) { -} + : v4l2_(new V4L2CaptureDeviceImpl()), + device_provider_(new DevVideoFilePathsDeviceProvider()), + ui_task_runner_(ui_task_runner) {} VideoCaptureDeviceFactoryLinux::~VideoCaptureDeviceFactoryLinux() = default; +void VideoCaptureDeviceFactoryLinux::SetV4L2EnvironmentForTesting( + scoped_refptr<V4L2CaptureDevice> v4l2, + std::unique_ptr<VideoCaptureDeviceFactoryLinux::DeviceProvider> + device_provider) { + v4l2_ = std::move(v4l2); + device_provider_ = std::move(device_provider); +} + std::unique_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryLinux::CreateDevice( const VideoCaptureDeviceDescriptor& device_descriptor) { DCHECK(thread_checker_.CalledOnValidThread()); #if defined(OS_CHROMEOS) - VideoCaptureDeviceChromeOS* self = - new VideoCaptureDeviceChromeOS(ui_task_runner_, device_descriptor); + ChromeOSDeviceCameraConfig camera_config( + device_provider_->GetCameraFacing(device_descriptor.device_id, + device_descriptor.model_id), + device_provider_->GetOrientation(device_descriptor.device_id, + device_descriptor.model_id)); + VideoCaptureDeviceChromeOS* self = new VideoCaptureDeviceChromeOS( + camera_config, ui_task_runner_, v4l2_.get(), device_descriptor); #else VideoCaptureDeviceLinux* self = - new VideoCaptureDeviceLinux(device_descriptor); + new VideoCaptureDeviceLinux(v4l2_.get(), device_descriptor); #endif if (!self) return std::unique_ptr<VideoCaptureDevice>(); @@ -227,38 +189,36 @@ void VideoCaptureDeviceFactoryLinux::GetDeviceDescriptors( VideoCaptureDeviceDescriptors* device_descriptors) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(device_descriptors->empty()); - const base::FilePath path("/dev/"); - base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES, - "video*"); - - while (!enumerator.Next().empty()) { - const base::FileEnumerator::FileInfo info = enumerator.GetInfo(); - const std::string unique_id = path.value() + info.GetName().value(); - const base::ScopedFD fd(HANDLE_EINTR(open(unique_id.c_str(), O_RDONLY))); + std::vector<std::string> filepaths; + device_provider_->GetDeviceIds(&filepaths); + for (auto& unique_id : filepaths) { + const base::ScopedFD fd( + HANDLE_EINTR(v4l2_->open(unique_id.c_str(), O_RDONLY))); if (!fd.is_valid()) { - DLOG(ERROR) << "Couldn't open " << info.GetName().value(); + DLOG(ERROR) << "Couldn't open " << unique_id; continue; } - // Test if this is a V4L2 capture device and if it has at least one - // supported capture format. Devices that have capture and output + // Test if this is a V4L2CaptureDevice capture device and if it has at least + // one supported capture format. Devices that have capture and output // capabilities at the same time are memory-to-memory and are skipped, see // http://crbug.com/139356. v4l2_capability cap; - if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && + if ((HANDLE_EINTR(v4l2_->ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE && !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) && HasUsableFormats(fd.get(), cap.capabilities)) { - const std::string model_id = GetDeviceModelId(unique_id); - std::string display_name = GetDeviceDisplayName(unique_id); + const std::string model_id = + device_provider_->GetDeviceModelId(unique_id); + std::string display_name = + device_provider_->GetDeviceDisplayName(unique_id); if (display_name.empty()) display_name = reinterpret_cast<char*>(cap.card); #if defined(OS_CHROMEOS) - static CameraConfigChromeOS* config = new CameraConfigChromeOS(); device_descriptors->emplace_back( display_name, unique_id, model_id, VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE, VideoCaptureTransportType::OTHER_TRANSPORT, - config->GetCameraFacing(unique_id, model_id)); + device_provider_->GetCameraFacing(unique_id, model_id)); #else device_descriptors->emplace_back( display_name, unique_id, model_id, @@ -278,7 +238,8 @@ void VideoCaptureDeviceFactoryLinux::GetSupportedFormats( DCHECK(thread_checker_.CalledOnValidThread()); if (device.device_id.empty()) return; - base::ScopedFD fd(HANDLE_EINTR(open(device.device_id.c_str(), O_RDONLY))); + base::ScopedFD fd( + HANDLE_EINTR(v4l2_->open(device.device_id.c_str(), O_RDONLY))); if (!fd.is_valid()) // Failed to open this device. return; supported_formats->clear(); @@ -287,16 +248,100 @@ void VideoCaptureDeviceFactoryLinux::GetSupportedFormats( GetSupportedFormatsForV4L2BufferType(fd.get(), supported_formats); } -#if !defined(OS_CHROMEOS) -// static -VideoCaptureDeviceFactory* -VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, - MojoJpegDecodeAcceleratorFactoryCB jda_factory, - MojoJpegEncodeAcceleratorFactoryCB jea_factory) { - return new VideoCaptureDeviceFactoryLinux(ui_task_runner); +bool VideoCaptureDeviceFactoryLinux::HasUsableFormats(int fd, + uint32_t capabilities) { + if (!(capabilities & V4L2_CAP_VIDEO_CAPTURE)) + return false; + + const std::list<uint32_t>& usable_fourccs = + VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false); + v4l2_fmtdesc fmtdesc = {}; + fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + for (; HANDLE_EINTR(v4l2_->ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0; + ++fmtdesc.index) { + if (std::find(usable_fourccs.begin(), usable_fourccs.end(), + fmtdesc.pixelformat) != usable_fourccs.end()) { + return true; + } + } + + DLOG(ERROR) << "No usable formats found"; + return false; +} + +std::list<float> VideoCaptureDeviceFactoryLinux::GetFrameRateList( + int fd, + uint32_t fourcc, + uint32_t width, + uint32_t height) { + std::list<float> frame_rates; + + v4l2_frmivalenum frame_interval = {}; + frame_interval.pixel_format = fourcc; + frame_interval.width = width; + frame_interval.height = height; + for (; HANDLE_EINTR(v4l2_->ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, + &frame_interval)) == 0; + ++frame_interval.index) { + if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { + if (frame_interval.discrete.numerator != 0) { + frame_rates.push_back( + frame_interval.discrete.denominator / + static_cast<float>(frame_interval.discrete.numerator)); + } + } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS || + frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { + // TODO(mcasas): see http://crbug.com/249953, support these devices. + NOTIMPLEMENTED_LOG_ONCE(); + break; + } + } + // Some devices, e.g. Kinect, do not enumerate any frame rates, see + // http://crbug.com/412284. Set their frame_rate to zero. + if (frame_rates.empty()) + frame_rates.push_back(0); + return frame_rates; +} + +void VideoCaptureDeviceFactoryLinux::GetSupportedFormatsForV4L2BufferType( + int fd, + VideoCaptureFormats* supported_formats) { + v4l2_fmtdesc v4l2_format = {}; + v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + for (; HANDLE_EINTR(v4l2_->ioctl(fd, VIDIOC_ENUM_FMT, &v4l2_format)) == 0; + ++v4l2_format.index) { + VideoCaptureFormat supported_format; + supported_format.pixel_format = + VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat( + v4l2_format.pixelformat); + + if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) + continue; + + v4l2_frmsizeenum frame_size = {}; + frame_size.pixel_format = v4l2_format.pixelformat; + for (; HANDLE_EINTR( + v4l2_->ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size)) == 0; + ++frame_size.index) { + if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { + supported_format.frame_size.SetSize(frame_size.discrete.width, + frame_size.discrete.height); + } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE || + frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { + // TODO(mcasas): see http://crbug.com/249953, support these devices. + NOTIMPLEMENTED_LOG_ONCE(); + } + + const std::list<float> frame_rates = GetFrameRateList( + fd, v4l2_format.pixelformat, frame_size.discrete.width, + frame_size.discrete.height); + for (const auto& frame_rate : frame_rates) { + supported_format.frame_rate = frame_rate; + supported_formats->push_back(supported_format); + DVLOG(1) << VideoCaptureFormat::ToString(supported_format); + } + } + } } -#endif } // namespace media diff --git a/chromium/media/capture/video/linux/video_capture_device_factory_linux.h b/chromium/media/capture/video/linux/video_capture_device_factory_linux.h index 50e8db4db88..d3f06f9168e 100644 --- a/chromium/media/capture/video/linux/video_capture_device_factory_linux.h +++ b/chromium/media/capture/video/linux/video_capture_device_factory_linux.h @@ -11,6 +11,7 @@ #include "base/macros.h" #include "base/single_thread_task_runner.h" +#include "media/capture/video/linux/v4l2_capture_device.h" #include "media/capture/video_capture_types.h" namespace media { @@ -20,10 +21,36 @@ namespace media { class CAPTURE_EXPORT VideoCaptureDeviceFactoryLinux : public VideoCaptureDeviceFactory { public: + class CAPTURE_EXPORT DeviceProvider { + public: + virtual ~DeviceProvider() {} + virtual void GetDeviceIds(std::vector<std::string>* target_container) = 0; + virtual std::string GetDeviceModelId(const std::string& device_id) = 0; + virtual std::string GetDeviceDisplayName(const std::string& device_id) = 0; + virtual VideoFacingMode GetCameraFacing(const std::string& device_id, + const std::string& model_id) = 0; + // Get the orientation of the camera. The value is the angle that the camera + // image needs to be rotated clockwise so it shows correctly on the display + // in its natural orientation. It should be 0, 90, 180, or 270. + // + // For example, suppose a device has a naturally tall screen. The + // back-facing camera sensor is mounted in landscape. You are looking at the + // screen. If the top side of the camera sensor is aligned with the right + // edge of the screen in natural orientation, the value should be 90. If the + // top side of a front-facing camera sensor is aligned with the right of the + // screen, the value should be 270. + virtual int GetOrientation(const std::string& device_id, + const std::string& model_id) = 0; + }; + explicit VideoCaptureDeviceFactoryLinux( scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); ~VideoCaptureDeviceFactoryLinux() override; + void SetV4L2EnvironmentForTesting( + scoped_refptr<V4L2CaptureDevice> v4l2, + std::unique_ptr<DeviceProvider> device_provider); + std::unique_ptr<VideoCaptureDevice> CreateDevice( const VideoCaptureDeviceDescriptor& device_descriptor) override; void GetDeviceDescriptors( @@ -33,6 +60,17 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryLinux VideoCaptureFormats* supported_formats) override; private: + bool HasUsableFormats(int fd, uint32_t capabilities); + std::list<float> GetFrameRateList(int fd, + uint32_t fourcc, + uint32_t width, + uint32_t height); + void GetSupportedFormatsForV4L2BufferType( + int fd, + VideoCaptureFormats* supported_formats); + + scoped_refptr<V4L2CaptureDevice> v4l2_; + std::unique_ptr<DeviceProvider> device_provider_; scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryLinux); }; diff --git a/chromium/media/capture/video/linux/video_capture_device_factory_linux_unittest.cc b/chromium/media/capture/video/linux/video_capture_device_factory_linux_unittest.cc new file mode 100644 index 00000000000..aa25be89fb6 --- /dev/null +++ b/chromium/media/capture/video/linux/video_capture_device_factory_linux_unittest.cc @@ -0,0 +1,107 @@ +// Copyright 2016 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/video/linux/video_capture_device_factory_linux.h" +#include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" +#include "media/capture/video/linux/fake_v4l2_impl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; + +namespace media { + +class DescriptorDeviceProvider + : public VideoCaptureDeviceFactoryLinux::DeviceProvider { + public: + void AddDevice(const VideoCaptureDeviceDescriptor& descriptor) { + descriptors_.emplace_back(descriptor); + } + + void GetDeviceIds(std::vector<std::string>* target_container) override { + for (const auto& entry : descriptors_) { + target_container->emplace_back(entry.device_id); + } + } + + std::string GetDeviceModelId(const std::string& device_id) override { + auto iter = + std::find_if(descriptors_.begin(), descriptors_.end(), + [&device_id](const VideoCaptureDeviceDescriptor& val) { + return val.device_id == device_id; + }); + if (iter == descriptors_.end()) + CHECK(false) << "Unknown device_id " << device_id; + + return iter->model_id; + } + + std::string GetDeviceDisplayName(const std::string& device_id) override { + auto iter = + std::find_if(descriptors_.begin(), descriptors_.end(), + [&device_id](const VideoCaptureDeviceDescriptor& val) { + return val.device_id == device_id; + }); + if (iter == descriptors_.end()) + CHECK(false) << "Unknown device_id " << device_id; + + return iter->display_name(); + } + + VideoFacingMode GetCameraFacing(const std::string& device_id, + const std::string& model_id) override { + return MEDIA_VIDEO_FACING_NONE; + } + + int GetOrientation(const std::string& device_id, + const std::string& model_id) override { + return 0; + } + + private: + std::vector<VideoCaptureDeviceDescriptor> descriptors_; +}; + +class VideoCaptureDeviceFactoryLinuxTest : public ::testing::Test { + public: + VideoCaptureDeviceFactoryLinuxTest() {} + ~VideoCaptureDeviceFactoryLinuxTest() override = default; + + void SetUp() override { + factory_ = std::make_unique<VideoCaptureDeviceFactoryLinux>( + base::ThreadTaskRunnerHandle::Get()); + scoped_refptr<FakeV4L2Impl> fake_v4l2(new FakeV4L2Impl()); + fake_v4l2_ = fake_v4l2.get(); + auto fake_device_provider = std::make_unique<DescriptorDeviceProvider>(); + fake_device_provider_ = fake_device_provider.get(); + factory_->SetV4L2EnvironmentForTesting(std::move(fake_v4l2), + std::move(fake_device_provider)); + } + + base::test::ScopedTaskEnvironment scoped_task_environment_; + FakeV4L2Impl* fake_v4l2_; + DescriptorDeviceProvider* fake_device_provider_; + std::unique_ptr<VideoCaptureDeviceFactoryLinux> factory_; +}; + +TEST_F(VideoCaptureDeviceFactoryLinuxTest, EnumerateSingleFakeV4L2Device) { + // Setup + const std::string stub_display_name = "Fake Device 0"; + const std::string stub_device_id = "/dev/video0"; + VideoCaptureDeviceDescriptor descriptor(stub_display_name, stub_device_id); + fake_device_provider_->AddDevice(descriptor); + fake_v4l2_->AddDevice(stub_device_id, FakeV4L2DeviceConfig(descriptor)); + + // Exercise + VideoCaptureDeviceDescriptors descriptors; + factory_->GetDeviceDescriptors(&descriptors); + + // Verification + ASSERT_EQ(1u, descriptors.size()); + ASSERT_EQ(stub_device_id, descriptors[0].device_id); + ASSERT_EQ(stub_display_name, descriptors[0].display_name()); +} + +}; // namespace media diff --git a/chromium/media/capture/video/linux/video_capture_device_linux.cc b/chromium/media/capture/video/linux/video_capture_device_linux.cc index 594596a07de..808b74f418d 100644 --- a/chromium/media/capture/video/linux/video_capture_device_linux.cc +++ b/chromium/media/capture/video/linux/video_capture_device_linux.cc @@ -37,8 +37,10 @@ std::list<uint32_t> VideoCaptureDeviceLinux::GetListOfUsableFourCCs( } VideoCaptureDeviceLinux::VideoCaptureDeviceLinux( + scoped_refptr<V4L2CaptureDevice> v4l2, const VideoCaptureDeviceDescriptor& device_descriptor) : device_descriptor_(device_descriptor), + v4l2_(std::move(v4l2)), v4l2_thread_("V4L2CaptureThread") {} VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() { @@ -59,7 +61,8 @@ void VideoCaptureDeviceLinux::AllocateAndStart( const int line_frequency = TranslatePowerLineFrequencyToV4L2(GetPowerLineFrequency(params)); capture_impl_ = std::make_unique<V4L2CaptureDelegate>( - device_descriptor_, v4l2_thread_.task_runner(), line_frequency); + v4l2_.get(), device_descriptor_, v4l2_thread_.task_runner(), + line_frequency); if (!capture_impl_) { client->OnError(FROM_HERE, "Failed to create VideoCaptureDelegate"); return; diff --git a/chromium/media/capture/video/linux/video_capture_device_linux.h b/chromium/media/capture/video/linux/video_capture_device_linux.h index cd34355e84b..e94cc6ac3e1 100644 --- a/chromium/media/capture/video/linux/video_capture_device_linux.h +++ b/chromium/media/capture/video/linux/video_capture_device_linux.h @@ -18,6 +18,7 @@ #include "base/files/scoped_file.h" #include "base/macros.h" #include "base/threading/thread.h" +#include "media/capture/video/linux/v4l2_capture_device_impl.h" #include "media/capture/video/video_capture_device.h" #include "media/capture/video_capture_types.h" @@ -32,6 +33,7 @@ class VideoCaptureDeviceLinux : public VideoCaptureDevice { static std::list<uint32_t> GetListOfUsableFourCCs(bool favour_mjpeg); explicit VideoCaptureDeviceLinux( + scoped_refptr<V4L2CaptureDevice> v4l2, const VideoCaptureDeviceDescriptor& device_descriptor); ~VideoCaptureDeviceLinux() override; @@ -52,6 +54,8 @@ class VideoCaptureDeviceLinux : public VideoCaptureDevice { private: static int TranslatePowerLineFrequencyToV4L2(PowerLineFrequency frequency); + const scoped_refptr<V4L2CaptureDevice> v4l2_; + // Internal delegate doing the actual capture setting, buffer allocation and // circulation with the V4L2 API. Created in the thread where // VideoCaptureDeviceLinux lives but otherwise operating and deleted on diff --git a/chromium/media/capture/video/mac/video_capture_device_factory_mac.mm b/chromium/media/capture/video/mac/video_capture_device_factory_mac.mm index d240605877f..48d3552524d 100644 --- a/chromium/media/capture/video/mac/video_capture_device_factory_mac.mm +++ b/chromium/media/capture/video/mac/video_capture_device_factory_mac.mm @@ -120,14 +120,4 @@ void VideoCaptureDeviceFactoryMac::GetSupportedFormats( } } -// static -VideoCaptureDeviceFactory* -VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, - MojoJpegDecodeAcceleratorFactoryCB jda_factory, - MojoJpegEncodeAcceleratorFactoryCB jea_factory) { - return new VideoCaptureDeviceFactoryMac(); -} - } // namespace media diff --git a/chromium/media/capture/video/mock_gpu_memory_buffer_manager.cc b/chromium/media/capture/video/mock_gpu_memory_buffer_manager.cc index 69629786d89..9b8befe84bf 100644 --- a/chromium/media/capture/video/mock_gpu_memory_buffer_manager.cc +++ b/chromium/media/capture/video/mock_gpu_memory_buffer_manager.cc @@ -93,7 +93,9 @@ class FakeGpuMemoryBuffer : public gfx::GpuMemoryBuffer { gfx::GpuMemoryBufferId GetId() const override { return handle_.id; } - gfx::GpuMemoryBufferHandle GetHandle() const override { return handle_; } + gfx::GpuMemoryBufferHandle GetHandle() const override { + return gfx::CloneHandleForIPC(handle_); + } ClientBuffer AsClientBuffer() override { NOTREACHED(); diff --git a/chromium/media/capture/video/shared_memory_buffer_tracker.cc b/chromium/media/capture/video/shared_memory_buffer_tracker.cc index 7cd4a05e580..e375a183c12 100644 --- a/chromium/media/capture/video/shared_memory_buffer_tracker.cc +++ b/chromium/media/capture/video/shared_memory_buffer_tracker.cc @@ -39,4 +39,8 @@ SharedMemoryBufferTracker::GetNonOwnedSharedMemoryHandleForLegacyIPC() { return provider_.GetNonOwnedSharedMemoryHandleForLegacyIPC(); } +uint32_t SharedMemoryBufferTracker::GetMemorySizeInBytes() { + return provider_.GetMemorySizeInBytes(); +} + } // namespace media diff --git a/chromium/media/capture/video/shared_memory_buffer_tracker.h b/chromium/media/capture/video/shared_memory_buffer_tracker.h index 2c92ca017e2..92abef763c9 100644 --- a/chromium/media/capture/video/shared_memory_buffer_tracker.h +++ b/chromium/media/capture/video/shared_memory_buffer_tracker.h @@ -27,6 +27,7 @@ class SharedMemoryBufferTracker final : public VideoCaptureBufferTracker { std::unique_ptr<VideoCaptureBufferHandle> GetMemoryMappedAccess() override; mojo::ScopedSharedBufferHandle GetHandleForTransit(bool read_only) override; base::SharedMemoryHandle GetNonOwnedSharedMemoryHandleForLegacyIPC() override; + uint32_t GetMemorySizeInBytes() override; private: SharedMemoryHandleProvider provider_; diff --git a/chromium/media/capture/video/shared_memory_handle_provider.cc b/chromium/media/capture/video/shared_memory_handle_provider.cc index 72a909337e6..2e2e7e78603 100644 --- a/chromium/media/capture/video/shared_memory_handle_provider.cc +++ b/chromium/media/capture/video/shared_memory_handle_provider.cc @@ -63,6 +63,25 @@ bool SharedMemoryHandleProvider::InitFromMojoHandle( return true; } +#if defined(OS_LINUX) +bool SharedMemoryHandleProvider::InitAsReadOnlyFromRawFileDescriptor( + mojo::ScopedHandle fd_handle, + uint32_t memory_size_in_bytes) { + base::PlatformFile platform_file; + const MojoResult result = + mojo::UnwrapPlatformFile(std::move(fd_handle), &platform_file); + if (result != MOJO_RESULT_OK) + return false; + base::UnguessableToken guid = base::UnguessableToken::Create(); + base::SharedMemoryHandle memory_handle( + base::FileDescriptor(platform_file, true), 0u, guid); + mapped_size_ = memory_size_in_bytes; + read_only_flag_ = true; + shared_memory_.emplace(memory_handle, read_only_flag_); + return true; +} +#endif // defined(OS_LINUX) + mojo::ScopedSharedBufferHandle SharedMemoryHandleProvider::GetHandleForInterProcessTransit(bool read_only) { if (read_only_flag_ && !read_only) { @@ -88,6 +107,10 @@ SharedMemoryHandleProvider::GetNonOwnedSharedMemoryHandleForLegacyIPC() { return shared_memory_->handle(); } +uint32_t SharedMemoryHandleProvider::GetMemorySizeInBytes() { + return static_cast<uint32_t>(mapped_size_); +} + std::unique_ptr<VideoCaptureBufferHandle> SharedMemoryHandleProvider::GetHandleForInProcessAccess() { { diff --git a/chromium/media/capture/video/shared_memory_handle_provider.h b/chromium/media/capture/video/shared_memory_handle_provider.h index 8a14f3a4d35..7cd578bcba6 100644 --- a/chromium/media/capture/video/shared_memory_handle_provider.h +++ b/chromium/media/capture/video/shared_memory_handle_provider.h @@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/memory/shared_memory.h" #include "base/optional.h" +#include "build/build_config.h" #include "media/capture/capture_export.h" #include "media/capture/video/video_capture_buffer_handle.h" #include "media/capture/video/video_capture_device.h" @@ -35,6 +36,15 @@ class CAPTURE_EXPORT SharedMemoryHandleProvider // if the operation failed. bool InitFromMojoHandle(mojo::ScopedSharedBufferHandle buffer_handle); +// This requires platforms where base::SharedMemoryHandle is backed by a +// file descriptor. +#if defined(OS_LINUX) + bool InitAsReadOnlyFromRawFileDescriptor(mojo::ScopedHandle fd_handle, + uint32_t memory_size_in_bytes); +#endif // defined(OS_LINUX) + + uint32_t GetMemorySizeInBytes(); + // Implementation of Buffer::HandleProvider: mojo::ScopedSharedBufferHandle GetHandleForInterProcessTransit( bool read_only) override; diff --git a/chromium/media/capture/video/video_capture_buffer_pool.h b/chromium/media/capture/video/video_capture_buffer_pool.h index 1760aea78a4..1c4aa541e93 100644 --- a/chromium/media/capture/video/video_capture_buffer_pool.h +++ b/chromium/media/capture/video/video_capture_buffer_pool.h @@ -7,6 +7,7 @@ #include "base/memory/ref_counted.h" #include "media/capture/capture_export.h" +#include "media/capture/mojom/video_capture_types.mojom.h" #include "media/capture/video_capture_types.h" #include "mojo/public/cpp/system/buffer.h" #include "ui/gfx/geometry/size.h" @@ -50,6 +51,9 @@ class CAPTURE_EXPORT VideoCaptureBufferPool virtual base::SharedMemoryHandle GetNonOwnedSharedMemoryHandleForLegacyIPC( int buffer_id) = 0; + virtual mojom::SharedMemoryViaRawFileDescriptorPtr + CreateSharedMemoryViaRawFileDescriptorStruct(int buffer_id) = 0; + // Try and obtain a read/write access to the buffer. virtual std::unique_ptr<VideoCaptureBufferHandle> GetHandleForInProcessAccess( int buffer_id) = 0; diff --git a/chromium/media/capture/video/video_capture_buffer_pool_impl.cc b/chromium/media/capture/video/video_capture_buffer_pool_impl.cc index 477f5697029..9359b38be22 100644 --- a/chromium/media/capture/video/video_capture_buffer_pool_impl.cc +++ b/chromium/media/capture/video/video_capture_buffer_pool_impl.cc @@ -11,6 +11,7 @@ #include "build/build_config.h" #include "media/capture/video/video_capture_buffer_handle.h" #include "media/capture/video/video_capture_buffer_tracker.h" +#include "mojo/public/cpp/system/platform_handle.h" #include "ui/gfx/buffer_format_util.h" namespace media { @@ -53,6 +54,33 @@ VideoCaptureBufferPoolImpl::GetNonOwnedSharedMemoryHandleForLegacyIPC( return tracker->GetNonOwnedSharedMemoryHandleForLegacyIPC(); } +mojom::SharedMemoryViaRawFileDescriptorPtr +VideoCaptureBufferPoolImpl::CreateSharedMemoryViaRawFileDescriptorStruct( + int buffer_id) { +// This requires platforms where base::SharedMemoryHandle is backed by a +// file descriptor. +#if defined(OS_LINUX) + base::AutoLock lock(lock_); + + VideoCaptureBufferTracker* tracker = GetTracker(buffer_id); + if (!tracker) { + NOTREACHED() << "Invalid buffer_id."; + return 0u; + } + + auto result = mojom::SharedMemoryViaRawFileDescriptor::New(); + result->file_descriptor_handle = mojo::WrapPlatformFile( + base::SharedMemory::DuplicateHandle( + tracker->GetNonOwnedSharedMemoryHandleForLegacyIPC()) + .GetHandle()); + result->shared_memory_size_in_bytes = tracker->GetMemorySizeInBytes(); + return result; +#else + NOTREACHED(); + return mojom::SharedMemoryViaRawFileDescriptorPtr(); +#endif +} + std::unique_ptr<VideoCaptureBufferHandle> VideoCaptureBufferPoolImpl::GetHandleForInProcessAccess(int buffer_id) { base::AutoLock lock(lock_); diff --git a/chromium/media/capture/video/video_capture_buffer_pool_impl.h b/chromium/media/capture/video/video_capture_buffer_pool_impl.h index 34b585f0885..2cde52214b3 100644 --- a/chromium/media/capture/video/video_capture_buffer_pool_impl.h +++ b/chromium/media/capture/video/video_capture_buffer_pool_impl.h @@ -40,6 +40,8 @@ class CAPTURE_EXPORT VideoCaptureBufferPoolImpl bool read_only) override; base::SharedMemoryHandle GetNonOwnedSharedMemoryHandleForLegacyIPC( int buffer_id) override; + mojom::SharedMemoryViaRawFileDescriptorPtr + CreateSharedMemoryViaRawFileDescriptorStruct(int buffer_id) override; std::unique_ptr<VideoCaptureBufferHandle> GetHandleForInProcessAccess( int buffer_id) override; int ReserveForProducer(const gfx::Size& dimensions, diff --git a/chromium/media/capture/video/video_capture_buffer_tracker.h b/chromium/media/capture/video/video_capture_buffer_tracker.h index 040ff5368bb..a4f7dff560c 100644 --- a/chromium/media/capture/video/video_capture_buffer_tracker.h +++ b/chromium/media/capture/video/video_capture_buffer_tracker.h @@ -44,6 +44,7 @@ class CAPTURE_EXPORT VideoCaptureBufferTracker { bool read_only) = 0; virtual base::SharedMemoryHandle GetNonOwnedSharedMemoryHandleForLegacyIPC() = 0; + virtual uint32_t GetMemorySizeInBytes() = 0; private: // |dimensions_| may change as a VideoCaptureBufferTracker is re-used, but diff --git a/chromium/media/capture/video/video_capture_device_client.cc b/chromium/media/capture/video/video_capture_device_client.cc index 1a1bc937b31..64dd779fc2f 100644 --- a/chromium/media/capture/video/video_capture_device_client.cc +++ b/chromium/media/capture/video/video_capture_device_client.cc @@ -64,7 +64,8 @@ void GetI420BufferAccess( *y_plane_stride = dimensions.width(); *uv_plane_stride = *y_plane_stride / 2; } -} + +} // anonymous namespace namespace media { @@ -96,12 +97,14 @@ class BufferPoolBufferHandleProvider }; VideoCaptureDeviceClient::VideoCaptureDeviceClient( + VideoCaptureBufferType target_buffer_type, std::unique_ptr<VideoFrameReceiver> receiver, scoped_refptr<VideoCaptureBufferPool> buffer_pool, - const VideoCaptureJpegDecoderFactoryCB& jpeg_decoder_factory) - : receiver_(std::move(receiver)), - jpeg_decoder_factory_callback_(jpeg_decoder_factory), - external_jpeg_decoder_initialized_(false), + VideoCaptureJpegDecoderFactoryCB optional_jpeg_decoder_factory_callback) + : target_buffer_type_(target_buffer_type), + receiver_(std::move(receiver)), + optional_jpeg_decoder_factory_callback_( + std::move(optional_jpeg_decoder_factory_callback)), buffer_pool_(std::move(buffer_pool)), last_captured_pixel_format_(PIXEL_FORMAT_UNKNOWN) { on_started_using_gpu_cb_ = @@ -138,6 +141,7 @@ void VideoCaptureDeviceClient::OnIncomingCapturedData( base::TimeTicks reference_time, base::TimeDelta timestamp, int frame_feedback_id) { + DFAKE_SCOPED_RECURSIVE_LOCK(call_from_producer_); TRACE_EVENT0("media", "VideoCaptureDeviceClient::OnIncomingCapturedData"); if (last_captured_pixel_format_ != format.pixel_format) { @@ -145,11 +149,11 @@ void VideoCaptureDeviceClient::OnIncomingCapturedData( last_captured_pixel_format_ = format.pixel_format; if (format.pixel_format == PIXEL_FORMAT_MJPEG && - !external_jpeg_decoder_initialized_) { - external_jpeg_decoder_initialized_ = true; - external_jpeg_decoder_ = jpeg_decoder_factory_callback_.Run(); - if (external_jpeg_decoder_) - external_jpeg_decoder_->Initialize(); + optional_jpeg_decoder_factory_callback_) { + external_jpeg_decoder_ = + std::move(optional_jpeg_decoder_factory_callback_).Run(); + DCHECK(external_jpeg_decoder_); + external_jpeg_decoder_->Initialize(); } } @@ -400,9 +404,21 @@ VideoCaptureDeviceClient::ReserveOutputBuffer(const gfx::Size& frame_size, if (!base::ContainsValue(buffer_ids_known_by_receiver_, buffer_id)) { media::mojom::VideoBufferHandlePtr buffer_handle = media::mojom::VideoBufferHandle::New(); - buffer_handle->set_shared_buffer_handle( - buffer_pool_->GetHandleForInterProcessTransit(buffer_id, - true /*read_only*/)); + switch (target_buffer_type_) { + case VideoCaptureBufferType::kSharedMemory: + buffer_handle->set_shared_buffer_handle( + buffer_pool_->GetHandleForInterProcessTransit(buffer_id, + true /*read_only*/)); + break; + case VideoCaptureBufferType::kSharedMemoryViaRawFileDescriptor: + buffer_handle->set_shared_memory_via_raw_file_descriptor( + buffer_pool_->CreateSharedMemoryViaRawFileDescriptorStruct( + buffer_id)); + break; + case VideoCaptureBufferType::kMailboxHolder: + NOTREACHED(); + break; + } receiver_->OnNewBuffer(buffer_id, std::move(buffer_handle)); buffer_ids_known_by_receiver_.push_back(buffer_id); } diff --git a/chromium/media/capture/video/video_capture_device_client.h b/chromium/media/capture/video/video_capture_device_client.h index 7708de91fc7..01dacc7376c 100644 --- a/chromium/media/capture/video/video_capture_device_client.h +++ b/chromium/media/capture/video/video_capture_device_client.h @@ -15,6 +15,7 @@ #include "base/memory/ref_counted.h" #include "base/threading/thread_collision_warner.h" #include "media/capture/capture_export.h" +#include "media/capture/mojom/video_capture_types.mojom.h" #include "media/capture/video/video_capture_device.h" namespace media { @@ -23,11 +24,15 @@ class VideoFrameReceiver; class VideoCaptureJpegDecoder; using VideoCaptureJpegDecoderFactoryCB = - base::Callback<std::unique_ptr<VideoCaptureJpegDecoder>()>; + base::OnceCallback<std::unique_ptr<VideoCaptureJpegDecoder>()>; // Implementation of VideoCaptureDevice::Client that uses a buffer pool // to provide buffers and converts incoming data to the I420 format for -// consumption by a given VideoFrameReceiver. +// consumption by a given VideoFrameReceiver. If +// |optional_jpeg_decoder_factory_callback| is provided, the +// VideoCaptureDeviceClient will attempt to use it for decoding of MJPEG frames. +// Otherwise, it will use libyuv to perform MJPEG to I420 conversion in +// software. // // Methods of this class may be called from any thread, and in practice will // often be called on some auxiliary thread depending on the platform and the @@ -39,9 +44,10 @@ class CAPTURE_EXPORT VideoCaptureDeviceClient : public VideoCaptureDevice::Client { public: VideoCaptureDeviceClient( + VideoCaptureBufferType target_buffer_type, std::unique_ptr<VideoFrameReceiver> receiver, scoped_refptr<VideoCaptureBufferPool> buffer_pool, - const VideoCaptureJpegDecoderFactoryCB& jpeg_decoder_factory); + VideoCaptureJpegDecoderFactoryCB optional_jpeg_decoder_factory_callback); ~VideoCaptureDeviceClient() override; static Buffer MakeBufferStruct( @@ -95,15 +101,14 @@ class CAPTURE_EXPORT VideoCaptureDeviceClient base::TimeDelta timestamp, int frame_feedback_id); + const VideoCaptureBufferType target_buffer_type_; + // The receiver to which we post events. const std::unique_ptr<VideoFrameReceiver> receiver_; std::vector<int> buffer_ids_known_by_receiver_; - const VideoCaptureJpegDecoderFactoryCB jpeg_decoder_factory_callback_; + VideoCaptureJpegDecoderFactoryCB optional_jpeg_decoder_factory_callback_; std::unique_ptr<VideoCaptureJpegDecoder> external_jpeg_decoder_; - - // Whether |external_jpeg_decoder_| has been initialized. - bool external_jpeg_decoder_initialized_; base::OnceClosure on_started_using_gpu_cb_; // The pool of shared-memory buffers used for capturing. diff --git a/chromium/media/capture/video/video_capture_device_client_unittest.cc b/chromium/media/capture/video/video_capture_device_client_unittest.cc index a3467e7e17a..56ada337446 100644 --- a/chromium/media/capture/video/video_capture_device_client_unittest.cc +++ b/chromium/media/capture/video/video_capture_device_client_unittest.cc @@ -54,8 +54,8 @@ class VideoCaptureDeviceClientTest : public ::testing::Test { gpu_memory_buffer_manager_ = std::make_unique<unittest_internal::MockGpuMemoryBufferManager>(); device_client_ = std::make_unique<VideoCaptureDeviceClient>( - std::move(controller), buffer_pool, - base::Bind(&ReturnNullPtrAsJpecDecoder)); + VideoCaptureBufferType::kSharedMemory, std::move(controller), + buffer_pool, base::BindRepeating(&ReturnNullPtrAsJpecDecoder)); } ~VideoCaptureDeviceClientTest() override = default; diff --git a/chromium/media/capture/video/video_capture_device_descriptor.cc b/chromium/media/capture/video/video_capture_device_descriptor.cc index 3a718ed8c6c..be6c87ec4ce 100644 --- a/chromium/media/capture/video/video_capture_device_descriptor.cc +++ b/chromium/media/capture/video/video_capture_device_descriptor.cc @@ -61,10 +61,10 @@ bool VideoCaptureDeviceDescriptor::operator<( "FACING_ENVIRONMENT has a wrong value"); static_assert(kFacingMapping[MEDIA_VIDEO_FACING_USER] == 2, "FACING_USER has a wrong value"); - if (kFacingMapping[facing] > kFacingMapping[other.facing]) - return true; - if (device_id < other.device_id) - return true; + if (kFacingMapping[facing] != kFacingMapping[other.facing]) + return kFacingMapping[facing] > kFacingMapping[other.facing]; + if (device_id != other.device_id) + return device_id < other.device_id; return capture_api < other.capture_api; } @@ -90,6 +90,8 @@ const char* VideoCaptureDeviceDescriptor::GetCaptureApiTypeString() const { return "Camera API2 Full"; case VideoCaptureApi::ANDROID_API2_LIMITED: return "Camera API2 Limited"; + case VideoCaptureApi::VIRTUAL_DEVICE: + return "Virtual Device"; case VideoCaptureApi::UNKNOWN: return "Unknown"; } diff --git a/chromium/media/capture/video/video_capture_device_descriptor.h b/chromium/media/capture/video/video_capture_device_descriptor.h index 48eed13ece0..c53274df3bf 100644 --- a/chromium/media/capture/video/video_capture_device_descriptor.h +++ b/chromium/media/capture/video/video_capture_device_descriptor.h @@ -27,6 +27,7 @@ enum class VideoCaptureApi { ANDROID_API2_LEGACY, ANDROID_API2_FULL, ANDROID_API2_LIMITED, + VIRTUAL_DEVICE, UNKNOWN }; diff --git a/chromium/media/capture/video/video_capture_device_factory.cc b/chromium/media/capture/video/video_capture_device_factory.cc index 4dd4f7bde89..4d903b6a714 100644 --- a/chromium/media/capture/video/video_capture_device_factory.cc +++ b/chromium/media/capture/video/video_capture_device_factory.cc @@ -14,61 +14,12 @@ namespace media { -// static -std::unique_ptr<VideoCaptureDeviceFactory> -VideoCaptureDeviceFactory::CreateFactory( - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, - gpu::GpuMemoryBufferManager* gpu_buffer_manager, - MojoJpegDecodeAcceleratorFactoryCB jda_factory, - MojoJpegEncodeAcceleratorFactoryCB jea_factory) { - const base::CommandLine* command_line = - base::CommandLine::ForCurrentProcess(); - // Use a Fake or File Video Device Factory if the command line flags are - // present, otherwise use the normal, platform-dependent, device factory. - if (command_line->HasSwitch(switches::kUseFakeDeviceForMediaStream)) { - if (command_line->HasSwitch(switches::kUseFileForFakeVideoCapture)) { - return std::unique_ptr<VideoCaptureDeviceFactory>( - new FileVideoCaptureDeviceFactory()); - } else { - std::vector<FakeVideoCaptureDeviceSettings> config; - FakeVideoCaptureDeviceFactory::ParseFakeDevicesConfigFromOptionsString( - command_line->GetSwitchValueASCII( - switches::kUseFakeDeviceForMediaStream), - &config); - auto result = std::make_unique<FakeVideoCaptureDeviceFactory>(); - result->SetToCustomDevicesConfig(config); - return std::move(result); - } - } else { - // |ui_task_runner| is needed for the Linux ChromeOS factory to retrieve - // screen rotations. - return std::unique_ptr<VideoCaptureDeviceFactory>( - CreateVideoCaptureDeviceFactory(ui_task_runner, gpu_buffer_manager, - std::move(jda_factory), - std::move(jea_factory))); - } -} - VideoCaptureDeviceFactory::VideoCaptureDeviceFactory() { thread_checker_.DetachFromThread(); } VideoCaptureDeviceFactory::~VideoCaptureDeviceFactory() = default; -#if !defined(OS_MACOSX) && !defined(OS_LINUX) && !defined(OS_ANDROID) && \ - !defined(OS_WIN) -// static -VideoCaptureDeviceFactory* -VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, - gpu::GpuMemoryBufferManager* gpu_buffer_manager, - MojoJpegDecodeAcceleratorFactoryCB jda_factory, - MojoJpegEncodeAcceleratorFactoryCB jea_factory) { - NOTIMPLEMENTED(); - return NULL; -} -#endif - void VideoCaptureDeviceFactory::GetCameraLocationsAsync( std::unique_ptr<VideoCaptureDeviceDescriptors> device_descriptors, DeviceDescriptorsCallback result_callback) { diff --git a/chromium/media/capture/video/video_capture_device_factory.h b/chromium/media/capture/video/video_capture_device_factory.h index 1cd174ffc75..9ec274265c1 100644 --- a/chromium/media/capture/video/video_capture_device_factory.h +++ b/chromium/media/capture/video/video_capture_device_factory.h @@ -34,12 +34,6 @@ using MojoJpegEncodeAcceleratorFactoryCB = // crbug.com/665065 class CAPTURE_EXPORT VideoCaptureDeviceFactory { public: - static std::unique_ptr<VideoCaptureDeviceFactory> CreateFactory( - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, - gpu::GpuMemoryBufferManager* gpu_buffer_manager, - MojoJpegDecodeAcceleratorFactoryCB jpeg_decoder_factory, - MojoJpegEncodeAcceleratorFactoryCB jpeg_encoder_factory); - VideoCaptureDeviceFactory(); virtual ~VideoCaptureDeviceFactory(); @@ -76,12 +70,6 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactory { base::ThreadChecker thread_checker_; private: - static VideoCaptureDeviceFactory* CreateVideoCaptureDeviceFactory( - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, - gpu::GpuMemoryBufferManager* gpu_buffer_manager, - MojoJpegDecodeAcceleratorFactoryCB jda_factory, - MojoJpegEncodeAcceleratorFactoryCB jea_factory); - DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactory); }; diff --git a/chromium/media/capture/video/video_capture_device_unittest.cc b/chromium/media/capture/video/video_capture_device_unittest.cc index 21143688320..dbb4f6565f5 100644 --- a/chromium/media/capture/video/video_capture_device_unittest.cc +++ b/chromium/media/capture/video/video_capture_device_unittest.cc @@ -21,7 +21,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "media/base/bind_to_current_loop.h" -#include "media/capture/video/video_capture_device_factory.h" +#include "media/capture/video/create_video_capture_device_factory.h" #include "media/capture/video_capture_types.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -49,6 +49,7 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/fake_power_manager_client.h" #include "media/capture/video/chromeos/camera_buffer_factory.h" +#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" #include "media/capture/video/chromeos/local_gpu_memory_buffer_manager.h" #include "media/capture/video/chromeos/video_capture_device_chromeos_halv3.h" #include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h" @@ -287,22 +288,23 @@ class VideoCaptureDeviceTest video_capture_client_(new MockVideoCaptureClient( base::Bind(&VideoCaptureDeviceTest::OnFrameCaptured, base::Unretained(this)))), - image_capture_client_(new MockImageCaptureClient()), + image_capture_client_(new MockImageCaptureClient()) { #if defined(OS_CHROMEOS) - local_gpu_memory_buffer_manager_(new LocalGpuMemoryBufferManager()), - dbus_setter_(chromeos::DBusThreadManager::GetSetterForTesting()), -#endif - video_capture_device_factory_(VideoCaptureDeviceFactory::CreateFactory( - base::ThreadTaskRunnerHandle::Get(), -#if defined(OS_CHROMEOS) - local_gpu_memory_buffer_manager_.get(), -#else - nullptr, + local_gpu_memory_buffer_manager_ = + std::make_unique<LocalGpuMemoryBufferManager>(); + dbus_setter_ = chromeos::DBusThreadManager::GetSetterForTesting(); + VideoCaptureDeviceFactoryChromeOS::SetGpuBufferManager( + local_gpu_memory_buffer_manager_.get()); + if (!CameraHalDispatcherImpl::GetInstance()->IsStarted()) { + CameraHalDispatcherImpl::GetInstance()->Start( + base::DoNothing::Repeatedly< + media::mojom::JpegDecodeAcceleratorRequest>(), + base::DoNothing::Repeatedly< + media::mojom::JpegEncodeAcceleratorRequest>()); + } #endif - base::BindRepeating( - [](media::mojom::JpegDecodeAcceleratorRequest) {}), - base::DoNothing::Repeatedly< - media::mojom::JpegEncodeAcceleratorRequest>())) { + video_capture_device_factory_ = + CreateVideoCaptureDeviceFactory(base::ThreadTaskRunnerHandle::Get()); } void SetUp() override { @@ -435,12 +437,10 @@ class VideoCaptureDeviceTest const scoped_refptr<MockImageCaptureClient> image_capture_client_; VideoCaptureFormat last_format_; #if defined(OS_CHROMEOS) - const std::unique_ptr<LocalGpuMemoryBufferManager> - local_gpu_memory_buffer_manager_; + std::unique_ptr<LocalGpuMemoryBufferManager> local_gpu_memory_buffer_manager_; std::unique_ptr<chromeos::DBusThreadManagerSetter> dbus_setter_; #endif - const std::unique_ptr<VideoCaptureDeviceFactory> - video_capture_device_factory_; + std::unique_ptr<VideoCaptureDeviceFactory> video_capture_device_factory_; }; // Cause hangs on Windows Debug. http://crbug.com/417824 diff --git a/chromium/media/capture/video/video_capture_jpeg_decoder.h b/chromium/media/capture/video/video_capture_jpeg_decoder.h index c5b32cf4519..e2da00d54c8 100644 --- a/chromium/media/capture/video/video_capture_jpeg_decoder.h +++ b/chromium/media/capture/video/video_capture_jpeg_decoder.h @@ -13,6 +13,8 @@ namespace media { +// All methods are allowed to be called from any thread, but calls must be +// non-concurrently. class CAPTURE_EXPORT VideoCaptureJpegDecoder { public: // Enumeration of decoder status. The enumeration is published for clients to @@ -24,7 +26,7 @@ class CAPTURE_EXPORT VideoCaptureJpegDecoder { // decode error. }; - using DecodeDoneCB = base::Callback<void( + using DecodeDoneCB = base::RepeatingCallback<void( int buffer_id, int frame_feedback_id, std::unique_ptr<VideoCaptureDevice::Client::Buffer:: diff --git a/chromium/media/capture/video/video_capture_jpeg_decoder_impl.cc b/chromium/media/capture/video/video_capture_jpeg_decoder_impl.cc new file mode 100644 index 00000000000..b82bae90b11 --- /dev/null +++ b/chromium/media/capture/video/video_capture_jpeg_decoder_impl.cc @@ -0,0 +1,260 @@ +// 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/video/video_capture_jpeg_decoder_impl.h" + +#include "base/metrics/histogram_macros.h" +#include "media/base/media_switches.h" + +namespace media { + +VideoCaptureJpegDecoderImpl::VideoCaptureJpegDecoderImpl( + MojoJpegDecodeAcceleratorFactoryCB jpeg_decoder_factory, + scoped_refptr<base::SequencedTaskRunner> decoder_task_runner, + DecodeDoneCB decode_done_cb, + base::RepeatingCallback<void(const std::string&)> send_log_message_cb) + : jpeg_decoder_factory_(std::move(jpeg_decoder_factory)), + decoder_task_runner_(std::move(decoder_task_runner)), + decode_done_cb_(std::move(decode_done_cb)), + send_log_message_cb_(std::move(send_log_message_cb)), + has_received_decoded_frame_(false), + next_bitstream_buffer_id_(0), + in_buffer_id_(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId), + decoder_status_(INIT_PENDING), + weak_ptr_factory_(this) {} + +VideoCaptureJpegDecoderImpl::~VideoCaptureJpegDecoderImpl() { + // |this| was set as |decoder_|'s client. |decoder_| has to be deleted on + // |decoder_task_runner_| before this destructor returns to ensure that it + // doesn't call back into its client. + + if (!decoder_) + return; + + if (decoder_task_runner_->RunsTasksInCurrentSequence()) { + decoder_.reset(); + return; + } + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + // base::Unretained is safe because |this| will be valid until |event| + // is signaled. + decoder_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&VideoCaptureJpegDecoderImpl::DestroyDecoderOnIOThread, + base::Unretained(this), &event)); + event.Wait(); +} + +void VideoCaptureJpegDecoderImpl::Initialize() { + if (!IsVideoCaptureAcceleratedJpegDecodingEnabled()) { + decoder_status_ = FAILED; + RecordInitDecodeUMA_Locked(); + return; + } + + decoder_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&VideoCaptureJpegDecoderImpl::FinishInitialization, + weak_ptr_factory_.GetWeakPtr())); +} + +VideoCaptureJpegDecoderImpl::STATUS VideoCaptureJpegDecoderImpl::GetStatus() + const { + base::AutoLock lock(lock_); + return decoder_status_; +} + +void VideoCaptureJpegDecoderImpl::DecodeCapturedData( + const uint8_t* data, + size_t in_buffer_size, + const media::VideoCaptureFormat& frame_format, + base::TimeTicks reference_time, + base::TimeDelta timestamp, + media::VideoCaptureDevice::Client::Buffer out_buffer) { + DCHECK(decoder_); + + TRACE_EVENT_ASYNC_BEGIN0("jpeg", "VideoCaptureJpegDecoderImpl decoding", + next_bitstream_buffer_id_); + TRACE_EVENT0("jpeg", "VideoCaptureJpegDecoderImpl::DecodeCapturedData"); + + // TODO(kcwu): enqueue decode requests in case decoding is not fast enough + // (say, if decoding time is longer than 16ms for 60fps 4k image) + { + base::AutoLock lock(lock_); + if (IsDecoding_Locked()) { + DVLOG(1) << "Drop captured frame. Previous jpeg frame is still decoding"; + return; + } + } + + // Enlarge input buffer if necessary. + if (!in_shared_memory_.get() || + in_buffer_size > in_shared_memory_->mapped_size()) { + // Reserve 2x space to avoid frequent reallocations for initial frames. + const size_t reserved_size = 2 * in_buffer_size; + in_shared_memory_.reset(new base::SharedMemory); + if (!in_shared_memory_->CreateAndMapAnonymous(reserved_size)) { + base::AutoLock lock(lock_); + decoder_status_ = FAILED; + LOG(WARNING) << "CreateAndMapAnonymous failed, size=" << reserved_size; + return; + } + } + memcpy(in_shared_memory_->memory(), data, in_buffer_size); + + // No need to lock for |in_buffer_id_| since IsDecoding_Locked() is false. + in_buffer_id_ = next_bitstream_buffer_id_; + media::BitstreamBuffer in_buffer(in_buffer_id_, in_shared_memory_->handle(), + in_buffer_size); + // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. + next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; + + // The API of |decoder_| requires us to wrap the |out_buffer| in a VideoFrame. + const gfx::Size dimensions = frame_format.frame_size; + std::unique_ptr<media::VideoCaptureBufferHandle> out_buffer_access = + out_buffer.handle_provider->GetHandleForInProcessAccess(); + base::SharedMemoryHandle out_handle = + out_buffer.handle_provider->GetNonOwnedSharedMemoryHandleForLegacyIPC(); + scoped_refptr<media::VideoFrame> out_frame = + media::VideoFrame::WrapExternalSharedMemory( + media::PIXEL_FORMAT_I420, // format + dimensions, // coded_size + gfx::Rect(dimensions), // visible_rect + dimensions, // natural_size + out_buffer_access->data(), // data + out_buffer_access->mapped_size(), // data_size + out_handle, // handle + 0, // shared_memory_offset + timestamp); // timestamp + if (!out_frame) { + base::AutoLock lock(lock_); + decoder_status_ = FAILED; + LOG(ERROR) << "DecodeCapturedData: WrapExternalSharedMemory failed"; + return; + } + // Hold onto the buffer access handle for the lifetime of the VideoFrame, to + // ensure the data pointers remain valid. + out_frame->AddDestructionObserver(base::BindOnce( + [](std::unique_ptr<media::VideoCaptureBufferHandle> handle) {}, + std::move(out_buffer_access))); + out_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, + frame_format.frame_rate); + + out_frame->metadata()->SetTimeTicks(media::VideoFrameMetadata::REFERENCE_TIME, + reference_time); + + media::mojom::VideoFrameInfoPtr out_frame_info = + media::mojom::VideoFrameInfo::New(); + out_frame_info->timestamp = timestamp; + out_frame_info->pixel_format = media::PIXEL_FORMAT_I420; + out_frame_info->coded_size = dimensions; + out_frame_info->visible_rect = gfx::Rect(dimensions); + out_frame_info->metadata = out_frame->metadata()->GetInternalValues().Clone(); + + { + base::AutoLock lock(lock_); + decode_done_closure_ = base::BindOnce( + decode_done_cb_, out_buffer.id, out_buffer.frame_feedback_id, + base::Passed(&out_buffer.access_permission), + base::Passed(&out_frame_info)); + } + + // base::Unretained is safe because |decoder_| is deleted on + // |decoder_task_runner_|. + decoder_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&media::JpegDecodeAccelerator::Decode, + base::Unretained(decoder_.get()), in_buffer, + std::move(out_frame))); +} + +void VideoCaptureJpegDecoderImpl::VideoFrameReady(int32_t bitstream_buffer_id) { + DCHECK(decoder_task_runner_->RunsTasksInCurrentSequence()); + TRACE_EVENT0("jpeg", "VideoCaptureJpegDecoderImpl::VideoFrameReady"); + if (!has_received_decoded_frame_) { + send_log_message_cb_.Run("Received decoded frame from Gpu Jpeg decoder"); + has_received_decoded_frame_ = true; + } + base::AutoLock lock(lock_); + + if (!IsDecoding_Locked()) { + LOG(ERROR) << "Got decode response while not decoding"; + return; + } + + if (bitstream_buffer_id != in_buffer_id_) { + LOG(ERROR) << "Unexpected bitstream_buffer_id " << bitstream_buffer_id + << ", expected " << in_buffer_id_; + return; + } + in_buffer_id_ = media::JpegDecodeAccelerator::kInvalidBitstreamBufferId; + + std::move(decode_done_closure_).Run(); + + TRACE_EVENT_ASYNC_END0("jpeg", "VideoCaptureJpegDecoderImpl decoding", + bitstream_buffer_id); +} + +void VideoCaptureJpegDecoderImpl::NotifyError( + int32_t bitstream_buffer_id, + media::JpegDecodeAccelerator::Error error) { + DCHECK(decoder_task_runner_->RunsTasksInCurrentSequence()); + LOG(ERROR) << "Decode error, bitstream_buffer_id=" << bitstream_buffer_id + << ", error=" << error; + send_log_message_cb_.Run("Gpu Jpeg decoder failed"); + base::AutoLock lock(lock_); + decode_done_closure_.Reset(); + decoder_status_ = FAILED; +} + +void VideoCaptureJpegDecoderImpl::FinishInitialization() { + TRACE_EVENT0("gpu", "VideoCaptureJpegDecoderImpl::FinishInitialization"); + DCHECK(decoder_task_runner_->RunsTasksInCurrentSequence()); + + media::mojom::JpegDecodeAcceleratorPtr remote_decoder; + jpeg_decoder_factory_.Run(mojo::MakeRequest(&remote_decoder)); + + base::AutoLock lock(lock_); + decoder_ = std::make_unique<media::MojoJpegDecodeAccelerator>( + decoder_task_runner_, remote_decoder.PassInterface()); + + decoder_->InitializeAsync( + this, + base::BindRepeating(&VideoCaptureJpegDecoderImpl::OnInitializationDone, + weak_ptr_factory_.GetWeakPtr())); +} + +void VideoCaptureJpegDecoderImpl::OnInitializationDone(bool success) { + TRACE_EVENT0("gpu", "VideoCaptureJpegDecoderImpl::OnInitializationDone"); + DCHECK(decoder_task_runner_->RunsTasksInCurrentSequence()); + + base::AutoLock lock(lock_); + if (!success) { + decoder_.reset(); + DLOG(ERROR) << "Failed to initialize JPEG decoder"; + } + + decoder_status_ = success ? INIT_PASSED : FAILED; + RecordInitDecodeUMA_Locked(); +} + +bool VideoCaptureJpegDecoderImpl::IsDecoding_Locked() const { + lock_.AssertAcquired(); + return !decode_done_closure_.is_null(); +} + +void VideoCaptureJpegDecoderImpl::RecordInitDecodeUMA_Locked() { + UMA_HISTOGRAM_BOOLEAN("Media.VideoCaptureGpuJpegDecoder.InitDecodeSuccess", + decoder_status_ == INIT_PASSED); +} + +void VideoCaptureJpegDecoderImpl::DestroyDecoderOnIOThread( + base::WaitableEvent* event) { + DCHECK(decoder_task_runner_->RunsTasksInCurrentSequence()); + decoder_.reset(); + event->Signal(); +} + +} // namespace media diff --git a/chromium/media/capture/video/video_capture_jpeg_decoder_impl.h b/chromium/media/capture/video/video_capture_jpeg_decoder_impl.h new file mode 100644 index 00000000000..a1bfcee8b75 --- /dev/null +++ b/chromium/media/capture/video/video_capture_jpeg_decoder_impl.h @@ -0,0 +1,119 @@ +// 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_VIDEO_VIDEO_CAPTURE_JPEG_DECODER_IMPL_H_ +#define MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_JPEG_DECODER_IMPL_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/sequence_checker.h" +#include "gpu/config/gpu_info.h" +#include "media/capture/capture_export.h" +#include "media/capture/video/video_capture_device_factory.h" +#include "media/capture/video/video_capture_jpeg_decoder.h" +#include "media/mojo/clients/mojo_jpeg_decode_accelerator.h" + +namespace base { +class WaitableEvent; +} + +namespace media { + +// Implementation of media::VideoCaptureJpegDecoder that delegates to a +// media::mojom::JpegDecodeAccelerator. When a frame is received in +// DecodeCapturedData(), it is copied to |in_shared_memory| for IPC transport +// to |decoder_|. When the decoder is finished with the frame, |decode_done_cb_| +// is invoked. Until |decode_done_cb_| is invoked, subsequent calls to +// DecodeCapturedData() are ignored. +// The given |decoder_task_runner| must allow blocking on |lock_|. +class CAPTURE_EXPORT VideoCaptureJpegDecoderImpl + : public media::VideoCaptureJpegDecoder, + public media::JpegDecodeAccelerator::Client { + public: + // |decode_done_cb| is called on the IO thread when decode succeeds. This can + // be on any thread. |decode_done_cb| is never called after + // VideoCaptureGpuJpegDecoder is destroyed. + VideoCaptureJpegDecoderImpl( + MojoJpegDecodeAcceleratorFactoryCB jpeg_decoder_factory, + scoped_refptr<base::SequencedTaskRunner> decoder_task_runner, + DecodeDoneCB decode_done_cb, + base::RepeatingCallback<void(const std::string&)> send_log_message_cb); + ~VideoCaptureJpegDecoderImpl() override; + + // Implementation of VideoCaptureJpegDecoder: + void Initialize() override; + STATUS GetStatus() const override; + void DecodeCapturedData( + const uint8_t* data, + size_t in_buffer_size, + const media::VideoCaptureFormat& frame_format, + base::TimeTicks reference_time, + base::TimeDelta timestamp, + media::VideoCaptureDevice::Client::Buffer out_buffer) override; + + // JpegDecodeAccelerator::Client implementation. + // These will be called on IO thread. + void VideoFrameReady(int32_t buffer_id) override; + void NotifyError(int32_t buffer_id, + media::JpegDecodeAccelerator::Error error) override; + + private: + void FinishInitialization(); + void OnInitializationDone(bool success); + + // Returns true if the decoding of last frame is not finished yet. + bool IsDecoding_Locked() const; + + // Records |decoder_status_| to histogram. + void RecordInitDecodeUMA_Locked(); + + void DestroyDecoderOnIOThread(base::WaitableEvent* event); + + MojoJpegDecodeAcceleratorFactoryCB jpeg_decoder_factory_; + scoped_refptr<base::SequencedTaskRunner> decoder_task_runner_; + + // The underlying JPEG decode accelerator. + std::unique_ptr<media::JpegDecodeAccelerator> decoder_; + + // The callback to run when decode succeeds. + const DecodeDoneCB decode_done_cb_; + + const base::RepeatingCallback<void(const std::string&)> send_log_message_cb_; + bool has_received_decoded_frame_; + + // Guards |decode_done_closure_| and |decoder_status_|. + mutable base::Lock lock_; + + // The closure of |decode_done_cb_| with bound parameters. + base::OnceClosure decode_done_closure_; + + // Next id for input BitstreamBuffer. + int32_t next_bitstream_buffer_id_; + + // The id for current input BitstreamBuffer being decoded. + int32_t in_buffer_id_; + + // Shared memory to store JPEG stream buffer. The input BitstreamBuffer is + // backed by this. + std::unique_ptr<base::SharedMemory> in_shared_memory_; + + STATUS decoder_status_; + + SEQUENCE_CHECKER(sequence_checker_); + + base::WeakPtrFactory<VideoCaptureJpegDecoderImpl> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(VideoCaptureJpegDecoderImpl); +}; + +} // namespace media + +#endif // MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_JPEG_DECODER_IMPL_H_ diff --git a/chromium/media/capture/video/win/video_capture_device_factory_win.cc b/chromium/media/capture/video/win/video_capture_device_factory_win.cc index ef04526c06f..bad25d00bf4 100644 --- a/chromium/media/capture/video/win/video_capture_device_factory_win.cc +++ b/chromium/media/capture/video/win/video_capture_device_factory_win.cc @@ -18,6 +18,7 @@ #include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/single_thread_task_runner.h" +#include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" #include "base/win/core_winrt_util.h" @@ -83,6 +84,11 @@ static_assert(arraysize(kBlacklistedCameraNames) == BLACKLISTED_CAMERA_MAX + 1, "kBlacklistedCameraNames should be same size as " "BlacklistedCameraNames enum"); +const char* const kModelIdsBlacklistedForMediaFoundation[] = { + // Devices using Empia 2860 or 2820 chips, see https://crbug.com/849636. + "eb1a:2860", "eb1a:2820", +}; + const std::pair<VideoCaptureApi, std::vector<std::pair<GUID, GUID>>> kMfAttributes[] = {{VideoCaptureApi::WIN_MEDIA_FOUNDATION, { @@ -100,6 +106,11 @@ bool IsDeviceBlacklistedForQueryingDetailedFrameRates( return display_name.find("WebcamMax") != std::string::npos; } +bool IsDeviceBlacklistedForMediaFoundationByModelId( + const std::string& model_id) { + return base::ContainsValue(kModelIdsBlacklistedForMediaFoundation, model_id); +} + bool LoadMediaFoundationDlls() { static const wchar_t* const kMfDLLs[] = { L"%WINDIR%\\system32\\mf.dll", L"%WINDIR%\\system32\\mfplat.dll", @@ -354,7 +365,7 @@ VideoCaptureDeviceFactoryWin::VideoCaptureDeviceFactoryWin() direct_show_get_supported_formats_func_ = base::BindRepeating(&GetDeviceSupportedFormatsDirectShow); - if (!PlatformSupportsMediaFoundation()) { + if (use_media_foundation_ && !PlatformSupportsMediaFoundation()) { use_media_foundation_ = false; LogVideoCaptureWinBackendUsed( VideoCaptureWinBackendUsed::kUsingDirectShowAsFallback); @@ -612,6 +623,8 @@ void VideoCaptureDeviceFactoryWin::GetDeviceDescriptorsMediaFoundation( const std::string device_id = base::SysWideToUTF8(std::wstring(id, id_size)); const std::string model_id = GetDeviceModelId(device_id); + if (IsDeviceBlacklistedForMediaFoundationByModelId(model_id)) + continue; if (list_was_empty || !DescriptorsContainDeviceId(*device_descriptors, device_id)) { device_descriptors->emplace_back( @@ -753,14 +766,4 @@ void VideoCaptureDeviceFactoryWin::GetSupportedFormats( GetApiSpecificSupportedFormats(device, formats); } -// static -VideoCaptureDeviceFactory* -VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, - MojoJpegDecodeAcceleratorFactoryCB jda_factory, - MojoJpegEncodeAcceleratorFactoryCB jea_factory) { - return new VideoCaptureDeviceFactoryWin(); -} - } // namespace media diff --git a/chromium/media/capture/video/win/video_capture_device_factory_win_unittest.cc b/chromium/media/capture/video/win/video_capture_device_factory_win_unittest.cc index 80b5532a6a0..27dd51e4f55 100644 --- a/chromium/media/capture/video/win/video_capture_device_factory_win_unittest.cc +++ b/chromium/media/capture/video/win/video_capture_device_factory_win_unittest.cc @@ -33,8 +33,16 @@ const wchar_t* kMFDeviceName2 = L"Device 2"; const wchar_t* kMFDeviceId5 = L"\\\\?\\usb#vid_0005&pid_0005&mi_00"; const wchar_t* kMFDeviceName5 = L"Dazzle"; +const wchar_t* kMFDeviceId6 = L"\\\\?\\usb#vid_eb1a&pid_2860&mi_00"; +const wchar_t* kMFDeviceName6 = L"Empia Device"; + void GetMFSupportedFormats(const VideoCaptureDeviceDescriptor& device, - VideoCaptureFormats* formats) {} + VideoCaptureFormats* formats) { + if (device.device_id == base::SysWideToUTF8(kMFDeviceId6)) { + VideoCaptureFormat arbitrary_format; + formats->emplace_back(arbitrary_format); + } +} // DirectShow devices const wchar_t* kDirectShowDeviceId0 = L"\\\\?\\usb#vid_0000&pid_0000&mi_00"; @@ -52,6 +60,9 @@ const wchar_t* kDirectShowDeviceName4 = L"Virtual Camera"; const wchar_t* kDirectShowDeviceId5 = L"\\\\?\\usb#vid_0005&pid_0005&mi_00#5"; const wchar_t* kDirectShowDeviceName5 = L"Dazzle"; +const wchar_t* kDirectShowDeviceId6 = L"\\\\?\\usb#vid_eb1a&pid_2860&mi_00"; +const wchar_t* kDirectShowDeviceName6 = L"Empia Device"; + void GetDirectShowSupportedFormats(const VideoCaptureDeviceDescriptor& device, VideoCaptureFormats* formats) { if (device.device_id == base::SysWideToUTF8(kDirectShowDeviceId5)) { @@ -426,7 +437,8 @@ HRESULT __stdcall MockMFEnumDeviceSources(IMFAttributes* attributes, new MockMFActivate(kMFDeviceId0, kMFDeviceName0, true, false), new MockMFActivate(kMFDeviceId1, kMFDeviceName1, true, true), new MockMFActivate(kMFDeviceId2, kMFDeviceName2, false, true), - new MockMFActivate(kMFDeviceId5, kMFDeviceName5, true, false)}; + new MockMFActivate(kMFDeviceId5, kMFDeviceName5, true, false), + new MockMFActivate(kMFDeviceId6, kMFDeviceName6, true, false)}; // Iterate once to get the match count and check for errors. *count = 0U; HRESULT hr; @@ -456,7 +468,8 @@ HRESULT EnumerateStubDirectShowDevices(IEnumMoniker** enum_moniker) { new StubMoniker(kDirectShowDeviceId1, kDirectShowDeviceName1), new StubMoniker(kDirectShowDeviceId3, kDirectShowDeviceName3), new StubMoniker(kDirectShowDeviceId4, kDirectShowDeviceName4), - new StubMoniker(kDirectShowDeviceId5, kDirectShowDeviceName5)}; + new StubMoniker(kDirectShowDeviceId5, kDirectShowDeviceName5), + new StubMoniker(kDirectShowDeviceId6, kDirectShowDeviceName6)}; StubEnumMoniker* stub_enum_moniker = new StubEnumMoniker(); for (StubMoniker* moniker : monikers) @@ -511,7 +524,7 @@ TEST_F(VideoCaptureDeviceFactoryMFWinTest, GetDeviceDescriptors) { base::BindRepeating(&EnumerateStubDirectShowDevices)); VideoCaptureDeviceDescriptors descriptors; factory_.GetDeviceDescriptors(&descriptors); - EXPECT_EQ(descriptors.size(), 6U); + EXPECT_EQ(descriptors.size(), 7U); for (auto it = descriptors.begin(); it != descriptors.end(); it++) { // Verify that there are no duplicates. EXPECT_EQ(FindDescriptorInRange(descriptors.begin(), it, it->device_id), @@ -555,6 +568,15 @@ TEST_F(VideoCaptureDeviceFactoryMFWinTest, GetDeviceDescriptors) { EXPECT_NE(it, descriptors.end()); EXPECT_EQ(it->capture_api, VideoCaptureApi::WIN_DIRECT_SHOW); EXPECT_EQ(it->display_name(), base::SysWideToUTF8(kDirectShowDeviceName5)); + + // Devices that are listed in both MediaFoundation and DirectShow but are + // blacklisted for use with MediaFoundation are expected to get enumerated + // with VideoCaptureApi::WIN_DIRECT_SHOW. + it = FindDescriptorInRange(descriptors.begin(), descriptors.end(), + base::SysWideToUTF8(kDirectShowDeviceId6)); + EXPECT_NE(it, descriptors.end()); + EXPECT_EQ(it->capture_api, VideoCaptureApi::WIN_DIRECT_SHOW); + EXPECT_EQ(it->display_name(), base::SysWideToUTF8(kDirectShowDeviceName6)); } } // namespace media diff --git a/chromium/media/capture/video/win/video_capture_device_win.cc b/chromium/media/capture/video/win/video_capture_device_win.cc index 78355961260..ae1bf4d602b 100644 --- a/chromium/media/capture/video/win/video_capture_device_win.cc +++ b/chromium/media/capture/video/win/video_capture_device_win.cc @@ -83,9 +83,9 @@ mojom::RangePtr RetrieveControlRangeAndCurrent( control_range->max = max; control_range->step = step; if (supported_modes != nullptr) { - if (flags && CameraControl_Flags_Auto) + if (flags & CameraControl_Flags_Auto) supported_modes->push_back(mojom::MeteringMode::CONTINUOUS); - if (flags && CameraControl_Flags_Manual) + if (flags & CameraControl_Flags_Manual) supported_modes->push_back(mojom::MeteringMode::MANUAL); } } @@ -95,9 +95,9 @@ mojom::RangePtr RetrieveControlRangeAndCurrent( if (SUCCEEDED(hr)) { control_range->current = current; if (current_mode != nullptr) { - if (flags && CameraControl_Flags_Auto) + if (flags & CameraControl_Flags_Auto) *current_mode = mojom::MeteringMode::CONTINUOUS; - else if (flags && CameraControl_Flags_Manual) + else if (flags & CameraControl_Flags_Manual) *current_mode = mojom::MeteringMode::MANUAL; } } diff --git a/chromium/media/capture/video_capture_types.cc b/chromium/media/capture/video_capture_types.cc index b6fc66e20c3..6cd3063bfee 100644 --- a/chromium/media/capture/video_capture_types.cc +++ b/chromium/media/capture/video_capture_types.cc @@ -70,7 +70,8 @@ bool VideoCaptureFormat::ComparePixelFormatPreference( } VideoCaptureParams::VideoCaptureParams() - : resolution_change_policy(ResolutionChangePolicy::FIXED_RESOLUTION), + : buffer_type(VideoCaptureBufferType::kSharedMemory), + resolution_change_policy(ResolutionChangePolicy::FIXED_RESOLUTION), power_line_frequency(PowerLineFrequency::FREQUENCY_DEFAULT) {} bool VideoCaptureParams::IsValid() const { diff --git a/chromium/media/capture/video_capture_types.h b/chromium/media/capture/video_capture_types.h index bb43a319454..cc7a5c42f6a 100644 --- a/chromium/media/capture/video_capture_types.h +++ b/chromium/media/capture/video_capture_types.h @@ -54,6 +54,12 @@ enum class PowerLineFrequency { FREQUENCY_MAX = FREQUENCY_60HZ }; +enum class VideoCaptureBufferType { + kSharedMemory, + kSharedMemoryViaRawFileDescriptor, + kMailboxHolder +}; + // Assert that the int:frequency mapping is correct. static_assert(static_cast<int>(PowerLineFrequency::FREQUENCY_DEFAULT) == 0, "static_cast<int>(FREQUENCY_DEFAULT) must equal 0."); @@ -135,6 +141,8 @@ struct CAPTURE_EXPORT VideoCaptureParams { // Requests a resolution and format at which the capture will occur. VideoCaptureFormat requested_format; + VideoCaptureBufferType buffer_type; + // Policy for resolution change. ResolutionChangePolicy resolution_change_policy; |