• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
RegisterVideoCaptureDevice(JNIEnv * env)25 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) {
26   return RegisterNativesImpl(env);
27 }
28 
GetModel() const29 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 
VideoCaptureDeviceAndroid(const Name & device_name)36 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(const Name& device_name)
37     : state_(kIdle), got_first_frame_(false), device_name_(device_name) {}
38 
~VideoCaptureDeviceAndroid()39 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() {
40   StopAndDeAllocate();
41 }
42 
Init()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 
AllocateAndStart(const VideoCaptureParams & params,scoped_ptr<Client> client)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 
StopAndDeAllocate()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 
OnFrameAvailable(JNIEnv * env,jobject obj,jbyteArray data,jint length,jint rotation)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 
GetColorspace()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 
SetErrorState(const std::string & reason)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