Home | History | Annotate | Download | only in android
      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