| 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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 } // anonymous namespace | 97 } // anonymous namespace |
| 98 | 98 |
| 99 // static | 99 // static |
| 100 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) { | 100 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) { |
| 101 return RegisterNativesImpl(env); | 101 return RegisterNativesImpl(env); |
| 102 } | 102 } |
| 103 | 103 |
| 104 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid( | 104 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid( |
| 105 const VideoCaptureDeviceDescriptor& device_descriptor) | 105 const VideoCaptureDeviceDescriptor& device_descriptor) |
| 106 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 106 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 107 state_(kIdle), | |
| 108 got_first_frame_(false), | |
| 109 device_descriptor_(device_descriptor), | 107 device_descriptor_(device_descriptor), |
| 110 weak_ptr_factory_(this) {} | 108 weak_ptr_factory_(this) {} |
| 111 | 109 |
| 112 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() { | 110 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() { |
| 113 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 111 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 114 StopAndDeAllocate(); | 112 StopAndDeAllocate(); |
| 115 } | 113 } |
| 116 | 114 |
| 117 bool VideoCaptureDeviceAndroid::Init() { | 115 bool VideoCaptureDeviceAndroid::Init() { |
| 118 int id; | 116 int id; |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 } | 253 } |
| 256 DoSetPhotoOptions(std::move(settings), std::move(callback)); | 254 DoSetPhotoOptions(std::move(settings), std::move(callback)); |
| 257 } | 255 } |
| 258 | 256 |
| 259 void VideoCaptureDeviceAndroid::OnFrameAvailable( | 257 void VideoCaptureDeviceAndroid::OnFrameAvailable( |
| 260 JNIEnv* env, | 258 JNIEnv* env, |
| 261 const JavaParamRef<jobject>& obj, | 259 const JavaParamRef<jobject>& obj, |
| 262 const JavaParamRef<jbyteArray>& data, | 260 const JavaParamRef<jbyteArray>& data, |
| 263 jint length, | 261 jint length, |
| 264 jint rotation) { | 262 jint rotation) { |
| 265 { | 263 if (!IsClientConfiguredForIncomingData()) |
| 266 base::AutoLock lock(lock_); | 264 return; |
| 267 if (state_ != kConfigured || !client_) | |
| 268 return; | |
| 269 } | |
| 270 | |
| 271 jbyte* buffer = env->GetByteArrayElements(data, NULL); | 265 jbyte* buffer = env->GetByteArrayElements(data, NULL); |
| 272 if (!buffer) { | 266 if (!buffer) { |
| 273 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: " | 267 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: " |
| 274 "failed to GetByteArrayElements"; | 268 "failed to GetByteArrayElements"; |
| 275 return; | 269 return; |
| 276 } | 270 } |
| 277 | 271 |
| 278 const base::TimeTicks current_time = base::TimeTicks::Now(); | 272 const base::TimeTicks current_time = base::TimeTicks::Now(); |
| 279 { | 273 ProcessFirstFrameAvailable(current_time); |
| 280 base::AutoLock lock(lock_); | |
| 281 if (!got_first_frame_) { | |
| 282 // Set aside one frame allowance for fluctuation. | |
| 283 expected_next_frame_time_ = current_time - frame_interval_; | |
| 284 got_first_frame_ = true; | |
| 285 | |
| 286 for (const auto& request : photo_requests_queue_) | |
| 287 main_task_runner_->PostTask(FROM_HERE, request); | |
| 288 photo_requests_queue_.clear(); | |
| 289 } | |
| 290 } | |
| 291 | 274 |
| 292 // Deliver the frame when it doesn't arrive too early. | 275 // Deliver the frame when it doesn't arrive too early. |
| 293 if (expected_next_frame_time_ <= current_time) { | 276 if (expected_next_frame_time_ <= current_time) { |
| 294 // Using |expected_next_frame_time_| to estimate a proper capture timestamp | 277 // Using |expected_next_frame_time_| to estimate a proper capture timestamp |
| 295 // since android.hardware.Camera API doesn't expose a better timestamp. | 278 // since android.hardware.Camera API doesn't expose a better timestamp. |
| 296 const base::TimeDelta capture_time = | 279 const base::TimeDelta capture_time = |
| 297 expected_next_frame_time_ - base::TimeTicks(); | 280 expected_next_frame_time_ - base::TimeTicks(); |
| 298 | 281 |
| 299 expected_next_frame_time_ += frame_interval_; | 282 expected_next_frame_time_ += frame_interval_; |
| 300 | 283 |
| 301 // TODO(qiangchen): Investigate how to get raw timestamp for Android, | 284 // TODO(qiangchen): Investigate how to get raw timestamp for Android, |
| 302 // rather than using reference time to calculate timestamp. | 285 // rather than using reference time to calculate timestamp. |
| 303 base::AutoLock lock(lock_); | 286 SendIncomingDataToClient(reinterpret_cast<uint8_t*>(buffer), length, |
| 304 if (!client_) | 287 rotation, current_time, capture_time); |
| 305 return; | |
| 306 client_->OnIncomingCapturedData(reinterpret_cast<uint8_t*>(buffer), length, | |
| 307 capture_format_, rotation, current_time, | |
| 308 capture_time); | |
| 309 } | 288 } |
| 310 | 289 |
| 311 env->ReleaseByteArrayElements(data, buffer, JNI_ABORT); | 290 env->ReleaseByteArrayElements(data, buffer, JNI_ABORT); |
| 312 } | 291 } |
| 313 | 292 |
| 314 void VideoCaptureDeviceAndroid::OnI420FrameAvailable(JNIEnv* env, | 293 void VideoCaptureDeviceAndroid::OnI420FrameAvailable(JNIEnv* env, |
| 315 jobject obj, | 294 jobject obj, |
| 316 jobject y_buffer, | 295 jobject y_buffer, |
| 317 jint y_stride, | 296 jint y_stride, |
| 318 jobject u_buffer, | 297 jobject u_buffer, |
| 319 jobject v_buffer, | 298 jobject v_buffer, |
| 320 jint uv_row_stride, | 299 jint uv_row_stride, |
| 321 jint uv_pixel_stride, | 300 jint uv_pixel_stride, |
| 322 jint width, | 301 jint width, |
| 323 jint height, | 302 jint height, |
| 324 jint rotation, | 303 jint rotation, |
| 325 jlong timestamp) { | 304 jlong timestamp) { |
| 326 { | 305 if (!IsClientConfiguredForIncomingData()) |
| 327 base::AutoLock lock(lock_); | 306 return; |
| 328 if (state_ != kConfigured || !client_) | |
| 329 return; | |
| 330 } | |
| 331 const int64_t absolute_micro = | 307 const int64_t absolute_micro = |
| 332 timestamp / base::Time::kNanosecondsPerMicrosecond; | 308 timestamp / base::Time::kNanosecondsPerMicrosecond; |
| 333 const base::TimeDelta capture_time = | 309 const base::TimeDelta capture_time = |
| 334 base::TimeDelta::FromMicroseconds(absolute_micro); | 310 base::TimeDelta::FromMicroseconds(absolute_micro); |
| 335 | 311 |
| 336 const base::TimeTicks current_time = base::TimeTicks::Now(); | 312 const base::TimeTicks current_time = base::TimeTicks::Now(); |
| 337 { | 313 ProcessFirstFrameAvailable(current_time); |
| 338 base::AutoLock lock(lock_); | |
| 339 if (!got_first_frame_) { | |
| 340 // Set aside one frame allowance for fluctuation. | |
| 341 expected_next_frame_time_ = current_time - frame_interval_; | |
| 342 got_first_frame_ = true; | |
| 343 | |
| 344 for (const auto& request : photo_requests_queue_) | |
| 345 main_task_runner_->PostTask(FROM_HERE, request); | |
| 346 photo_requests_queue_.clear(); | |
| 347 } | |
| 348 } | |
| 349 | 314 |
| 350 uint8_t* const y_src = | 315 uint8_t* const y_src = |
| 351 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(y_buffer)); | 316 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(y_buffer)); |
| 352 CHECK(y_src); | 317 CHECK(y_src); |
| 353 uint8_t* const u_src = | 318 uint8_t* const u_src = |
| 354 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(u_buffer)); | 319 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(u_buffer)); |
| 355 CHECK(u_src); | 320 CHECK(u_src); |
| 356 uint8_t* const v_src = | 321 uint8_t* const v_src = |
| 357 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(v_buffer)); | 322 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(v_buffer)); |
| 358 CHECK(v_src); | 323 CHECK(v_src); |
| 359 | 324 |
| 360 const int y_plane_length = width * height; | 325 const int y_plane_length = width * height; |
| 361 const int uv_plane_length = y_plane_length / 4; | 326 const int uv_plane_length = y_plane_length / 4; |
| 362 const int buffer_length = y_plane_length + uv_plane_length * 2; | 327 const int buffer_length = y_plane_length + uv_plane_length * 2; |
| 363 std::unique_ptr<uint8_t> buffer(new uint8_t[buffer_length]); | 328 std::unique_ptr<uint8_t> buffer(new uint8_t[buffer_length]); |
| 364 | 329 |
| 365 libyuv::Android420ToI420(y_src, y_stride, u_src, uv_row_stride, v_src, | 330 libyuv::Android420ToI420(y_src, y_stride, u_src, uv_row_stride, v_src, |
| 366 uv_row_stride, uv_pixel_stride, buffer.get(), width, | 331 uv_row_stride, uv_pixel_stride, buffer.get(), width, |
| 367 buffer.get() + y_plane_length, width / 2, | 332 buffer.get() + y_plane_length, width / 2, |
| 368 buffer.get() + y_plane_length + uv_plane_length, | 333 buffer.get() + y_plane_length + uv_plane_length, |
| 369 width / 2, width, height); | 334 width / 2, width, height); |
| 370 | 335 |
| 371 // Deliver the frame when it doesn't arrive too early. | 336 // Deliver the frame when it doesn't arrive too early. |
| 372 if (expected_next_frame_time_ <= current_time) { | 337 if (AdvanceToNextFrameTime(current_time)) { |
| 373 expected_next_frame_time_ += frame_interval_; | 338 SendIncomingDataToClient(buffer.get(), buffer_length, rotation, |
| 374 | 339 current_time, capture_time); |
| 375 // TODO(qiangchen): Investigate how to get raw timestamp for Android, | |
| 376 // rather than using reference time to calculate timestamp. | |
| 377 base::AutoLock lock(lock_); | |
| 378 if (!client_) | |
| 379 return; | |
| 380 client_->OnIncomingCapturedData(buffer.get(), buffer_length, | |
| 381 capture_format_, rotation, current_time, | |
| 382 capture_time); | |
| 383 } | 340 } |
| 384 } | 341 } |
| 385 | 342 |
| 386 void VideoCaptureDeviceAndroid::OnError(JNIEnv* env, | 343 void VideoCaptureDeviceAndroid::OnError(JNIEnv* env, |
| 387 const JavaParamRef<jobject>& obj, | 344 const JavaParamRef<jobject>& obj, |
| 388 const JavaParamRef<jstring>& message) { | 345 const JavaParamRef<jstring>& message) { |
| 389 SetErrorState(FROM_HERE, | 346 SetErrorState(FROM_HERE, |
| 390 base::android::ConvertJavaStringToUTF8(env, message)); | 347 base::android::ConvertJavaStringToUTF8(env, message)); |
| 391 } | 348 } |
| 392 | 349 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 423 void VideoCaptureDeviceAndroid::OnStarted(JNIEnv* env, | 380 void VideoCaptureDeviceAndroid::OnStarted(JNIEnv* env, |
| 424 const JavaParamRef<jobject>& obj) { | 381 const JavaParamRef<jobject>& obj) { |
| 425 if (client_) | 382 if (client_) |
| 426 client_->OnStarted(); | 383 client_->OnStarted(); |
| 427 } | 384 } |
| 428 | 385 |
| 429 void VideoCaptureDeviceAndroid::ConfigureForTesting() { | 386 void VideoCaptureDeviceAndroid::ConfigureForTesting() { |
| 430 Java_VideoCapture_setTestMode(AttachCurrentThread(), j_capture_); | 387 Java_VideoCapture_setTestMode(AttachCurrentThread(), j_capture_); |
| 431 } | 388 } |
| 432 | 389 |
| 390 void VideoCaptureDeviceAndroid::ProcessFirstFrameAvailable( |
| 391 base::TimeTicks current_time) { |
| 392 base::AutoLock lock(lock_); |
| 393 if (got_first_frame_) |
| 394 return; |
| 395 // Set aside one frame allowance for fluctuation. |
| 396 expected_next_frame_time_ = current_time - frame_interval_; |
| 397 got_first_frame_ = true; |
| 398 |
| 399 for (const auto& request : photo_requests_queue_) |
| 400 main_task_runner_->PostTask(FROM_HERE, request); |
| 401 photo_requests_queue_.clear(); |
| 402 } |
| 403 |
| 404 bool VideoCaptureDeviceAndroid::IsClientConfiguredForIncomingData() { |
| 405 base::AutoLock lock(lock_); |
| 406 return (state_ == kConfigured && client_); |
| 407 } |
| 408 |
| 409 bool VideoCaptureDeviceAndroid::AdvanceToNextFrameTime( |
| 410 base::TimeTicks current_time) { |
| 411 if (expected_next_frame_time_ > current_time) |
| 412 return false; |
| 413 expected_next_frame_time_ += frame_interval_; |
| 414 return true; |
| 415 } |
| 416 |
| 417 void VideoCaptureDeviceAndroid::SendIncomingDataToClient( |
| 418 const uint8_t* data, |
| 419 int length, |
| 420 int rotation, |
| 421 base::TimeTicks reference_time, |
| 422 base::TimeDelta timestamp) { |
| 423 base::AutoLock lock(lock_); |
| 424 if (!client_) |
| 425 return; |
| 426 client_->OnIncomingCapturedData(data, length, capture_format_, rotation, |
| 427 reference_time, timestamp); |
| 428 } |
| 429 |
| 433 VideoPixelFormat VideoCaptureDeviceAndroid::GetColorspace() { | 430 VideoPixelFormat VideoCaptureDeviceAndroid::GetColorspace() { |
| 434 JNIEnv* env = AttachCurrentThread(); | 431 JNIEnv* env = AttachCurrentThread(); |
| 435 const int current_capture_colorspace = | 432 const int current_capture_colorspace = |
| 436 Java_VideoCapture_getColorspace(env, j_capture_); | 433 Java_VideoCapture_getColorspace(env, j_capture_); |
| 437 switch (current_capture_colorspace) { | 434 switch (current_capture_colorspace) { |
| 438 case ANDROID_IMAGE_FORMAT_YV12: | 435 case ANDROID_IMAGE_FORMAT_YV12: |
| 439 return media::PIXEL_FORMAT_YV12; | 436 return media::PIXEL_FORMAT_YV12; |
| 440 case ANDROID_IMAGE_FORMAT_YUV_420_888: | 437 case ANDROID_IMAGE_FORMAT_YUV_420_888: |
| 441 return media::PIXEL_FORMAT_I420; | 438 return media::PIXEL_FORMAT_I420; |
| 442 case ANDROID_IMAGE_FORMAT_NV21: | 439 case ANDROID_IMAGE_FORMAT_NV21: |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 settings->has_exposure_compensation, exposure_compensation, | 641 settings->has_exposure_compensation, exposure_compensation, |
| 645 static_cast<int>(white_balance_mode), iso, | 642 static_cast<int>(white_balance_mode), iso, |
| 646 settings->has_red_eye_reduction, settings->red_eye_reduction, | 643 settings->has_red_eye_reduction, settings->red_eye_reduction, |
| 647 static_cast<int>(fill_light_mode), settings->has_torch, settings->torch, | 644 static_cast<int>(fill_light_mode), settings->has_torch, settings->torch, |
| 648 color_temperature); | 645 color_temperature); |
| 649 | 646 |
| 650 callback.Run(true); | 647 callback.Run(true); |
| 651 } | 648 } |
| 652 | 649 |
| 653 } // namespace media | 650 } // namespace media |
| OLD | NEW |