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 3 // found in the LICENSE file. 4 5 #include "media/video/capture/android/video_capture_device_android.h" 6 7 #include <string> 8 9 #include "base/android/jni_android.h" 10 #include "base/android/scoped_java_ref.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "jni/VideoCapture_jni.h" 13 #include "media/video/capture/android/video_capture_device_factory_android.h" 14 15 using base::android::AttachCurrentThread; 16 using base::android::CheckException; 17 using base::android::GetClass; 18 using base::android::MethodID; 19 using base::android::JavaRef; 20 using base::android::ScopedJavaLocalRef; 21 22 namespace media { 23 24 // static 25 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) { 26 return RegisterNativesImpl(env); 27 } 28 29 const std::string VideoCaptureDevice::Name::GetModel() const { 30 // Android cameras are not typically USB devices, and this method is currently 31 // only used for USB model identifiers, so this implementation just indicates 32 // an unknown device model. 33 return ""; 34 } 35 36 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(const Name& device_name) 37 : state_(kIdle), got_first_frame_(false), device_name_(device_name) {} 38 39 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() { 40 StopAndDeAllocate(); 41 } 42 43 bool VideoCaptureDeviceAndroid::Init() { 44 int id; 45 if (!base::StringToInt(device_name_.id(), &id)) 46 return false; 47 48 j_capture_.Reset(VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid( 49 id, reinterpret_cast<intptr_t>(this))); 50 return true; 51 } 52 53 void VideoCaptureDeviceAndroid::AllocateAndStart( 54 const VideoCaptureParams& params, 55 scoped_ptr<Client> client) { 56 DVLOG(1) << "VideoCaptureDeviceAndroid::AllocateAndStart"; 57 { 58 base::AutoLock lock(lock_); 59 if (state_ != kIdle) 60 return; 61 client_ = client.Pass(); 62 got_first_frame_ = false; 63 } 64 65 JNIEnv* env = AttachCurrentThread(); 66 67 jboolean ret = Java_VideoCapture_allocate( 68 env, 69 j_capture_.obj(), 70 params.requested_format.frame_size.width(), 71 params.requested_format.frame_size.height(), 72 params.requested_format.frame_rate); 73 if (!ret) { 74 SetErrorState("failed to allocate"); 75 return; 76 } 77 78 // Store current width and height. 79 capture_format_.frame_size.SetSize( 80 Java_VideoCapture_queryWidth(env, j_capture_.obj()), 81 Java_VideoCapture_queryHeight(env, j_capture_.obj())); 82 capture_format_.frame_rate = 83 Java_VideoCapture_queryFrameRate(env, j_capture_.obj()); 84 capture_format_.pixel_format = GetColorspace(); 85 DCHECK_NE(capture_format_.pixel_format, media::PIXEL_FORMAT_UNKNOWN); 86 CHECK(capture_format_.frame_size.GetArea() > 0); 87 CHECK(!(capture_format_.frame_size.width() % 2)); 88 CHECK(!(capture_format_.frame_size.height() % 2)); 89 90 if (capture_format_.frame_rate > 0) { 91 frame_interval_ = base::TimeDelta::FromMicroseconds( 92 (base::Time::kMicrosecondsPerSecond + capture_format_.frame_rate - 1) / 93 capture_format_.frame_rate); 94 } 95 96 DVLOG(1) << "VideoCaptureDeviceAndroid::Allocate: queried frame_size=" 97 << capture_format_.frame_size.ToString() 98 << ", frame_rate=" << capture_format_.frame_rate; 99 100 jint result = Java_VideoCapture_startCapture(env, j_capture_.obj()); 101 if (result < 0) { 102 SetErrorState("failed to start capture"); 103 return; 104 } 105 106 { 107 base::AutoLock lock(lock_); 108 state_ = kCapturing; 109 } 110 } 111 112 void VideoCaptureDeviceAndroid::StopAndDeAllocate() { 113 DVLOG(1) << "VideoCaptureDeviceAndroid::StopAndDeAllocate"; 114 { 115 base::AutoLock lock(lock_); 116 if (state_ != kCapturing && state_ != kError) 117 return; 118 } 119 120 JNIEnv* env = AttachCurrentThread(); 121 122 jint ret = Java_VideoCapture_stopCapture(env, j_capture_.obj()); 123 if (ret < 0) { 124 SetErrorState("failed to stop capture"); 125 return; 126 } 127 128 { 129 base::AutoLock lock(lock_); 130 state_ = kIdle; 131 client_.reset(); 132 } 133 134 Java_VideoCapture_deallocate(env, j_capture_.obj()); 135 } 136 137 void VideoCaptureDeviceAndroid::OnFrameAvailable( 138 JNIEnv* env, 139 jobject obj, 140 jbyteArray data, 141 jint length, 142 jint rotation) { 143 DVLOG(3) << "VideoCaptureDeviceAndroid::OnFrameAvailable: length =" << length; 144 145 base::AutoLock lock(lock_); 146 if (state_ != kCapturing || !client_.get()) 147 return; 148 149 jbyte* buffer = env->GetByteArrayElements(data, NULL); 150 if (!buffer) { 151 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: " 152 "failed to GetByteArrayElements"; 153 return; 154 } 155 156 base::TimeTicks current_time = base::TimeTicks::Now(); 157 if (!got_first_frame_) { 158 // Set aside one frame allowance for fluctuation. 159 expected_next_frame_time_ = current_time - frame_interval_; 160 got_first_frame_ = true; 161 } 162 163 // Deliver the frame when it doesn't arrive too early. 164 if (expected_next_frame_time_ <= current_time) { 165 expected_next_frame_time_ += frame_interval_; 166 167 client_->OnIncomingCapturedData(reinterpret_cast<uint8*>(buffer), 168 length, 169 capture_format_, 170 rotation, 171 base::TimeTicks::Now()); 172 } 173 174 env->ReleaseByteArrayElements(data, buffer, JNI_ABORT); 175 } 176 177 VideoPixelFormat VideoCaptureDeviceAndroid::GetColorspace() { 178 JNIEnv* env = AttachCurrentThread(); 179 int current_capture_colorspace = 180 Java_VideoCapture_getColorspace(env, j_capture_.obj()); 181 switch (current_capture_colorspace) { 182 case ANDROID_IMAGEFORMAT_YV12: 183 return media::PIXEL_FORMAT_YV12; 184 case ANDROID_IMAGEFORMAT_NV21: 185 return media::PIXEL_FORMAT_NV21; 186 case ANDROID_IMAGEFORMAT_UNKNOWN: 187 default: 188 return media::PIXEL_FORMAT_UNKNOWN; 189 } 190 } 191 192 void VideoCaptureDeviceAndroid::SetErrorState(const std::string& reason) { 193 LOG(ERROR) << "VideoCaptureDeviceAndroid::SetErrorState: " << reason; 194 { 195 base::AutoLock lock(lock_); 196 state_ = kError; 197 } 198 client_->OnError(reason); 199 } 200 201 } // namespace media 202