media_perception: Multiple input device access.
for the VideoCaptureServiceClient object.
BUG=chromium:911347,b:117872925
TEST=Verified on device that multiple clients can access same device.
Change-Id: I4d35980116c06d53447826538496c4a5ee09b93e
Reviewed-on: https://chromium-review.googlesource.com/1352734
Commit-Ready: Luke Sorenson <lasoren@chromium.org>
Tested-by: Luke Sorenson <lasoren@chromium.org>
Reviewed-by: Rahul Chaturvedi <rkc@chromium.org>
(cherry picked from commit c3de6011ee803c4c2b4239a48ed9962d29da5c79)
Reviewed-on: https://chromium-review.googlesource.com/c/1398864
Reviewed-by: Jacob Dufault <jdufault@chromium.org>
Commit-Queue: Luke Sorenson <lasoren@chromium.org>
diff --git a/media_perception/fake_video_capture_service_client.cc b/media_perception/fake_video_capture_service_client.cc
index 7bee671..6c70a2e 100644
--- a/media_perception/fake_video_capture_service_client.cc
+++ b/media_perception/fake_video_capture_service_client.cc
@@ -25,14 +25,18 @@
callback(devices_);
}
-void FakeVideoCaptureServiceClient::SetActiveDevice(
+void FakeVideoCaptureServiceClient::OpenDevice(
const std::string& device_id,
- const SetActiveDeviceCallback& callback) {}
+ const OpenDeviceCallback& callback) {}
-void FakeVideoCaptureServiceClient::StartVideoCapture(
- const SerializedVideoStreamParams& capture_format) {}
+bool FakeVideoCaptureServiceClient::IsVideoCaptureStartedForDevice(
+ const std::string& device_id,
+ SerializedVideoStreamParams* capture_format) { return false; }
-void FakeVideoCaptureServiceClient::StopVideoCapture() {}
+int FakeVideoCaptureServiceClient::AddFrameHandler(
+ const std::string& device_id,
+ const SerializedVideoStreamParams& capture_format,
+ FrameHandler frame_handler) { return 0; }
void FakeVideoCaptureServiceClient::CreateVirtualDevice(
const SerializedVideoDevice& video_device,
@@ -49,4 +53,9 @@
void FakeVideoCaptureServiceClient::CloseVirtualDevice(
const std::string& device_id) {}
+bool FakeVideoCaptureServiceClient::RemoveFrameHandler(
+ const std::string& device_id, int frame_handler_id) {
+ return false;
+}
+
} // namespace mri
diff --git a/media_perception/fake_video_capture_service_client.h b/media_perception/fake_video_capture_service_client.h
index 8c9b959..651f5a3 100644
--- a/media_perception/fake_video_capture_service_client.h
+++ b/media_perception/fake_video_capture_service_client.h
@@ -24,11 +24,17 @@
bool Connect() override;
bool IsConnected() override;
void GetDevices(const GetDevicesCallback& callback) override;
- void SetActiveDevice(const std::string& device_id,
- const SetActiveDeviceCallback& callback) override;
- void StartVideoCapture(
- const SerializedVideoStreamParams& capture_format) override;
- void StopVideoCapture() override;
+ void OpenDevice(const std::string& device_id,
+ const OpenDeviceCallback& callback) override;
+ bool IsVideoCaptureStartedForDevice(
+ const std::string& device_id,
+ SerializedVideoStreamParams* capture_format) override;
+ int AddFrameHandler(
+ const std::string& device_id,
+ const SerializedVideoStreamParams& capture_format,
+ FrameHandler handler) override;
+ bool RemoveFrameHandler(
+ const std::string& device_id, int frame_handler_id) override;
void CreateVirtualDevice(const SerializedVideoDevice& video_device,
const VirtualDeviceCallback& callback) override;
void PushFrameToVirtualDevice(const std::string& device_id,
diff --git a/media_perception/media_perception_controller_impl.h b/media_perception/media_perception_controller_impl.h
index ecf2bc3..6344fad 100644
--- a/media_perception/media_perception_controller_impl.h
+++ b/media_perception/media_perception_controller_impl.h
@@ -8,8 +8,8 @@
#include <memory>
#include <mojo/public/cpp/bindings/binding.h>
-#include "media_perception/video_capture_service_client.h"
#include "media_perception/rtanalytics.h"
+#include "media_perception/video_capture_service_client.h"
#include "mojom/media_perception_service.mojom.h"
namespace mri {
diff --git a/media_perception/mojo_connector.cc b/media_perception/mojo_connector.cc
index 1cd4a42..06b56e8 100644
--- a/media_perception/mojo_connector.cc
+++ b/media_perception/mojo_connector.cc
@@ -126,6 +126,8 @@
}
void MojoConnector::ConnectToVideoCaptureServiceOnIpcThread() {
+ unique_device_counter_ = 1;
+
media_perception_service_impl_->ConnectToVideoCaptureService(
mojo::MakeRequest(&device_factory_));
device_factory_.set_connection_error_handler(
@@ -206,51 +208,76 @@
callback(devices);
}
-void MojoConnector::SetActiveDevice(
- std::string device_id,
- const VideoCaptureServiceClient::SetActiveDeviceCallback& callback) {
+void MojoConnector::OpenDevice(
+ const std::string& device_id,
+ const VideoCaptureServiceClient::OpenDeviceCallback& callback) {
ipc_thread_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&MojoConnector::SetActiveDeviceOnIpcThread,
+ FROM_HERE, base::Bind(&MojoConnector::OpenDeviceOnIpcThread,
base::Unretained(this), device_id, callback));
}
-void MojoConnector::SetActiveDeviceOnIpcThread(
- std::string device_id,
- const VideoCaptureServiceClient::SetActiveDeviceCallback& callback) {
+void MojoConnector::OpenDeviceOnIpcThread(
+ const std::string& device_id,
+ const VideoCaptureServiceClient::OpenDeviceCallback& callback) {
std::map<std::string, std::string>::iterator it =
obfuscated_device_id_map_.find(device_id);
if (it == obfuscated_device_id_map_.end()) {
LOG(ERROR) << "Device id not found in obfuscated_device_id map.";
return;
}
+
+ std::map<std::string, video_capture::mojom::DevicePtr>::iterator
+ device_it = device_id_to_active_device_map_.find(device_id);
+ // Check to see if the device is already successfully opened.
+ if (device_it != device_id_to_active_device_map_.end()) {
+ callback(DeviceAccessResultCode::SUCCESS);
+ return;
+ }
+
+ video_capture::mojom::DevicePtr new_device;
device_factory_->CreateDevice(
- it->second, mojo::MakeRequest(&active_device_),
- base::Bind(&MojoConnector::OnSetActiveDeviceCallback,
- base::Unretained(this), callback));
+ it->second, mojo::MakeRequest(&new_device),
+ base::Bind(&MojoConnector::OnOpenDeviceCallback,
+ base::Unretained(this), device_id, callback));
+ device_id_to_active_device_map_.insert(
+ std::make_pair(device_id, std::move(new_device)));
}
-void MojoConnector::OnSetActiveDeviceCallback(
- const VideoCaptureServiceClient::SetActiveDeviceCallback& callback,
+void MojoConnector::OnOpenDeviceCallback(
+ const std::string& device_id,
+ const VideoCaptureServiceClient::OpenDeviceCallback& callback,
video_capture::mojom::DeviceAccessResultCode code) {
+ // Delete the device from the active device map if we were not successful in
+ // opening it.
+ if (code != video_capture::mojom::DeviceAccessResultCode::SUCCESS) {
+ device_id_to_active_device_map_.erase(device_id);
+ }
callback(GetDeviceAccessResultCode(code));
}
void MojoConnector::StartVideoCapture(
- const VideoStreamParams& capture_format,
- std::function<void(uint64_t timestamp_in_microseconds, const uint8_t* data,
- int data_size)>
- frame_handler) {
- LOG(INFO) << "Setting frame handler.";
- receiver_impl_.SetFrameHandler(std::move(frame_handler));
- // Mojo code to start video capture and pass frames to the frame handler.
+ const std::string& device_id,
+ std::shared_ptr<ReceiverImpl> receiver_impl,
+ const VideoStreamParams& capture_format) {
ipc_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&MojoConnector::StartVideoCaptureOnIpcThread,
- base::Unretained(this), capture_format));
+ base::Unretained(this),
+ device_id,
+ receiver_impl,
+ capture_format));
}
void MojoConnector::StartVideoCaptureOnIpcThread(
+ const std::string& device_id,
+ std::shared_ptr<ReceiverImpl> receiver_impl,
const VideoStreamParams& capture_format) {
LOG(INFO) << "Starting video capture on ipc thread.";
+ std::map<std::string, video_capture::mojom::DevicePtr>::iterator
+ it = device_id_to_active_device_map_.find(device_id);
+ if (it == device_id_to_active_device_map_.end()) {
+ LOG(ERROR) << "Device id not found in active device map.";
+ return;
+ }
auto requested_settings = media::mojom::VideoCaptureParams::New();
requested_settings->requested_format =
@@ -270,18 +297,19 @@
requested_settings->buffer_type =
media::mojom::VideoCaptureBufferType::kSharedMemoryViaRawFileDescriptor;
- active_device_->Start(std::move(requested_settings),
- receiver_impl_.CreateInterfacePtr());
+
+ it->second->Start(std::move(requested_settings),
+ receiver_impl->CreateInterfacePtr());
}
-void MojoConnector::StopVideoCapture() {
+void MojoConnector::StopVideoCapture(const std::string& device_id) {
ipc_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&MojoConnector::StopVideoCaptureOnIpcThread,
- base::Unretained(this)));
+ base::Unretained(this), device_id));
}
-void MojoConnector::StopVideoCaptureOnIpcThread() {
- active_device_ = video_capture::mojom::DevicePtr();
+void MojoConnector::StopVideoCaptureOnIpcThread(const std::string& device_id) {
+ device_id_to_active_device_map_.erase(device_id);
}
void MojoConnector::CreateVirtualDevice(
diff --git a/media_perception/mojo_connector.h b/media_perception/mojo_connector.h
index f760f5f..d0ef581 100644
--- a/media_perception/mojo_connector.h
+++ b/media_perception/mojo_connector.h
@@ -56,18 +56,18 @@
// Attempts to acquire exclusive access to a video device. Note that this does
// not block another client of the video capture service from taking over
// access on this device, which would disconnect this client.
- void SetActiveDevice(
- std::string device_id,
- const VideoCaptureServiceClient::SetActiveDeviceCallback& callback);
+ void OpenDevice(
+ const std::string& device_id,
+ const VideoCaptureServiceClient::OpenDeviceCallback& callback);
// Starts video capture on the active device.
- void StartVideoCapture(const VideoStreamParams& capture_format,
- std::function<void(uint64_t timestamp_in_microseconds,
- const uint8_t* data, int data_size)>
- frame_handler);
+ void StartVideoCapture(
+ const std::string& device_id,
+ std::shared_ptr<ReceiverImpl> receiver_impl,
+ const VideoStreamParams& capture_format);
- // Stops video capture on the active device.
- void StopVideoCapture();
+ // Stops video capture on the specified active device.
+ void StopVideoCapture(const std::string& device_id);
// Creates a new virtual device that frames can be fed into.
void CreateVirtualDevice(
@@ -104,17 +104,21 @@
const VideoCaptureServiceClient::GetDevicesCallback& callback,
std::vector<media::mojom::VideoCaptureDeviceInfoPtr> infos);
- void SetActiveDeviceOnIpcThread(
- std::string device_id,
- const VideoCaptureServiceClient::SetActiveDeviceCallback& callback);
+ void OpenDeviceOnIpcThread(
+ const std::string& device_id,
+ const VideoCaptureServiceClient::OpenDeviceCallback& callback);
- void OnSetActiveDeviceCallback(
- const VideoCaptureServiceClient::SetActiveDeviceCallback& callback,
+ void OnOpenDeviceCallback(
+ const std::string& device_id,
+ const VideoCaptureServiceClient::OpenDeviceCallback& callback,
video_capture::mojom::DeviceAccessResultCode code);
- void StartVideoCaptureOnIpcThread(const VideoStreamParams& capture_format);
+ void StartVideoCaptureOnIpcThread(
+ const std::string& device_id,
+ std::shared_ptr<ReceiverImpl> receiver_impl,
+ const VideoStreamParams& capture_format);
- void StopVideoCaptureOnIpcThread();
+ void StopVideoCaptureOnIpcThread(const std::string& device_id);
void CreateVirtualDeviceOnIpcThread(
const VideoDevice& video_device,
@@ -142,8 +146,10 @@
// Entry point Mojo object for talking to the video capture service API.
video_capture::mojom::DeviceFactoryPtr device_factory_;
- // Provides interface to an open device.
- video_capture::mojom::DevicePtr active_device_;
+ // Store a map from device ids to active devices.
+ std::map<std::string /* obfuscated device_id */,
+ video_capture::mojom::DevicePtr /* active_device */>
+ device_id_to_active_device_map_;
int unique_device_counter_;
@@ -160,9 +166,6 @@
std::string /* obfuscated device_id */,
std::string /* device_id */> obfuscated_device_id_map_;
- // Provides interface for receiving frames from the video capture service.
- ReceiverImpl receiver_impl_;
-
std::mutex vcs_connection_state_mutex_;
bool is_connected_to_vcs_ = false;
};
diff --git a/media_perception/proto_mojom_conversion.cc b/media_perception/proto_mojom_conversion.cc
index 7bd72f9..5a1b7a2 100644
--- a/media_perception/proto_mojom_conversion.cc
+++ b/media_perception/proto_mojom_conversion.cc
@@ -249,6 +249,16 @@
namespace mri {
+std::vector<uint8_t> SerializeVideoStreamParamsProto(
+ const VideoStreamParams& params) {
+ const int size = params.ByteSizeLong();
+ std::vector<uint8_t> bytes(size, 0);
+
+ CHECK(params.SerializeToArray(bytes.data(), size))
+ << "Failed to serialize params proto.";
+ return bytes;
+}
+
std::vector<uint8_t> SerializeVideoDeviceProto(const VideoDevice& device) {
const int size = device.ByteSizeLong();
std::vector<uint8_t> bytes(size, 0);
diff --git a/media_perception/proto_mojom_conversion.h b/media_perception/proto_mojom_conversion.h
index 62659d9..c3b8563 100644
--- a/media_perception/proto_mojom_conversion.h
+++ b/media_perception/proto_mojom_conversion.h
@@ -56,6 +56,8 @@
namespace mri {
+std::vector<uint8_t> SerializeVideoStreamParamsProto(
+ const VideoStreamParams& params);
std::vector<uint8_t> SerializeVideoDeviceProto(const VideoDevice& device);
std::vector<uint8_t> SerializeSuccessStatusProto(const SuccessStatus& status);
diff --git a/media_perception/receiver_impl.cc b/media_perception/receiver_impl.cc
index 244a620..45789e3 100644
--- a/media_perception/receiver_impl.cc
+++ b/media_perception/receiver_impl.cc
@@ -10,8 +10,46 @@
namespace mri {
-void ReceiverImpl::SetFrameHandler(FrameDataHandler frame_data_handler) {
- frame_data_handler_ = std::move(frame_data_handler);
+bool ReceiverImpl::HasValidCaptureFormat() {
+ return capture_format_.width_in_pixels() > 0
+ && capture_format_.height_in_pixels() > 0;
+}
+
+void ReceiverImpl::SetCaptureFormat(const VideoStreamParams& params) {
+ capture_format_ = params;
+}
+
+bool ReceiverImpl::CaptureFormatsMatch(const VideoStreamParams& params) {
+ return capture_format_.width_in_pixels() == params.width_in_pixels() &&
+ capture_format_.height_in_pixels() == params.height_in_pixels() &&
+ capture_format_.frame_rate_in_frames_per_second() ==
+ params.frame_rate_in_frames_per_second();
+}
+
+VideoStreamParams ReceiverImpl::GetCaptureFormat() {
+ return capture_format_;
+}
+
+int ReceiverImpl::GetFrameHandlerCount() {
+ return frame_handler_map_.size();
+}
+
+int ReceiverImpl::AddFrameHandler(
+ VideoCaptureServiceClient::FrameHandler frame_handler) {
+ frame_handler_id_counter_++;
+ frame_handler_map_.insert(
+ std::make_pair(frame_handler_id_counter_, std::move(frame_handler)));
+ return frame_handler_id_counter_;
+}
+
+bool ReceiverImpl::RemoveFrameHandler(int frame_handler_id) {
+ std::map<int, VideoCaptureServiceClient::FrameHandler>::iterator it =
+ frame_handler_map_.find(frame_handler_id);
+ if (it == frame_handler_map_.end()) {
+ return false;
+ }
+ frame_handler_map_.erase(frame_handler_id);
+ return true;
}
video_capture::mojom::ReceiverPtr ReceiverImpl::CreateInterfacePtr() {
@@ -20,6 +58,7 @@
void ReceiverImpl::OnNewBuffer(
int32_t buffer_id, media::mojom::VideoBufferHandlePtr buffer_handle) {
+ LOG(INFO) << "On new buffer";
CHECK(buffer_handle->is_shared_memory_via_raw_file_descriptor());
std::unique_ptr<SharedMemoryProvider> shared_memory_provider =
SharedMemoryProvider::CreateFromRawFileDescriptor(
@@ -40,18 +79,20 @@
int32_t buffer_id, int32_t frame_feedback_id,
video_capture::mojom::ScopedAccessPermissionPtr permission,
media::mojom::VideoFrameInfoPtr frame_info) {
- if (frame_data_handler_ == nullptr) {
- LOG(ERROR) << "Frame handler is null.";
- return;
- }
-
SharedMemoryProvider* incoming_buffer =
incoming_buffer_id_to_buffer_map_.at(buffer_id).get();
- frame_data_handler_(
- frame_info->timestamp->microseconds,
- static_cast<const uint8_t*>(
- incoming_buffer->GetSharedMemoryForInProcessAccess()->memory()),
- incoming_buffer->GetMemorySizeInBytes());
+ // Loop through all the registered frame handlers and push a frame out.
+ std::map<int, VideoCaptureServiceClient::FrameHandler>::iterator it;
+ for (it = frame_handler_map_.begin();
+ it != frame_handler_map_.end(); it++) {
+ it->second(
+ frame_info->timestamp->microseconds,
+ static_cast<const uint8_t*>(
+ incoming_buffer->GetSharedMemoryForInProcessAccess()->memory()),
+ incoming_buffer->GetMemorySizeInBytes(),
+ capture_format_.width_in_pixels(),
+ capture_format_.height_in_pixels());
+ }
}
void ReceiverImpl::OnFrameDropped(
diff --git a/media_perception/receiver_impl.h b/media_perception/receiver_impl.h
index 690061e..7de7e87 100644
--- a/media_perception/receiver_impl.h
+++ b/media_perception/receiver_impl.h
@@ -12,6 +12,7 @@
#include <string>
#include "base/logging.h"
+#include "media_perception/device_management.pb.h"
#include "media_perception/shared_memory_provider.h"
#include "media_perception/video_capture_service_client.h"
#include "mojom/device_factory.mojom.h"
@@ -20,15 +21,32 @@
class ReceiverImpl : public video_capture::mojom::Receiver {
public:
- using FrameDataHandler = std::function<void(
- uint64_t timestamp_in_microseconds, const uint8_t* data, int data_size)>;
- ReceiverImpl() : binding_(this) {}
+ ReceiverImpl() :
+ frame_handler_id_counter_(0),
+ binding_(this) {}
+
+ bool HasValidCaptureFormat();
+
+ void SetCaptureFormat(const VideoStreamParams& params);
+
+ VideoStreamParams GetCaptureFormat();
+
+ // Checks if the frame dimensions match the current dimensions.
+ bool CaptureFormatsMatch(const VideoStreamParams& params);
// Creates a local proxy of the ReceiverPtr interface.
video_capture::mojom::ReceiverPtr CreateInterfacePtr();
- // Sets the handler that will be called when new frames come from the device.
- void SetFrameHandler(FrameDataHandler frame_data_handler);
+ // Returns the count of active frame handlers on this receiver.
+ int GetFrameHandlerCount();
+
+ // Add a handler that will be called when new frames come from the associated
+ // device. Return value is an id for this frame handler.
+ int AddFrameHandler(VideoCaptureServiceClient::FrameHandler frame_handler);
+
+ // Removes a frame handler on this device with this id. Return value indicates
+ // if the removal was successful.
+ bool RemoveFrameHandler(int frame_handler_id);
// video_capture::mojom::Receiver overrides.
void OnNewBuffer(int32_t buffer_id,
@@ -46,12 +64,18 @@
void OnStartedUsingGpuDecode() override;
private:
- // Frame handler for forwarding frames to the client.
- FrameDataHandler frame_data_handler_;
+ // Incremented to create unique frame handler ids.
+ int frame_handler_id_counter_;
+
+ // Frame handler map for forwarding frames to one or more clients.
+ std::map<int, VideoCaptureServiceClient::FrameHandler> frame_handler_map_;
// Binding of the Recevier interface to message pipe.
mojo::Binding<video_capture::mojom::Receiver> binding_;
+ // Stores the capture format requested from the open device.
+ VideoStreamParams capture_format_;
+
std::map<int32_t /*buffer_id*/, std::unique_ptr<SharedMemoryProvider>>
incoming_buffer_id_to_buffer_map_;
};
diff --git a/media_perception/video_capture_service_client.h b/media_perception/video_capture_service_client.h
index 55c891d..870f03d 100644
--- a/media_perception/video_capture_service_client.h
+++ b/media_perception/video_capture_service_client.h
@@ -14,14 +14,15 @@
#include <utility>
#include <vector>
+
+namespace mri {
+
// Typdefs for readability. Serialized protos are passed back and forth across
// the boundary between platform2 code and librtanalytics.so
using SerializedVideoStreamParams = std::vector<uint8_t>;
using SerializedVideoDevice = std::vector<uint8_t>;
using RawPixelFormat = uint32_t;
-namespace mri {
-
enum DeviceAccessResultCode {
RESULT_UNKNOWN,
NOT_INITIALIZED,
@@ -30,12 +31,14 @@
};
// Provides the interface definition for the rtanalytics library to interact
-// with the Chrome Video Capture Service.
+// with the Chrome Video Capture Service. Note that the
+// VideoCaptureServiceClient is thread-safe and can be shared between multiple
+// clients.
class VideoCaptureServiceClient {
public:
using GetDevicesCallback = std::function<void(
std::vector<SerializedVideoDevice>)>;
- using SetActiveDeviceCallback = std::function<void(DeviceAccessResultCode)>;
+ using OpenDeviceCallback = std::function<void(DeviceAccessResultCode)>;
using VirtualDeviceCallback = std::function<void(SerializedVideoDevice)>;
using FrameHandler =
std::function<void(uint64_t timestamp_us, const uint8_t* data,
@@ -52,15 +55,34 @@
// Gets a list of video devices available.
virtual void GetDevices(const GetDevicesCallback& callback) = 0;
- // Sets the active device to be opened by the Video Capture Service.
- // Return value indicates success or failure of setting the active device.
- virtual void SetActiveDevice(const std::string& device_id,
- const SetActiveDeviceCallback& callback) = 0;
+ // Sets a device to be opened by the Video Capture Service with the exact
+ // device_id specified. OpenDeviceCallback provides information on the success
+ // or failure of the request.
+ virtual void OpenDevice(const std::string& device_id,
+ const OpenDeviceCallback& callback) = 0;
- // Starts video capture on the active device. Frames will be forwarded to
- // the frame handler.
- virtual void StartVideoCapture(
- const SerializedVideoStreamParams& capture_format) = 0;
+ // Determines if a particular device has already started capture and if it
+ // has, fills in the |capture_format| with the current parameters used to
+ // read frames from the device.
+ virtual bool IsVideoCaptureStartedForDevice(
+ const std::string& device_id,
+ SerializedVideoStreamParams* capture_format) = 0;
+
+ // Add a frame handler for a particular device id. Return value is the handler
+ // id. Note that multiple clients can add a frame handler for a single device.
+ // AddFrameHandler will start video capture on a device if it is not already
+ // started. An return value of 0 indicates a failure to add the handler or
+ // start video capture.
+ virtual int AddFrameHandler(
+ const std::string& device_id,
+ const SerializedVideoStreamParams& capture_format,
+ FrameHandler handler) = 0;
+
+ // Remove a frame handler for a particular device by specifying the frame
+ // handler id. Video capture on a particular device will only stop when all
+ // frame handlers are removed for a particular device.
+ virtual bool RemoveFrameHandler(
+ const std::string& device_id, int frame_handler_id) = 0;
// Interface for creating a virtual device with a set of parameters.
virtual void CreateVirtualDevice(
@@ -77,19 +99,6 @@
// Closes the specified virtual device.
virtual void CloseVirtualDevice(const std::string& device_id) = 0;
-
- // Stops video capture from the active device.
- virtual void StopVideoCapture() = 0;
-
- // Set the frame handler. Made virtual to support testing/mocking, clients are
- // not expected to override this function.
- virtual void SetFrameHandler(FrameHandler handler) {
- frame_handler_ = std::move(handler);
- }
-
- protected:
- // Handler for processing input frames.
- FrameHandler frame_handler_;
};
} // namespace mri
diff --git a/media_perception/video_capture_service_client_impl.cc b/media_perception/video_capture_service_client_impl.cc
index 7b0a4fb..2672afc 100644
--- a/media_perception/video_capture_service_client_impl.cc
+++ b/media_perception/video_capture_service_client_impl.cc
@@ -8,6 +8,7 @@
#include <base/single_thread_task_runner.h>
#include "media_perception/device_management.pb.h"
+#include "media_perception/proto_mojom_conversion.h"
namespace mri {
@@ -37,42 +38,89 @@
mojo_connector_->GetDevices(callback);
}
-void VideoCaptureServiceClientImpl::SetActiveDevice(
- const std::string& device_id, const SetActiveDeviceCallback& callback) {
- mojo_connector_->SetActiveDevice(device_id, callback);
+void VideoCaptureServiceClientImpl::OpenDevice(
+ const std::string& device_id, const OpenDeviceCallback& callback) {
+ mojo_connector_->OpenDevice(device_id, callback);
}
-void VideoCaptureServiceClientImpl::StartVideoCapture(
- const SerializedVideoStreamParams& capture_format) {
+bool VideoCaptureServiceClientImpl::IsVideoCaptureStartedForDevice(
+ const std::string& device_id,
+ SerializedVideoStreamParams* capture_format) {
+ std::lock_guard<std::mutex> lock(device_id_to_receiver_map_lock_);
+ std::map<std::string, std::shared_ptr<ReceiverImpl>>::iterator it =
+ device_id_to_receiver_map_.find(device_id);
+ bool capture_started = it != device_id_to_receiver_map_.end() &&
+ it->second->HasValidCaptureFormat();
+ if (capture_started) {
+ *capture_format = SerializeVideoStreamParamsProto(
+ it->second->GetCaptureFormat());
+ }
+ return capture_started;
+}
+
+int VideoCaptureServiceClientImpl::AddFrameHandler(
+ const std::string& device_id,
+ const SerializedVideoStreamParams& capture_format,
+ FrameHandler handler) {
+ std::lock_guard<std::mutex> lock(device_id_to_receiver_map_lock_);
VideoStreamParams format;
CHECK(format.ParseFromArray(capture_format.data(), capture_format.size()))
<< "Failed to deserialize mri::VideoStreamParams proto.";
- requested_frame_width_ = format.width_in_pixels();
- requested_frame_height_ = format.height_in_pixels();
- mojo_connector_->StartVideoCapture(
- format, std::bind(&VideoCaptureServiceClientImpl::OnNewFrameData,
- this, std::placeholders::_1,
- std::placeholders::_2, std::placeholders::_3));
-}
-
-void VideoCaptureServiceClientImpl::StopVideoCapture() {
- mojo_connector_->StopVideoCapture();
-}
-
-void VideoCaptureServiceClientImpl::OnNewFrameData(
- uint64_t timestamp_in_microseconds, const uint8_t* data, int data_size) {
- if (frame_handler_ == nullptr) {
- LOG(ERROR) << "Frame handler is null but receiving frames.";
- return;
+ std::map<std::string, std::shared_ptr<ReceiverImpl>>::iterator it =
+ device_id_to_receiver_map_.find(device_id);
+ if (it != device_id_to_receiver_map_.end() &&
+ it->second->HasValidCaptureFormat()) {
+ LOG(INFO) << "Device with " << device_id << " already open.";
+ if (!it->second->CaptureFormatsMatch(format)) {
+ LOG(WARNING) << "Device " << device_id << " is already open but with "
+ << "different capture formats.";
+ return 0;
+ }
+ return it->second->AddFrameHandler(std::move(handler));
}
- frame_handler_(timestamp_in_microseconds, data, data_size,
- requested_frame_width_, requested_frame_height_);
+
+ std::shared_ptr<ReceiverImpl> receiver_impl;
+ if (it != device_id_to_receiver_map_.end()) {
+ receiver_impl = it->second;
+ } else { // Create receiver if it doesn't exist.
+ receiver_impl = std::make_shared<ReceiverImpl>();
+ }
+ receiver_impl->SetCaptureFormat(format);
+ device_id_to_receiver_map_.insert(
+ std::make_pair(device_id, receiver_impl));
+ mojo_connector_->StartVideoCapture(
+ device_id, receiver_impl, format);
+ return receiver_impl->AddFrameHandler(std::move(handler));
+}
+
+bool VideoCaptureServiceClientImpl::RemoveFrameHandler(
+ const std::string& device_id, int frame_handler_id) {
+ std::lock_guard<std::mutex> lock(device_id_to_receiver_map_lock_);
+ std::map<std::string, std::shared_ptr<ReceiverImpl>>::iterator it =
+ device_id_to_receiver_map_.find(device_id);
+
+ if (it == device_id_to_receiver_map_.end()) {
+ // Receiver does not exist. Ensure that the device is removed as well.
+ mojo_connector_->StopVideoCapture(device_id);
+ return false;
+ }
+
+ // Receiver does exist.
+ bool success = it->second->RemoveFrameHandler(frame_handler_id);
+ if (it->second->GetFrameHandlerCount() == 0) {
+ // Remove the receiver object.
+ device_id_to_receiver_map_.erase(device_id);
+ // Stop video capture on the device.
+ mojo_connector_->StopVideoCapture(device_id);
+ }
+ return success;
}
void VideoCaptureServiceClientImpl::CreateVirtualDevice(
const SerializedVideoDevice& video_device,
const VirtualDeviceCallback& callback) {
+ std::lock_guard<std::mutex> lock(device_id_to_producer_map_lock_);
VideoDevice device;
CHECK(device.ParseFromArray(video_device.data(), video_device.size()))
<< "Failed to deserialze mri::VideoDevice proto.";
@@ -80,7 +128,6 @@
auto producer_impl = std::make_shared<ProducerImpl>();
mojo_connector_->CreateVirtualDevice(device, producer_impl, callback);
- std::lock_guard<std::mutex> lock(device_id_to_producer_map_lock_);
device_id_to_producer_map_.insert(
std::make_pair(device.id(), producer_impl));
}
diff --git a/media_perception/video_capture_service_client_impl.h b/media_perception/video_capture_service_client_impl.h
index b2be5b4..7a35188 100644
--- a/media_perception/video_capture_service_client_impl.h
+++ b/media_perception/video_capture_service_client_impl.h
@@ -15,6 +15,7 @@
#include "media_perception/mojo_connector.h"
#include "media_perception/producer_impl.h"
+#include "media_perception/receiver_impl.h"
#include "mojom/media_perception_service.mojom.h"
namespace mri {
@@ -33,11 +34,17 @@
bool Connect() override;
bool IsConnected() override;
void GetDevices(const GetDevicesCallback& callback) override;
- void SetActiveDevice(const std::string& device_id,
- const SetActiveDeviceCallback& callback) override;
- void StartVideoCapture(
- const SerializedVideoStreamParams& capture_format) override;
- void StopVideoCapture() override;
+ void OpenDevice(const std::string& device_id,
+ const OpenDeviceCallback& callback) override;
+ bool IsVideoCaptureStartedForDevice(
+ const std::string& device_id,
+ SerializedVideoStreamParams* capture_format) override;
+ int AddFrameHandler(
+ const std::string& device_id,
+ const SerializedVideoStreamParams& capture_format,
+ FrameHandler handler) override;
+ bool RemoveFrameHandler(
+ const std::string& device_id, int frame_handler_id) override;
void CreateVirtualDevice(const SerializedVideoDevice& video_device,
const VirtualDeviceCallback& callback) override;
void PushFrameToVirtualDevice(const std::string& device_id,
@@ -49,11 +56,16 @@
void CloseVirtualDevice(const std::string& device_id) override;
private:
- void OnNewFrameData(uint64_t timestamp_in_microseconds, const uint8_t* data,
- int data_size);
-
MojoConnector* mojo_connector_;
+ // Stores a map of device ids to receivers for receiving frame for the correct
+ // mojo object associated with an open device.
+ std::map<std::string /*device_id*/, std::shared_ptr<ReceiverImpl>>
+ device_id_to_receiver_map_;
+
+ // Guards against concurrent changes to |device_id_to_receiver_map_|.
+ mutable std::mutex device_id_to_receiver_map_lock_;
+
// Stores a map of device ids to producers for pushing frames to the correct
// mojo object when PushFrameToVirtualDevice is called.
// ProducerImpl objects provide an interface for buffer info updates of an
@@ -62,12 +74,8 @@
device_id_to_producer_map_;
// Guards against concurrent changes to |device_id_to_producer_map_|.
+ // TODO(crbug.com/918668): Remove use of locks if possible.
mutable std::mutex device_id_to_producer_map_lock_;
-
- // Stores the most recent requested frame width and height for incoming image
- // frames from the open active device.
- int requested_frame_width_;
- int requested_frame_height_;
};
} // namespace mri