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 media {
     25 
     26 // static
     27 void VideoCaptureDevice::GetDeviceNames(Names* device_names) {
     28   device_names->clear();
     29 
     30   JNIEnv* env = AttachCurrentThread();
     31 
     32   int num_cameras = Java_ChromiumCameraInfo_getNumberOfCameras(env);
     33   DVLOG(1) << "VideoCaptureDevice::GetDeviceNames: num_cameras=" << num_cameras;
     34   if (num_cameras <= 0)
     35     return;
     36 
     37   for (int camera_id = num_cameras - 1; camera_id >= 0; --camera_id) {
     38     ScopedJavaLocalRef<jobject> ci =
     39         Java_ChromiumCameraInfo_getAt(env, camera_id);
     40 
     41     Name name(
     42         base::android::ConvertJavaStringToUTF8(
     43             Java_ChromiumCameraInfo_getDeviceName(env, ci.obj())),
     44         base::StringPrintf("%d", Java_ChromiumCameraInfo_getId(env, ci.obj())));
     45     device_names->push_back(name);
     46 
     47     DVLOG(1) << "VideoCaptureDevice::GetDeviceNames: camera device_name="
     48              << name.name()
     49              << ", unique_id="
     50              << name.id()
     51              << ", orientation "
     52              << Java_ChromiumCameraInfo_getOrientation(env, ci.obj());
     53   }
     54 }
     55 
     56 // static
     57 void VideoCaptureDevice::GetDeviceSupportedFormats(const Name& device,
     58     VideoCaptureFormats* formats) {
     59   NOTIMPLEMENTED();
     60 }
     61 
     62 const std::string VideoCaptureDevice::Name::GetModel() const {
     63   // Android cameras are not typically USB devices, and this method is currently
     64   // only used for USB model identifiers, so this implementation just indicates
     65   // an unknown device model.
     66   return "";
     67 }
     68 
     69 // static
     70 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) {
     71   return VideoCaptureDeviceAndroid::Create(device_name);
     72 }
     73 
     74 // static
     75 VideoCaptureDevice* VideoCaptureDeviceAndroid::Create(const Name& device_name) {
     76   scoped_ptr<VideoCaptureDeviceAndroid> ret(
     77       new VideoCaptureDeviceAndroid(device_name));
     78   if (ret->Init())
     79     return ret.release();
     80   return NULL;
     81 }
     82 
     83 // static
     84 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) {
     85   return RegisterNativesImpl(env);
     86 }
     87 
     88 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(const Name& device_name)
     89     : state_(kIdle), got_first_frame_(false), device_name_(device_name) {}
     90 
     91 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() {
     92   StopAndDeAllocate();
     93 }
     94 
     95 bool VideoCaptureDeviceAndroid::Init() {
     96   int id;
     97   if (!base::StringToInt(device_name_.id(), &id))
     98     return false;
     99 
    100   JNIEnv* env = AttachCurrentThread();
    101 
    102   j_capture_.Reset(Java_VideoCapture_createVideoCapture(
    103       env, base::android::GetApplicationContext(), id,
    104       reinterpret_cast<intptr_t>(this)));
    105 
    106   return true;
    107 }
    108 
    109 void VideoCaptureDeviceAndroid::AllocateAndStart(
    110     const VideoCaptureParams& params,
    111     scoped_ptr<Client> client) {
    112   DVLOG(1) << "VideoCaptureDeviceAndroid::AllocateAndStart";
    113   {
    114     base::AutoLock lock(lock_);
    115     if (state_ != kIdle)
    116       return;
    117     client_ = client.Pass();
    118     got_first_frame_ = false;
    119   }
    120 
    121   JNIEnv* env = AttachCurrentThread();
    122 
    123   jboolean ret =
    124       Java_VideoCapture_allocate(env,
    125                                  j_capture_.obj(),
    126                                  params.requested_format.frame_size.width(),
    127                                  params.requested_format.frame_size.height(),
    128                                  params.requested_format.frame_rate);
    129   if (!ret) {
    130     SetErrorState("failed to allocate");
    131     return;
    132   }
    133 
    134   // Store current width and height.
    135   capture_format_.frame_size.SetSize(
    136       Java_VideoCapture_queryWidth(env, j_capture_.obj()),
    137       Java_VideoCapture_queryHeight(env, j_capture_.obj()));
    138   capture_format_.frame_rate =
    139       Java_VideoCapture_queryFrameRate(env, j_capture_.obj());
    140   capture_format_.pixel_format = GetColorspace();
    141   DCHECK_NE(capture_format_.pixel_format, media::PIXEL_FORMAT_UNKNOWN);
    142   CHECK(capture_format_.frame_size.GetArea() > 0);
    143   CHECK(!(capture_format_.frame_size.width() % 2));
    144   CHECK(!(capture_format_.frame_size.height() % 2));
    145 
    146   if (capture_format_.frame_rate > 0) {
    147     frame_interval_ = base::TimeDelta::FromMicroseconds(
    148         (base::Time::kMicrosecondsPerSecond + capture_format_.frame_rate - 1) /
    149         capture_format_.frame_rate);
    150   }
    151 
    152   DVLOG(1) << "VideoCaptureDeviceAndroid::Allocate: queried frame_size="
    153            << capture_format_.frame_size.ToString()
    154            << ", frame_rate=" << capture_format_.frame_rate;
    155 
    156   jint result = Java_VideoCapture_startCapture(env, j_capture_.obj());
    157   if (result < 0) {
    158     SetErrorState("failed to start capture");
    159     return;
    160   }
    161 
    162   {
    163     base::AutoLock lock(lock_);
    164     state_ = kCapturing;
    165   }
    166 }
    167 
    168 void VideoCaptureDeviceAndroid::StopAndDeAllocate() {
    169   DVLOG(1) << "VideoCaptureDeviceAndroid::StopAndDeAllocate";
    170   {
    171     base::AutoLock lock(lock_);
    172     if (state_ != kCapturing && state_ != kError)
    173       return;
    174   }
    175 
    176   JNIEnv* env = AttachCurrentThread();
    177 
    178   jint ret = Java_VideoCapture_stopCapture(env, j_capture_.obj());
    179   if (ret < 0) {
    180     SetErrorState("failed to stop capture");
    181     return;
    182   }
    183 
    184   {
    185     base::AutoLock lock(lock_);
    186     state_ = kIdle;
    187     client_.reset();
    188   }
    189 
    190   Java_VideoCapture_deallocate(env, j_capture_.obj());
    191 }
    192 
    193 void VideoCaptureDeviceAndroid::OnFrameAvailable(
    194     JNIEnv* env,
    195     jobject obj,
    196     jbyteArray data,
    197     jint length,
    198     jint rotation) {
    199   DVLOG(3) << "VideoCaptureDeviceAndroid::OnFrameAvailable: length =" << length;
    200 
    201   base::AutoLock lock(lock_);
    202   if (state_ != kCapturing || !client_.get())
    203     return;
    204 
    205   jbyte* buffer = env->GetByteArrayElements(data, NULL);
    206   if (!buffer) {
    207     LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: "
    208                   "failed to GetByteArrayElements";
    209     return;
    210   }
    211 
    212   base::TimeTicks current_time = base::TimeTicks::Now();
    213   if (!got_first_frame_) {
    214     // Set aside one frame allowance for fluctuation.
    215     expected_next_frame_time_ = current_time - frame_interval_;
    216     got_first_frame_ = true;
    217   }
    218 
    219   // Deliver the frame when it doesn't arrive too early.
    220   if (expected_next_frame_time_ <= current_time) {
    221     expected_next_frame_time_ += frame_interval_;
    222 
    223     client_->OnIncomingCapturedFrame(reinterpret_cast<uint8*>(buffer),
    224                                      length,
    225                                      base::Time::Now(),
    226                                      rotation,
    227                                      capture_format_);
    228   }
    229 
    230   env->ReleaseByteArrayElements(data, buffer, JNI_ABORT);
    231 }
    232 
    233 VideoPixelFormat VideoCaptureDeviceAndroid::GetColorspace() {
    234   JNIEnv* env = AttachCurrentThread();
    235   int current_capture_colorspace =
    236       Java_VideoCapture_getColorspace(env, j_capture_.obj());
    237   switch (current_capture_colorspace){
    238   case ANDROID_IMAGEFORMAT_YV12:
    239     return media::PIXEL_FORMAT_YV12;
    240   case ANDROID_IMAGEFORMAT_NV21:
    241     return media::PIXEL_FORMAT_NV21;
    242   case ANDROID_IMAGEFORMAT_YUY2:
    243     return media::PIXEL_FORMAT_YUY2;
    244   case ANDROID_IMAGEFORMAT_NV16:
    245   case ANDROID_IMAGEFORMAT_JPEG:
    246   case ANDROID_IMAGEFORMAT_RGB_565:
    247   case ANDROID_IMAGEFORMAT_UNKNOWN:
    248     // NOTE(mcasas): NV16, JPEG, RGB565 not supported in VideoPixelFormat.
    249   default:
    250     return media::PIXEL_FORMAT_UNKNOWN;
    251   }
    252 }
    253 
    254 void VideoCaptureDeviceAndroid::SetErrorState(const std::string& reason) {
    255   LOG(ERROR) << "VideoCaptureDeviceAndroid::SetErrorState: " << reason;
    256   {
    257     base::AutoLock lock(lock_);
    258     state_ = kError;
    259   }
    260   client_->OnError();
    261 }
    262 
    263 }  // namespace media
    264