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/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   {
    194     base::AutoLock lock(lock_);
    195     state_ = kError;
    196   }
    197   client_->OnError(reason);
    198 }
    199 
    200 }  // namespace media
    201