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