1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "media/capture/video/chromeos/camera_app_device_impl.h"
6 
7 #include "media/capture/video/chromeos/camera_metadata_utils.h"
8 
9 namespace media {
10 
11 namespace {
12 
OnStillCaptureDone(media::mojom::ImageCapture::TakePhotoCallback callback,int status,mojom::BlobPtr blob)13 void OnStillCaptureDone(media::mojom::ImageCapture::TakePhotoCallback callback,
14                         int status,
15                         mojom::BlobPtr blob) {
16   DCHECK_EQ(status, kReprocessSuccess);
17   std::move(callback).Run(std::move(blob));
18 }
19 
20 }  // namespace
21 
22 ReprocessTask::ReprocessTask() = default;
23 
ReprocessTask(ReprocessTask && other)24 ReprocessTask::ReprocessTask(ReprocessTask&& other)
25     : effect(other.effect),
26       callback(std::move(other.callback)),
27       extra_metadata(std::move(other.extra_metadata)) {}
28 
29 ReprocessTask::~ReprocessTask() = default;
30 
31 // static
GetReprocessReturnCode(cros::mojom::Effect effect,const cros::mojom::CameraMetadataPtr * metadata)32 int CameraAppDeviceImpl::GetReprocessReturnCode(
33     cros::mojom::Effect effect,
34     const cros::mojom::CameraMetadataPtr* metadata) {
35   if (effect == cros::mojom::Effect::PORTRAIT_MODE) {
36     auto portrait_mode_segmentation_result = GetMetadataEntryAsSpan<uint8_t>(
37         *metadata, static_cast<cros::mojom::CameraMetadataTag>(
38                        kPortraitModeSegmentationResultVendorKey));
39     DCHECK(!portrait_mode_segmentation_result.empty());
40     return static_cast<int>(portrait_mode_segmentation_result[0]);
41   }
42   return kReprocessSuccess;
43 }
44 
45 // static
GetSingleShotReprocessOptions(media::mojom::ImageCapture::TakePhotoCallback take_photo_callback)46 ReprocessTaskQueue CameraAppDeviceImpl::GetSingleShotReprocessOptions(
47     media::mojom::ImageCapture::TakePhotoCallback take_photo_callback) {
48   ReprocessTaskQueue result_task_queue;
49   ReprocessTask still_capture_task;
50   still_capture_task.effect = cros::mojom::Effect::NO_EFFECT;
51   still_capture_task.callback =
52       base::BindOnce(&OnStillCaptureDone, std::move(take_photo_callback));
53   // Explicitly disable edge enhancement and noise reduction for YUV -> JPG
54   // conversion.
55   DisableEeNr(&still_capture_task);
56   result_task_queue.push(std::move(still_capture_task));
57   return result_task_queue;
58 }
59 
CameraAppDeviceImpl(const std::string & device_id,cros::mojom::CameraInfoPtr camera_info)60 CameraAppDeviceImpl::CameraAppDeviceImpl(const std::string& device_id,
61                                          cros::mojom::CameraInfoPtr camera_info)
62     : device_id_(device_id),
63       camera_info_(std::move(camera_info)),
64       task_runner_(base::ThreadTaskRunnerHandle::Get()),
65       capture_intent_(cros::mojom::CaptureIntent::DEFAULT),
66       next_metadata_observer_id_(0),
67       next_camera_event_observer_id_(0),
68       weak_ptr_factory_(
69           std::make_unique<base::WeakPtrFactory<CameraAppDeviceImpl>>(this)) {}
70 
~CameraAppDeviceImpl()71 CameraAppDeviceImpl::~CameraAppDeviceImpl() {
72   task_runner_->DeleteSoon(FROM_HERE, std::move(weak_ptr_factory_));
73 }
74 
BindReceiver(mojo::PendingReceiver<cros::mojom::CameraAppDevice> receiver)75 void CameraAppDeviceImpl::BindReceiver(
76     mojo::PendingReceiver<cros::mojom::CameraAppDevice> receiver) {
77   receivers_.Add(this, std::move(receiver));
78 }
79 
ConsumeReprocessOptions(media::mojom::ImageCapture::TakePhotoCallback take_photo_callback,base::OnceCallback<void (ReprocessTaskQueue)> consumption_callback)80 void CameraAppDeviceImpl::ConsumeReprocessOptions(
81     media::mojom::ImageCapture::TakePhotoCallback take_photo_callback,
82     base::OnceCallback<void(ReprocessTaskQueue)> consumption_callback) {
83   ReprocessTaskQueue result_task_queue;
84 
85   ReprocessTask still_capture_task;
86   still_capture_task.effect = cros::mojom::Effect::NO_EFFECT;
87   still_capture_task.callback =
88       base::BindOnce(&OnStillCaptureDone, std::move(take_photo_callback));
89   // Explicitly disable edge enhancement and noise reduction for YUV -> JPG
90   // conversion.
91   DisableEeNr(&still_capture_task);
92   result_task_queue.push(std::move(still_capture_task));
93 
94   base::AutoLock lock(reprocess_tasks_lock_);
95 
96   while (!reprocess_task_queue_.empty()) {
97     result_task_queue.push(std::move(reprocess_task_queue_.front()));
98     reprocess_task_queue_.pop();
99   }
100   std::move(consumption_callback).Run(std::move(result_task_queue));
101 }
102 
GetFpsRange()103 base::Optional<gfx::Range> CameraAppDeviceImpl::GetFpsRange() {
104   base::AutoLock lock(fps_ranges_lock_);
105 
106   return specified_fps_range_;
107 }
108 
GetStillCaptureResolution()109 gfx::Size CameraAppDeviceImpl::GetStillCaptureResolution() {
110   base::AutoLock lock(still_capture_resolution_lock_);
111 
112   return still_capture_resolution_;
113 }
114 
GetCaptureIntent()115 cros::mojom::CaptureIntent CameraAppDeviceImpl::GetCaptureIntent() {
116   base::AutoLock lock(capture_intent_lock_);
117   return capture_intent_;
118 }
119 
OnResultMetadataAvailable(const cros::mojom::CameraMetadataPtr & metadata,cros::mojom::StreamType streamType)120 void CameraAppDeviceImpl::OnResultMetadataAvailable(
121     const cros::mojom::CameraMetadataPtr& metadata,
122     cros::mojom::StreamType streamType) {
123   base::AutoLock lock(metadata_observers_lock_);
124 
125   const auto& observer_ids = stream_metadata_observer_ids_[streamType];
126 
127   for (auto& id : observer_ids) {
128     metadata_observers_[id]->OnMetadataAvailable(metadata.Clone());
129   }
130 }
131 
OnShutterDone()132 void CameraAppDeviceImpl::OnShutterDone() {
133   base::AutoLock lock(camera_event_observers_lock_);
134 
135   for (auto& observer : camera_event_observers_) {
136     observer.second->OnShutterDone();
137   }
138 }
139 
GetCameraInfo(GetCameraInfoCallback callback)140 void CameraAppDeviceImpl::GetCameraInfo(GetCameraInfoCallback callback) {
141   DCHECK(camera_info_);
142   std::move(callback).Run(camera_info_.Clone());
143 }
144 
SetReprocessOption(cros::mojom::Effect effect,SetReprocessOptionCallback reprocess_result_callback)145 void CameraAppDeviceImpl::SetReprocessOption(
146     cros::mojom::Effect effect,
147     SetReprocessOptionCallback reprocess_result_callback) {
148   ReprocessTask task;
149   task.effect = effect;
150   task.callback = base::BindOnce(&CameraAppDeviceImpl::SetReprocessResult,
151                                  weak_ptr_factory_->GetWeakPtr(),
152                                  std::move(reprocess_result_callback));
153 
154   if (effect == cros::mojom::Effect::PORTRAIT_MODE) {
155     auto e = BuildMetadataEntry(
156         static_cast<cros::mojom::CameraMetadataTag>(kPortraitModeVendorKey),
157         int32_t{1});
158     task.extra_metadata.push_back(std::move(e));
159   }
160 
161   base::AutoLock lock(reprocess_tasks_lock_);
162 
163   reprocess_task_queue_.push(std::move(task));
164 }
165 
SetFpsRange(const gfx::Range & fps_range,SetFpsRangeCallback callback)166 void CameraAppDeviceImpl::SetFpsRange(const gfx::Range& fps_range,
167                                       SetFpsRangeCallback callback) {
168   const int entry_length = 2;
169 
170   auto& static_metadata = camera_info_->static_camera_characteristics;
171   auto available_fps_range_entries = GetMetadataEntryAsSpan<int32_t>(
172       static_metadata, cros::mojom::CameraMetadataTag::
173                            ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
174   DCHECK(available_fps_range_entries.size() % entry_length == 0);
175 
176   bool is_valid = false;
177   int min_fps = static_cast<int>(fps_range.GetMin());
178   int max_fps = static_cast<int>(fps_range.GetMax());
179   for (size_t i = 0; i < available_fps_range_entries.size();
180        i += entry_length) {
181     if (available_fps_range_entries[i] == min_fps &&
182         available_fps_range_entries[i + 1] == max_fps) {
183       is_valid = true;
184       break;
185     }
186   }
187 
188   base::AutoLock lock(fps_ranges_lock_);
189 
190   if (is_valid) {
191     specified_fps_range_ = fps_range;
192   } else {
193     specified_fps_range_ = {};
194   }
195   std::move(callback).Run(is_valid);
196 }
197 
SetStillCaptureResolution(const gfx::Size & resolution,SetStillCaptureResolutionCallback callback)198 void CameraAppDeviceImpl::SetStillCaptureResolution(
199     const gfx::Size& resolution,
200     SetStillCaptureResolutionCallback callback) {
201   base::AutoLock lock(still_capture_resolution_lock_);
202   still_capture_resolution_ = resolution;
203   std::move(callback).Run();
204 }
205 
SetCaptureIntent(cros::mojom::CaptureIntent capture_intent,SetCaptureIntentCallback callback)206 void CameraAppDeviceImpl::SetCaptureIntent(
207     cros::mojom::CaptureIntent capture_intent,
208     SetCaptureIntentCallback callback) {
209   base::AutoLock lock(capture_intent_lock_);
210   capture_intent_ = capture_intent;
211   std::move(callback).Run();
212 }
213 
AddResultMetadataObserver(mojo::PendingRemote<cros::mojom::ResultMetadataObserver> observer,cros::mojom::StreamType stream_type,AddResultMetadataObserverCallback callback)214 void CameraAppDeviceImpl::AddResultMetadataObserver(
215     mojo::PendingRemote<cros::mojom::ResultMetadataObserver> observer,
216     cros::mojom::StreamType stream_type,
217     AddResultMetadataObserverCallback callback) {
218   base::AutoLock lock(metadata_observers_lock_);
219 
220   uint32_t id = next_metadata_observer_id_++;
221   metadata_observers_[id] =
222       mojo::Remote<cros::mojom::ResultMetadataObserver>(std::move(observer));
223   stream_metadata_observer_ids_[stream_type].insert(id);
224 
225   std::move(callback).Run(id);
226 }
227 
RemoveResultMetadataObserver(uint32_t id,RemoveResultMetadataObserverCallback callback)228 void CameraAppDeviceImpl::RemoveResultMetadataObserver(
229     uint32_t id,
230     RemoveResultMetadataObserverCallback callback) {
231   base::AutoLock lock(metadata_observers_lock_);
232 
233   if (metadata_observers_.erase(id) == 0) {
234     std::move(callback).Run(false);
235     return;
236   }
237 
238   for (auto& kv : stream_metadata_observer_ids_) {
239     auto& observer_ids = kv.second;
240     observer_ids.erase(id);
241   }
242   std::move(callback).Run(true);
243 }
244 
AddCameraEventObserver(mojo::PendingRemote<cros::mojom::CameraEventObserver> observer,AddCameraEventObserverCallback callback)245 void CameraAppDeviceImpl::AddCameraEventObserver(
246     mojo::PendingRemote<cros::mojom::CameraEventObserver> observer,
247     AddCameraEventObserverCallback callback) {
248   base::AutoLock lock(camera_event_observers_lock_);
249 
250   uint32_t id = next_camera_event_observer_id_++;
251   camera_event_observers_[id] =
252       mojo::Remote<cros::mojom::CameraEventObserver>(std::move(observer));
253   std::move(callback).Run(id);
254 }
255 
RemoveCameraEventObserver(uint32_t id,RemoveCameraEventObserverCallback callback)256 void CameraAppDeviceImpl::RemoveCameraEventObserver(
257     uint32_t id,
258     RemoveCameraEventObserverCallback callback) {
259   base::AutoLock lock(camera_event_observers_lock_);
260 
261   bool is_success = camera_event_observers_.erase(id) == 1;
262   std::move(callback).Run(is_success);
263 }
264 
265 // static
DisableEeNr(ReprocessTask * task)266 void CameraAppDeviceImpl::DisableEeNr(ReprocessTask* task) {
267   auto ee_entry =
268       BuildMetadataEntry(cros::mojom::CameraMetadataTag::ANDROID_EDGE_MODE,
269                          cros::mojom::AndroidEdgeMode::ANDROID_EDGE_MODE_OFF);
270   auto nr_entry = BuildMetadataEntry(
271       cros::mojom::CameraMetadataTag::ANDROID_NOISE_REDUCTION_MODE,
272       cros::mojom::AndroidNoiseReductionMode::ANDROID_NOISE_REDUCTION_MODE_OFF);
273   task->extra_metadata.push_back(std::move(ee_entry));
274   task->extra_metadata.push_back(std::move(nr_entry));
275 }
276 
SetReprocessResult(SetReprocessOptionCallback callback,const int32_t status,media::mojom::BlobPtr blob)277 void CameraAppDeviceImpl::SetReprocessResult(
278     SetReprocessOptionCallback callback,
279     const int32_t status,
280     media::mojom::BlobPtr blob) {
281   auto callback_on_mojo_thread = base::BindOnce(
282       [](const int32_t status, media::mojom::BlobPtr blob,
283          SetReprocessOptionCallback callback) {
284         std::move(callback).Run(status, std::move(blob));
285       },
286       status, std::move(blob), std::move(callback));
287   task_runner_->PostTask(FROM_HERE, std::move(callback_on_mojo_thread));
288 }
289 
290 }  // namespace media
291