OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/capture/video/android/video_capture_device_android.h" | 5 #include "media/capture/video/android/video_capture_device_android.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/android/jni_android.h" | 10 #include "base/android/jni_android.h" |
(...skipping 25 matching lines...) Expand all Loading... |
36 // only used for USB model identifiers, so this implementation just indicates | 36 // only used for USB model identifiers, so this implementation just indicates |
37 // an unknown device model. | 37 // an unknown device model. |
38 return ""; | 38 return ""; |
39 } | 39 } |
40 | 40 |
41 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(const Name& device_name) | 41 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(const Name& device_name) |
42 : state_(kIdle), got_first_frame_(false), device_name_(device_name) { | 42 : state_(kIdle), got_first_frame_(false), device_name_(device_name) { |
43 } | 43 } |
44 | 44 |
45 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() { | 45 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() { |
| 46 DCHECK(thread_checker_.CalledOnValidThread()); |
46 StopAndDeAllocate(); | 47 StopAndDeAllocate(); |
47 } | 48 } |
48 | 49 |
49 bool VideoCaptureDeviceAndroid::Init() { | 50 bool VideoCaptureDeviceAndroid::Init() { |
50 int id; | 51 int id; |
51 if (!base::StringToInt(device_name_.id(), &id)) | 52 if (!base::StringToInt(device_name_.id(), &id)) |
52 return false; | 53 return false; |
53 | 54 |
54 j_capture_.Reset(VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid( | 55 j_capture_.Reset(VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid( |
55 id, reinterpret_cast<intptr_t>(this))); | 56 id, reinterpret_cast<intptr_t>(this))); |
56 return true; | 57 return true; |
57 } | 58 } |
58 | 59 |
59 void VideoCaptureDeviceAndroid::AllocateAndStart( | 60 void VideoCaptureDeviceAndroid::AllocateAndStart( |
60 const VideoCaptureParams& params, | 61 const VideoCaptureParams& params, |
61 std::unique_ptr<Client> client) { | 62 std::unique_ptr<Client> client) { |
62 DVLOG(1) << __FUNCTION__; | 63 DCHECK(thread_checker_.CalledOnValidThread()); |
63 { | 64 { |
64 base::AutoLock lock(lock_); | 65 base::AutoLock lock(lock_); |
65 if (state_ != kIdle) | 66 if (state_ != kIdle) |
66 return; | 67 return; |
67 client_ = std::move(client); | 68 client_ = std::move(client); |
68 got_first_frame_ = false; | 69 got_first_frame_ = false; |
69 } | 70 } |
70 | 71 |
71 JNIEnv* env = AttachCurrentThread(); | 72 JNIEnv* env = AttachCurrentThread(); |
72 | 73 |
73 jboolean ret = Java_VideoCapture_allocate( | 74 jboolean ret = Java_VideoCapture_allocate( |
74 env, j_capture_.obj(), params.requested_format.frame_size.width(), | 75 env, j_capture_.obj(), params.requested_format.frame_size.width(), |
75 params.requested_format.frame_size.height(), | 76 params.requested_format.frame_size.height(), |
76 params.requested_format.frame_rate); | 77 params.requested_format.frame_rate); |
77 if (!ret) { | 78 if (!ret) { |
78 SetErrorState(FROM_HERE, "failed to allocate"); | 79 SetErrorState(FROM_HERE, "failed to allocate"); |
79 return; | 80 return; |
80 } | 81 } |
81 | 82 |
82 // Store current width and height. | |
83 capture_format_.frame_size.SetSize( | 83 capture_format_.frame_size.SetSize( |
84 Java_VideoCapture_queryWidth(env, j_capture_.obj()), | 84 Java_VideoCapture_queryWidth(env, j_capture_.obj()), |
85 Java_VideoCapture_queryHeight(env, j_capture_.obj())); | 85 Java_VideoCapture_queryHeight(env, j_capture_.obj())); |
86 capture_format_.frame_rate = | 86 capture_format_.frame_rate = |
87 Java_VideoCapture_queryFrameRate(env, j_capture_.obj()); | 87 Java_VideoCapture_queryFrameRate(env, j_capture_.obj()); |
88 capture_format_.pixel_format = GetColorspace(); | 88 capture_format_.pixel_format = GetColorspace(); |
89 DCHECK_NE(capture_format_.pixel_format, media::PIXEL_FORMAT_UNKNOWN); | 89 DCHECK_NE(capture_format_.pixel_format, media::PIXEL_FORMAT_UNKNOWN); |
90 CHECK(capture_format_.frame_size.GetArea() > 0); | 90 CHECK(capture_format_.frame_size.GetArea() > 0); |
91 CHECK(!(capture_format_.frame_size.width() % 2)); | 91 CHECK(!(capture_format_.frame_size.width() % 2)); |
92 CHECK(!(capture_format_.frame_size.height() % 2)); | 92 CHECK(!(capture_format_.frame_size.height() % 2)); |
93 | 93 |
94 if (capture_format_.frame_rate > 0) { | 94 if (capture_format_.frame_rate > 0) { |
95 frame_interval_ = base::TimeDelta::FromMicroseconds( | 95 frame_interval_ = base::TimeDelta::FromMicroseconds( |
96 (base::Time::kMicrosecondsPerSecond + capture_format_.frame_rate - 1) / | 96 (base::Time::kMicrosecondsPerSecond + capture_format_.frame_rate - 1) / |
97 capture_format_.frame_rate); | 97 capture_format_.frame_rate); |
98 } | 98 } |
99 | 99 |
100 DVLOG(1) << "VideoCaptureDeviceAndroid::Allocate: queried frame_size=" | 100 DVLOG(1) << __FUNCTION__ << " requested (" |
101 << capture_format_.frame_size.ToString() | 101 << capture_format_.frame_size.ToString() << ")@ " |
102 << ", frame_rate=" << capture_format_.frame_rate; | 102 << capture_format_.frame_rate << "fps"; |
103 | 103 |
104 ret = Java_VideoCapture_startCapture(env, j_capture_.obj()); | 104 ret = Java_VideoCapture_startCapture(env, j_capture_.obj()); |
105 if (!ret) { | 105 if (!ret) { |
106 SetErrorState(FROM_HERE, "failed to start capture"); | 106 SetErrorState(FROM_HERE, "failed to start capture"); |
107 return; | 107 return; |
108 } | 108 } |
109 | 109 |
110 { | 110 { |
111 base::AutoLock lock(lock_); | 111 base::AutoLock lock(lock_); |
112 state_ = kCapturing; | 112 state_ = kCapturing; |
113 } | 113 } |
114 } | 114 } |
115 | 115 |
116 void VideoCaptureDeviceAndroid::StopAndDeAllocate() { | 116 void VideoCaptureDeviceAndroid::StopAndDeAllocate() { |
117 DVLOG(1) << __FUNCTION__; | 117 DCHECK(thread_checker_.CalledOnValidThread()); |
118 { | 118 { |
119 base::AutoLock lock(lock_); | 119 base::AutoLock lock(lock_); |
120 if (state_ != kCapturing && state_ != kError) | 120 if (state_ != kCapturing && state_ != kError) |
121 return; | 121 return; |
122 } | 122 } |
123 | 123 |
124 JNIEnv* env = AttachCurrentThread(); | 124 JNIEnv* env = AttachCurrentThread(); |
125 | 125 |
126 jboolean ret = Java_VideoCapture_stopCapture(env, j_capture_.obj()); | 126 const jboolean ret = Java_VideoCapture_stopCapture(env, j_capture_.obj()); |
127 if (!ret) { | 127 if (!ret) { |
128 SetErrorState(FROM_HERE, "failed to stop capture"); | 128 SetErrorState(FROM_HERE, "failed to stop capture"); |
129 return; | 129 return; |
130 } | 130 } |
131 | 131 |
132 { | 132 { |
133 base::AutoLock lock(lock_); | 133 base::AutoLock lock(lock_); |
134 state_ = kIdle; | 134 state_ = kIdle; |
135 client_.reset(); | 135 client_.reset(); |
136 } | 136 } |
137 | 137 |
138 Java_VideoCapture_deallocate(env, j_capture_.obj()); | 138 Java_VideoCapture_deallocate(env, j_capture_.obj()); |
139 } | 139 } |
140 | 140 |
141 void VideoCaptureDeviceAndroid::TakePhoto(TakePhotoCallback callback) { | 141 void VideoCaptureDeviceAndroid::TakePhoto(TakePhotoCallback callback) { |
142 DVLOG(1) << __FUNCTION__; | 142 DCHECK(thread_checker_.CalledOnValidThread()); |
143 { | 143 { |
144 base::AutoLock lock(lock_); | 144 base::AutoLock lock(lock_); |
145 if (state_ != kCapturing) | 145 if (state_ != kCapturing) |
146 return; | 146 return; |
147 } | 147 } |
148 | 148 |
149 JNIEnv* env = AttachCurrentThread(); | 149 JNIEnv* env = AttachCurrentThread(); |
150 | 150 |
151 // Make copy on the heap so we can pass the pointer through JNI. | 151 // Make copy on the heap so we can pass the pointer through JNI. |
152 std::unique_ptr<TakePhotoCallback> heap_callback( | 152 std::unique_ptr<TakePhotoCallback> heap_callback( |
153 new TakePhotoCallback(std::move(callback))); | 153 new TakePhotoCallback(std::move(callback))); |
154 const intptr_t callback_id = reinterpret_cast<intptr_t>(heap_callback.get()); | 154 const intptr_t callback_id = reinterpret_cast<intptr_t>(heap_callback.get()); |
155 if (!Java_VideoCapture_takePhoto(env, j_capture_.obj(), callback_id, | 155 if (!Java_VideoCapture_takePhoto(env, j_capture_.obj(), callback_id, |
156 next_photo_resolution_.width(), | 156 next_photo_resolution_.width(), |
157 next_photo_resolution_.height())) | 157 next_photo_resolution_.height())) |
158 return; | 158 return; |
159 | 159 |
160 { | 160 { |
161 base::AutoLock lock(photo_callbacks_lock_); | 161 base::AutoLock lock(photo_callbacks_lock_); |
162 photo_callbacks_.push_back(std::move(heap_callback)); | 162 photo_callbacks_.push_back(std::move(heap_callback)); |
163 } | 163 } |
164 } | 164 } |
165 | 165 |
166 void VideoCaptureDeviceAndroid::GetPhotoCapabilities( | 166 void VideoCaptureDeviceAndroid::GetPhotoCapabilities( |
167 GetPhotoCapabilitiesCallback callback) { | 167 GetPhotoCapabilitiesCallback callback) { |
| 168 DCHECK(thread_checker_.CalledOnValidThread()); |
168 JNIEnv* env = AttachCurrentThread(); | 169 JNIEnv* env = AttachCurrentThread(); |
169 | 170 |
170 PhotoCapabilities caps( | 171 PhotoCapabilities caps( |
171 Java_VideoCapture_getPhotoCapabilities(env, j_capture_.obj())); | 172 Java_VideoCapture_getPhotoCapabilities(env, j_capture_.obj())); |
172 | 173 |
173 // TODO(mcasas): Manual member copying sucks, consider adding typemapping from | 174 // TODO(mcasas): Manual member copying sucks, consider adding typemapping from |
174 // PhotoCapabilities to mojom::PhotoCapabilitiesPtr, https://crbug.com/622002. | 175 // PhotoCapabilities to mojom::PhotoCapabilitiesPtr, https://crbug.com/622002. |
175 mojom::PhotoCapabilitiesPtr photo_capabilities = | 176 mojom::PhotoCapabilitiesPtr photo_capabilities = |
176 mojom::PhotoCapabilities::New(); | 177 mojom::PhotoCapabilities::New(); |
177 photo_capabilities->iso = mojom::Range::New(); | 178 photo_capabilities->iso = mojom::Range::New(); |
(...skipping 14 matching lines...) Expand all Loading... |
192 photo_capabilities->zoom->min = caps.getMinZoom(); | 193 photo_capabilities->zoom->min = caps.getMinZoom(); |
193 photo_capabilities->focus_mode = caps.getAutoFocusInUse() | 194 photo_capabilities->focus_mode = caps.getAutoFocusInUse() |
194 ? mojom::FocusMode::AUTO | 195 ? mojom::FocusMode::AUTO |
195 : mojom::FocusMode::MANUAL; | 196 : mojom::FocusMode::MANUAL; |
196 callback.Run(std::move(photo_capabilities)); | 197 callback.Run(std::move(photo_capabilities)); |
197 } | 198 } |
198 | 199 |
199 void VideoCaptureDeviceAndroid::SetPhotoOptions( | 200 void VideoCaptureDeviceAndroid::SetPhotoOptions( |
200 mojom::PhotoSettingsPtr settings, | 201 mojom::PhotoSettingsPtr settings, |
201 SetPhotoOptionsCallback callback) { | 202 SetPhotoOptionsCallback callback) { |
| 203 DCHECK(thread_checker_.CalledOnValidThread()); |
202 JNIEnv* env = AttachCurrentThread(); | 204 JNIEnv* env = AttachCurrentThread(); |
203 // |width| and/or |height| are kept for the next TakePhoto()s. | 205 // |width| and/or |height| are kept for the next TakePhoto()s. |
204 if (settings->has_width || settings->has_height) | 206 if (settings->has_width || settings->has_height) |
205 next_photo_resolution_.SetSize(0, 0); | 207 next_photo_resolution_.SetSize(0, 0); |
206 if (settings->has_width) { | 208 if (settings->has_width) { |
207 next_photo_resolution_.set_width( | 209 next_photo_resolution_.set_width( |
208 base::saturated_cast<int>(settings->width)); | 210 base::saturated_cast<int>(settings->width)); |
209 } | 211 } |
210 if (settings->has_height) { | 212 if (settings->has_height) { |
211 next_photo_resolution_.set_height( | 213 next_photo_resolution_.set_height( |
212 base::saturated_cast<int>(settings->height)); | 214 base::saturated_cast<int>(settings->height)); |
213 } | 215 } |
214 | 216 |
215 if (settings->has_zoom) | 217 if (settings->has_zoom) |
216 Java_VideoCapture_setZoom(env, j_capture_.obj(), settings->zoom); | 218 Java_VideoCapture_setZoom(env, j_capture_.obj(), settings->zoom); |
217 callback.Run(true); | 219 callback.Run(true); |
218 } | 220 } |
219 | 221 |
220 void VideoCaptureDeviceAndroid::OnFrameAvailable( | 222 void VideoCaptureDeviceAndroid::OnFrameAvailable( |
221 JNIEnv* env, | 223 JNIEnv* env, |
222 const JavaParamRef<jobject>& obj, | 224 const JavaParamRef<jobject>& obj, |
223 const JavaParamRef<jbyteArray>& data, | 225 const JavaParamRef<jbyteArray>& data, |
224 jint length, | 226 jint length, |
225 jint rotation) { | 227 jint rotation) { |
226 DVLOG(3) << __FUNCTION__ << " length =" << length; | 228 { |
227 | 229 base::AutoLock lock(lock_); |
228 base::AutoLock lock(lock_); | 230 if (state_ != kCapturing || !client_) |
229 if (state_ != kCapturing || !client_.get()) | 231 return; |
230 return; | 232 } |
231 | 233 |
232 jbyte* buffer = env->GetByteArrayElements(data, NULL); | 234 jbyte* buffer = env->GetByteArrayElements(data, NULL); |
233 if (!buffer) { | 235 if (!buffer) { |
234 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: " | 236 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: " |
235 "failed to GetByteArrayElements"; | 237 "failed to GetByteArrayElements"; |
236 return; | 238 return; |
237 } | 239 } |
238 | 240 |
239 const base::TimeTicks current_time = base::TimeTicks::Now(); | 241 const base::TimeTicks current_time = base::TimeTicks::Now(); |
240 if (!got_first_frame_) { | 242 if (!got_first_frame_) { |
241 // Set aside one frame allowance for fluctuation. | 243 // Set aside one frame allowance for fluctuation. |
242 expected_next_frame_time_ = current_time - frame_interval_; | 244 expected_next_frame_time_ = current_time - frame_interval_; |
243 first_ref_time_ = current_time; | 245 first_ref_time_ = current_time; |
244 got_first_frame_ = true; | 246 got_first_frame_ = true; |
245 } | 247 } |
246 | 248 |
247 // Deliver the frame when it doesn't arrive too early. | 249 // Deliver the frame when it doesn't arrive too early. |
248 if (expected_next_frame_time_ <= current_time) { | 250 if (expected_next_frame_time_ <= current_time) { |
249 expected_next_frame_time_ += frame_interval_; | 251 expected_next_frame_time_ += frame_interval_; |
250 | 252 |
251 // TODO(qiangchen): Investigate how to get raw timestamp for Android, | 253 // TODO(qiangchen): Investigate how to get raw timestamp for Android, |
252 // rather than using reference time to calculate timestamp. | 254 // rather than using reference time to calculate timestamp. |
| 255 base::AutoLock lock(lock_); |
| 256 if (!client_) |
| 257 return; |
253 client_->OnIncomingCapturedData(reinterpret_cast<uint8_t*>(buffer), length, | 258 client_->OnIncomingCapturedData(reinterpret_cast<uint8_t*>(buffer), length, |
254 capture_format_, rotation, current_time, | 259 capture_format_, rotation, current_time, |
255 current_time - first_ref_time_); | 260 current_time - first_ref_time_); |
256 } | 261 } |
257 | 262 |
258 env->ReleaseByteArrayElements(data, buffer, JNI_ABORT); | 263 env->ReleaseByteArrayElements(data, buffer, JNI_ABORT); |
259 } | 264 } |
260 | 265 |
261 void VideoCaptureDeviceAndroid::OnI420FrameAvailable(JNIEnv* env, | 266 void VideoCaptureDeviceAndroid::OnI420FrameAvailable(JNIEnv* env, |
262 jobject obj, | 267 jobject obj, |
263 jobject y_buffer, | 268 jobject y_buffer, |
264 jint y_stride, | 269 jint y_stride, |
265 jobject u_buffer, | 270 jobject u_buffer, |
266 jobject v_buffer, | 271 jobject v_buffer, |
267 jint uv_row_stride, | 272 jint uv_row_stride, |
268 jint uv_pixel_stride, | 273 jint uv_pixel_stride, |
269 jint width, | 274 jint width, |
270 jint height, | 275 jint height, |
271 jint rotation) { | 276 jint rotation) { |
| 277 { |
| 278 base::AutoLock lock(lock_); |
| 279 if (state_ != kCapturing || !client_) |
| 280 return; |
| 281 } |
| 282 |
272 const base::TimeTicks current_time = base::TimeTicks::Now(); | 283 const base::TimeTicks current_time = base::TimeTicks::Now(); |
273 if (!got_first_frame_) { | 284 if (!got_first_frame_) { |
274 // Set aside one frame allowance for fluctuation. | 285 // Set aside one frame allowance for fluctuation. |
275 expected_next_frame_time_ = current_time - frame_interval_; | 286 expected_next_frame_time_ = current_time - frame_interval_; |
276 first_ref_time_ = current_time; | 287 first_ref_time_ = current_time; |
277 got_first_frame_ = true; | 288 got_first_frame_ = true; |
278 } | 289 } |
279 | 290 |
280 uint8_t* const y_src = | 291 uint8_t* const y_src = |
281 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(y_buffer)); | 292 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(y_buffer)); |
(...skipping 15 matching lines...) Expand all Loading... |
297 buffer.get() + y_plane_length, width / 2, | 308 buffer.get() + y_plane_length, width / 2, |
298 buffer.get() + y_plane_length + uv_plane_length, | 309 buffer.get() + y_plane_length + uv_plane_length, |
299 width / 2, width, height); | 310 width / 2, width, height); |
300 | 311 |
301 // Deliver the frame when it doesn't arrive too early. | 312 // Deliver the frame when it doesn't arrive too early. |
302 if (expected_next_frame_time_ <= current_time) { | 313 if (expected_next_frame_time_ <= current_time) { |
303 expected_next_frame_time_ += frame_interval_; | 314 expected_next_frame_time_ += frame_interval_; |
304 | 315 |
305 // TODO(qiangchen): Investigate how to get raw timestamp for Android, | 316 // TODO(qiangchen): Investigate how to get raw timestamp for Android, |
306 // rather than using reference time to calculate timestamp. | 317 // rather than using reference time to calculate timestamp. |
| 318 base::AutoLock lock(lock_); |
| 319 if (!client_) |
| 320 return; |
307 client_->OnIncomingCapturedData(buffer.get(), buffer_length, | 321 client_->OnIncomingCapturedData(buffer.get(), buffer_length, |
308 capture_format_, rotation, current_time, | 322 capture_format_, rotation, current_time, |
309 current_time - first_ref_time_); | 323 current_time - first_ref_time_); |
310 } | 324 } |
311 } | 325 } |
312 | 326 |
313 void VideoCaptureDeviceAndroid::OnError(JNIEnv* env, | 327 void VideoCaptureDeviceAndroid::OnError(JNIEnv* env, |
314 const JavaParamRef<jobject>& obj, | 328 const JavaParamRef<jobject>& obj, |
315 const JavaParamRef<jstring>& message) { | 329 const JavaParamRef<jstring>& message) { |
316 SetErrorState(FROM_HERE, | 330 SetErrorState(FROM_HERE, |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 return media::PIXEL_FORMAT_UNKNOWN; | 377 return media::PIXEL_FORMAT_UNKNOWN; |
364 } | 378 } |
365 } | 379 } |
366 | 380 |
367 void VideoCaptureDeviceAndroid::SetErrorState( | 381 void VideoCaptureDeviceAndroid::SetErrorState( |
368 const tracked_objects::Location& from_here, | 382 const tracked_objects::Location& from_here, |
369 const std::string& reason) { | 383 const std::string& reason) { |
370 { | 384 { |
371 base::AutoLock lock(lock_); | 385 base::AutoLock lock(lock_); |
372 state_ = kError; | 386 state_ = kError; |
| 387 if (!client_) |
| 388 return; |
| 389 client_->OnError(from_here, reason); |
373 } | 390 } |
374 client_->OnError(from_here, reason); | |
375 } | 391 } |
376 | 392 |
377 } // namespace media | 393 } // namespace media |
OLD | NEW |