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/jni_string.h" 11 #include "base/android/scoped_java_ref.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/stringprintf.h" 14 #include "jni/VideoCapture_jni.h" 15 #include "media/base/video_util.h" 16 17 using base::android::AttachCurrentThread; 18 using base::android::CheckException; 19 using base::android::GetClass; 20 using base::android::MethodID; 21 using base::android::JavaRef; 22 using base::android::ScopedJavaLocalRef; 23 24 namespace { 25 26 int GetIntField(JNIEnv* env, 27 const JavaRef<jclass>& clazz, 28 const JavaRef<jobject>& instance, 29 const char* field_name) { 30 jfieldID field = GetFieldID(env, clazz, field_name, "I"); 31 jint int_value = env->GetIntField(instance.obj(), field); 32 return int_value; 33 } 34 35 } // namespace 36 37 namespace media { 38 39 // static 40 void VideoCaptureDevice::GetDeviceNames(Names* device_names) { 41 device_names->clear(); 42 43 JNIEnv* env = AttachCurrentThread(); 44 45 int num_cameras = Java_ChromiumCameraInfo_getNumberOfCameras(env); 46 DVLOG(1) << "VideoCaptureDevice::GetDeviceNames: num_cameras=" << num_cameras; 47 if (num_cameras <= 0) 48 return; 49 50 for (int camera_id = num_cameras - 1; camera_id >= 0; --camera_id) { 51 ScopedJavaLocalRef<jobject> ci = 52 Java_ChromiumCameraInfo_getAt(env, camera_id); 53 54 Name name( 55 base::android::ConvertJavaStringToUTF8( 56 Java_ChromiumCameraInfo_getDeviceName(env, ci.obj())), 57 base::StringPrintf("%d", Java_ChromiumCameraInfo_getId(env, ci.obj()))); 58 device_names->push_back(name); 59 60 DVLOG(1) << "VideoCaptureDevice::GetDeviceNames: camera device_name=" 61 << name.name() 62 << ", unique_id=" 63 << name.id() 64 << ", orientation " 65 << Java_ChromiumCameraInfo_getOrientation(env, ci.obj()); 66 } 67 } 68 69 const std::string VideoCaptureDevice::Name::GetModel() const { 70 // Android cameras are not typically USB devices, and this method is currently 71 // only used for USB model identifiers, so this implementation just indicates 72 // an unknown device model. 73 return ""; 74 } 75 76 // static 77 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { 78 return VideoCaptureDeviceAndroid::Create(device_name); 79 } 80 81 // static 82 VideoCaptureDevice* VideoCaptureDeviceAndroid::Create(const Name& device_name) { 83 scoped_ptr<VideoCaptureDeviceAndroid> ret( 84 new VideoCaptureDeviceAndroid(device_name)); 85 if (ret->Init()) 86 return ret.release(); 87 return NULL; 88 } 89 90 // static 91 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) { 92 return RegisterNativesImpl(env); 93 } 94 95 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(const Name& device_name) 96 : state_(kIdle), 97 observer_(NULL), 98 device_name_(device_name), 99 current_settings_() { 100 } 101 102 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() { 103 DeAllocate(); 104 } 105 106 bool VideoCaptureDeviceAndroid::Init() { 107 int id; 108 if (!base::StringToInt(device_name_.id(), &id)) 109 return false; 110 111 JNIEnv* env = AttachCurrentThread(); 112 113 j_capture_.Reset(Java_VideoCapture_createVideoCapture( 114 env, base::android::GetApplicationContext(), id, 115 reinterpret_cast<jint>(this))); 116 117 return true; 118 } 119 120 const VideoCaptureDevice::Name& VideoCaptureDeviceAndroid::device_name() { 121 return device_name_; 122 } 123 124 void VideoCaptureDeviceAndroid::Allocate( 125 const VideoCaptureCapability& capture_format, 126 EventHandler* observer) { 127 { 128 base::AutoLock lock(lock_); 129 if (state_ != kIdle) 130 return; 131 observer_ = observer; 132 state_ = kAllocated; 133 } 134 135 JNIEnv* env = AttachCurrentThread(); 136 137 jboolean ret = Java_VideoCapture_allocate(env, 138 j_capture_.obj(), 139 capture_format.width, 140 capture_format.height, 141 capture_format.frame_rate); 142 if (!ret) { 143 SetErrorState("failed to allocate"); 144 return; 145 } 146 147 // Store current width and height. 148 current_settings_.width = 149 Java_VideoCapture_queryWidth(env, j_capture_.obj()); 150 current_settings_.height = 151 Java_VideoCapture_queryHeight(env, j_capture_.obj()); 152 current_settings_.frame_rate = 153 Java_VideoCapture_queryFrameRate(env, j_capture_.obj()); 154 current_settings_.color = VideoCaptureCapability::kYV12; 155 CHECK(current_settings_.width > 0 && !(current_settings_.width % 2)); 156 CHECK(current_settings_.height > 0 && !(current_settings_.height % 2)); 157 158 DVLOG(1) << "VideoCaptureDeviceAndroid::Allocate: queried width=" 159 << current_settings_.width 160 << ", height=" 161 << current_settings_.height 162 << ", frame_rate=" 163 << current_settings_.frame_rate; 164 // Report the frame size to the observer. 165 observer_->OnFrameInfo(current_settings_); 166 } 167 168 void VideoCaptureDeviceAndroid::Start() { 169 DVLOG(1) << "VideoCaptureDeviceAndroid::Start"; 170 { 171 base::AutoLock lock(lock_); 172 DCHECK_EQ(state_, kAllocated); 173 } 174 175 JNIEnv* env = AttachCurrentThread(); 176 177 jint ret = Java_VideoCapture_startCapture(env, j_capture_.obj()); 178 if (ret < 0) { 179 SetErrorState("failed to start capture"); 180 return; 181 } 182 183 { 184 base::AutoLock lock(lock_); 185 state_ = kCapturing; 186 } 187 } 188 189 void VideoCaptureDeviceAndroid::Stop() { 190 DVLOG(1) << "VideoCaptureDeviceAndroid::Stop"; 191 { 192 base::AutoLock lock(lock_); 193 if (state_ != kCapturing && state_ != kError) 194 return; 195 if (state_ == kCapturing) 196 state_ = kAllocated; 197 } 198 199 JNIEnv* env = AttachCurrentThread(); 200 201 jint ret = Java_VideoCapture_stopCapture(env, j_capture_.obj()); 202 if (ret < 0) { 203 SetErrorState("failed to stop capture"); 204 return; 205 } 206 } 207 208 void VideoCaptureDeviceAndroid::DeAllocate() { 209 DVLOG(1) << "VideoCaptureDeviceAndroid::DeAllocate"; 210 { 211 base::AutoLock lock(lock_); 212 if (state_ == kIdle) 213 return; 214 215 if (state_ == kCapturing) { 216 base::AutoUnlock unlock(lock_); 217 Stop(); 218 } 219 220 if (state_ == kAllocated) 221 state_ = kIdle; 222 223 observer_ = NULL; 224 } 225 226 JNIEnv* env = AttachCurrentThread(); 227 228 Java_VideoCapture_deallocate(env, j_capture_.obj()); 229 } 230 231 void VideoCaptureDeviceAndroid::OnFrameAvailable( 232 JNIEnv* env, 233 jobject obj, 234 jbyteArray data, 235 jint length, 236 jint rotation, 237 jboolean flip_vert, 238 jboolean flip_horiz) { 239 DVLOG(3) << "VideoCaptureDeviceAndroid::OnFrameAvailable: length =" << length; 240 241 base::AutoLock lock(lock_); 242 if (state_ != kCapturing || !observer_) 243 return; 244 245 jbyte* buffer = env->GetByteArrayElements(data, NULL); 246 if (!buffer) { 247 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: " 248 "failed to GetByteArrayElements"; 249 return; 250 } 251 252 observer_->OnIncomingCapturedFrame( 253 reinterpret_cast<uint8*>(buffer), length, base::Time::Now(), 254 rotation, flip_vert, flip_horiz); 255 256 env->ReleaseByteArrayElements(data, buffer, JNI_ABORT); 257 } 258 259 void VideoCaptureDeviceAndroid::SetErrorState(const std::string& reason) { 260 LOG(ERROR) << "VideoCaptureDeviceAndroid::SetErrorState: " << reason; 261 { 262 base::AutoLock lock(lock_); 263 state_ = kError; 264 } 265 observer_->OnError(); 266 } 267 268 } // namespace media 269