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