Allow overlapping sync and async startup requests
[chromium-blink-merge.git] / media / base / android / media_codec_bridge.cc
blobbb5ddccfd7e5a239961ba4761ee8903da0a84e56
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.
5 #include "media/base/android/media_codec_bridge.h"
7 #include <jni.h>
9 #include "base/android/build_info.h"
10 #include "base/android/jni_android.h"
11 #include "base/android/jni_array.h"
12 #include "base/android/jni_string.h"
13 #include "base/basictypes.h"
14 #include "base/lazy_instance.h"
15 #include "base/logging.h"
16 #include "base/safe_numerics.h"
17 #include "base/strings/stringprintf.h"
18 #include "jni/MediaCodecBridge_jni.h"
19 #include "media/base/bit_reader.h"
20 #include "media/base/decrypt_config.h"
22 using base::android::AttachCurrentThread;
23 using base::android::ConvertUTF8ToJavaString;
24 using base::android::ScopedJavaLocalRef;
26 namespace media {
28 enum { kBufferFlagEndOfStream = 4 };
30 static const char* AudioCodecToMimeType(const AudioCodec codec) {
31 switch (codec) {
32 case kCodecMP3:
33 return "audio/mpeg";
34 case kCodecVorbis:
35 return "audio/vorbis";
36 case kCodecAAC:
37 return "audio/mp4a-latm";
38 default:
39 return NULL;
43 static const char* VideoCodecToMimeType(const VideoCodec codec) {
44 switch (codec) {
45 case kCodecH264:
46 return "video/avc";
47 case kCodecVP8:
48 return "video/x-vnd.on2.vp8";
49 default:
50 return NULL;
54 static ScopedJavaLocalRef<jintArray> ToJavaIntArray(
55 JNIEnv* env, scoped_ptr<jint[]> native_array, int size) {
56 ScopedJavaLocalRef<jintArray> j_array(env, env->NewIntArray(size));
57 env->SetIntArrayRegion(j_array.obj(), 0, size, native_array.get());
58 return j_array;
61 // static
62 const base::TimeDelta MediaCodecBridge::kTimeOutInfinity =
63 base::TimeDelta::FromMicroseconds(-1);
65 // static
66 const base::TimeDelta MediaCodecBridge::kTimeOutNoWait =
67 base::TimeDelta::FromMicroseconds(0);
69 // static
70 bool MediaCodecBridge::IsAvailable() {
71 // MediaCodec is only available on JB and greater.
72 return base::android::BuildInfo::GetInstance()->sdk_int() >= 16;
75 MediaCodecBridge::MediaCodecBridge(const char* mime) {
76 JNIEnv* env = AttachCurrentThread();
77 CHECK(env);
78 DCHECK(mime);
80 ScopedJavaLocalRef<jstring> j_type = ConvertUTF8ToJavaString(env, mime);
81 j_media_codec_.Reset(Java_MediaCodecBridge_create(
82 env, j_type.obj()));
85 MediaCodecBridge::~MediaCodecBridge() {
86 JNIEnv* env = AttachCurrentThread();
87 CHECK(env);
88 if (j_media_codec_.obj())
89 Java_MediaCodecBridge_release(env, j_media_codec_.obj());
92 void MediaCodecBridge::StartInternal() {
93 JNIEnv* env = AttachCurrentThread();
94 Java_MediaCodecBridge_start(env, j_media_codec_.obj());
95 GetOutputBuffers();
98 void MediaCodecBridge::Reset() {
99 JNIEnv* env = AttachCurrentThread();
100 Java_MediaCodecBridge_flush(env, j_media_codec_.obj());
103 void MediaCodecBridge::Stop() {
104 JNIEnv* env = AttachCurrentThread();
105 Java_MediaCodecBridge_stop(env, j_media_codec_.obj());
108 void MediaCodecBridge::GetOutputFormat(int* width, int* height) {
109 JNIEnv* env = AttachCurrentThread();
111 *width = Java_MediaCodecBridge_getOutputWidth(env, j_media_codec_.obj());
112 *height = Java_MediaCodecBridge_getOutputHeight(env, j_media_codec_.obj());
115 size_t MediaCodecBridge::QueueInputBuffer(
116 int index, const uint8* data, int size,
117 const base::TimeDelta& presentation_time) {
118 size_t size_to_copy = FillInputBuffer(index, data, size);
119 JNIEnv* env = AttachCurrentThread();
120 Java_MediaCodecBridge_queueInputBuffer(
121 env, j_media_codec_.obj(),
122 index, 0, size_to_copy, presentation_time.InMicroseconds(), 0);
123 return size_to_copy;
126 size_t MediaCodecBridge::QueueSecureInputBuffer(
127 int index, const uint8* data, int data_size, const uint8* key_id,
128 int key_id_size, const uint8* iv, int iv_size,
129 const SubsampleEntry* subsamples, int subsamples_size,
130 const base::TimeDelta& presentation_time) {
131 size_t size_to_copy = FillInputBuffer(index, data, data_size);
133 JNIEnv* env = AttachCurrentThread();
134 ScopedJavaLocalRef<jbyteArray> j_key_id =
135 base::android::ToJavaByteArray(env, key_id, key_id_size);
136 ScopedJavaLocalRef<jbyteArray> j_iv =
137 base::android::ToJavaByteArray(env, iv, iv_size);
138 scoped_ptr<jint[]> native_clear_array(new jint[subsamples_size]);
139 scoped_ptr<jint[]> native_cypher_array(new jint[subsamples_size]);
140 for (int i = 0; i < subsamples_size; ++i) {
141 native_clear_array[i] = subsamples[i].clear_bytes;
142 native_cypher_array[i] = subsamples[i].cypher_bytes;
144 ScopedJavaLocalRef<jintArray> clear_array = ToJavaIntArray(
145 env, native_clear_array.Pass(), subsamples_size);
146 ScopedJavaLocalRef<jintArray> cypher_array = ToJavaIntArray(
147 env, native_cypher_array.Pass(), subsamples_size);
149 Java_MediaCodecBridge_queueSecureInputBuffer(
150 env, j_media_codec_.obj(), index, 0, j_iv.obj(), j_key_id.obj(),
151 clear_array.obj(), cypher_array.obj(), subsamples_size,
152 presentation_time.InMicroseconds());
154 return size_to_copy;
157 void MediaCodecBridge::QueueEOS(int input_buffer_index) {
158 JNIEnv* env = AttachCurrentThread();
159 Java_MediaCodecBridge_queueInputBuffer(
160 env, j_media_codec_.obj(),
161 input_buffer_index, 0, 0, 0, kBufferFlagEndOfStream);
164 int MediaCodecBridge::DequeueInputBuffer(base::TimeDelta timeout) {
165 JNIEnv* env = AttachCurrentThread();
166 return Java_MediaCodecBridge_dequeueInputBuffer(
167 env, j_media_codec_.obj(), timeout.InMicroseconds());
170 int MediaCodecBridge::DequeueOutputBuffer(
171 base::TimeDelta timeout, size_t* offset, size_t* size,
172 base::TimeDelta* presentation_time, bool* end_of_stream) {
173 JNIEnv* env = AttachCurrentThread();
175 ScopedJavaLocalRef<jobject> result =
176 Java_MediaCodecBridge_dequeueOutputBuffer(env, j_media_codec_.obj(),
177 timeout.InMicroseconds());
179 int j_buffer = Java_DequeueOutputResult_index(env, result.obj());
180 if (j_buffer >= 0) {
181 int64 presentation_time_us =
182 Java_DequeueOutputResult_presentationTimeMicroseconds(
183 env, result.obj());
184 int flags = Java_DequeueOutputResult_flags(env, result.obj());
185 *offset = base::checked_numeric_cast<size_t>(
186 Java_DequeueOutputResult_offset(env, result.obj()));
187 *size = base::checked_numeric_cast<size_t>(
188 Java_DequeueOutputResult_numBytes(env, result.obj()));
189 *presentation_time =
190 base::TimeDelta::FromMicroseconds(presentation_time_us);
191 *end_of_stream = flags & kBufferFlagEndOfStream;
193 return j_buffer;
196 void MediaCodecBridge::ReleaseOutputBuffer(int index, bool render) {
197 JNIEnv* env = AttachCurrentThread();
198 CHECK(env);
200 Java_MediaCodecBridge_releaseOutputBuffer(
201 env, j_media_codec_.obj(), index, render);
204 void MediaCodecBridge::GetOutputBuffers() {
205 JNIEnv* env = AttachCurrentThread();
206 Java_MediaCodecBridge_getOutputBuffers(env, j_media_codec_.obj());
209 size_t MediaCodecBridge::FillInputBuffer(
210 int index, const uint8* data, int size) {
211 JNIEnv* env = AttachCurrentThread();
213 ScopedJavaLocalRef<jobject> j_buffer(
214 Java_MediaCodecBridge_getInputBuffer(env, j_media_codec_.obj(), index));
216 uint8* direct_buffer =
217 static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj()));
218 int64 buffer_capacity = env->GetDirectBufferCapacity(j_buffer.obj());
220 int size_to_copy = (buffer_capacity < size) ? buffer_capacity : size;
221 // TODO(qinmin): Handling the case that not all the data can be copied.
222 DCHECK(size_to_copy == size) <<
223 "Failed to fill all the data into the input buffer. Size to fill: "
224 << size << ". Size filled: " << size_to_copy;
225 if (size_to_copy > 0)
226 memcpy(direct_buffer, data, size_to_copy);
227 return size_to_copy;
230 AudioCodecBridge::AudioCodecBridge(const char* mime)
231 : MediaCodecBridge(mime) {
234 bool AudioCodecBridge::Start(
235 const AudioCodec codec, int sample_rate, int channel_count,
236 const uint8* extra_data, size_t extra_data_size, bool play_audio,
237 jobject media_crypto) {
238 JNIEnv* env = AttachCurrentThread();
239 DCHECK(AudioCodecToMimeType(codec));
241 if (!media_codec())
242 return false;
244 ScopedJavaLocalRef<jstring> j_mime =
245 ConvertUTF8ToJavaString(env, AudioCodecToMimeType(codec));
246 ScopedJavaLocalRef<jobject> j_format(
247 Java_MediaCodecBridge_createAudioFormat(
248 env, j_mime.obj(), sample_rate, channel_count));
249 DCHECK(!j_format.is_null());
251 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size))
252 return false;
254 if (!Java_MediaCodecBridge_configureAudio(
255 env, media_codec(), j_format.obj(), media_crypto, 0, play_audio)) {
256 return false;
258 StartInternal();
259 return true;
262 bool AudioCodecBridge::ConfigureMediaFormat(
263 jobject j_format, const AudioCodec codec, const uint8* extra_data,
264 size_t extra_data_size) {
265 if (extra_data_size == 0)
266 return true;
268 JNIEnv* env = AttachCurrentThread();
269 switch(codec) {
270 case kCodecVorbis:
272 if (extra_data[0] != 2) {
273 LOG(ERROR) << "Invalid number of vorbis headers before the codec "
274 << "header: " << extra_data[0];
275 return false;
278 size_t header_length[2];
279 // |total_length| keeps track of the total number of bytes before the last
280 // header.
281 size_t total_length = 1;
282 const uint8* current_pos = extra_data;
283 // Calculate the length of the first 2 headers.
284 for (int i = 0; i < 2; ++i) {
285 header_length[i] = 0;
286 while (total_length < extra_data_size) {
287 size_t size = *(++current_pos);
288 total_length += 1 + size;
289 if (total_length > 0x80000000) {
290 LOG(ERROR) << "Vorbis header size too large";
291 return false;
293 header_length[i] += size;
294 if (size < 0xFF)
295 break;
297 if (total_length >= extra_data_size) {
298 LOG(ERROR) << "Invalid vorbis header size in the extra data";
299 return false;
302 current_pos++;
303 // The first header is identification header.
304 jobject identification_header = env->NewDirectByteBuffer(
305 const_cast<uint8*>(current_pos), header_length[0]);
306 Java_MediaCodecBridge_setCodecSpecificData(
307 env, j_format, 0, identification_header);
308 // The last header is codec header.
309 jobject codec_header = env->NewDirectByteBuffer(
310 const_cast<uint8*>(extra_data + total_length),
311 extra_data_size - total_length);
312 Java_MediaCodecBridge_setCodecSpecificData(
313 env, j_format, 1, codec_header);
314 env->DeleteLocalRef(codec_header);
315 env->DeleteLocalRef(identification_header);
316 break;
318 case kCodecAAC:
320 media::BitReader reader(extra_data, extra_data_size);
322 // The following code is copied from aac.cc
323 // TODO(qinmin): refactor the code in aac.cc to make it more reusable.
324 uint8 profile = 0;
325 uint8 frequency_index = 0;
326 uint8 channel_config = 0;
327 if (!reader.ReadBits(5, &profile) ||
328 !reader.ReadBits(4, &frequency_index)) {
329 LOG(ERROR) << "Unable to parse AAC header";
330 return false;
332 if (0xf == frequency_index && !reader.SkipBits(24)) {
333 LOG(ERROR) << "Unable to parse AAC header";
334 return false;
336 if (!reader.ReadBits(4, &channel_config)) {
337 LOG(ERROR) << "Unable to parse AAC header";
338 return false;
341 if (profile < 1 || profile > 4 || frequency_index == 0xf ||
342 channel_config > 7) {
343 LOG(ERROR) << "Invalid AAC header";
344 return false;
346 uint8 csd[2];
347 csd[0] = profile << 3 | frequency_index >> 1;
348 csd[1] = (frequency_index & 0x01) << 7 | channel_config << 3;
349 jobject header = env->NewDirectByteBuffer(csd, 2);
350 Java_MediaCodecBridge_setCodecSpecificData(
351 env, j_format, 0, header);
352 // TODO(qinmin): pass an extra variable to this function to determine
353 // whether we need to call this.
354 Java_MediaCodecBridge_setFrameHasADTSHeader(env, j_format);
355 env->DeleteLocalRef(header);
356 break;
358 default:
359 LOG(ERROR) << "Invalid header encountered for codec: "
360 << AudioCodecToMimeType(codec);
361 return false;
363 return true;
366 void AudioCodecBridge::PlayOutputBuffer(int index, size_t size) {
367 DCHECK_LE(0, index);
368 int numBytes = base::checked_numeric_cast<int>(size);
369 JNIEnv* env = AttachCurrentThread();
370 ScopedJavaLocalRef<jobject> buf =
371 Java_MediaCodecBridge_getOutputBuffer(env, media_codec(), index);
372 uint8* buffer = static_cast<uint8*>(env->GetDirectBufferAddress(buf.obj()));
374 ScopedJavaLocalRef<jbyteArray> byte_array =
375 base::android::ToJavaByteArray(env, buffer, numBytes);
376 Java_MediaCodecBridge_playOutputBuffer(
377 env, media_codec(), byte_array.obj());
380 void AudioCodecBridge::SetVolume(double volume) {
381 JNIEnv* env = AttachCurrentThread();
382 Java_MediaCodecBridge_setVolume(env, media_codec(), volume);
385 VideoCodecBridge::VideoCodecBridge(const char* mime)
386 : MediaCodecBridge(mime) {
389 bool VideoCodecBridge::Start(
390 const VideoCodec codec, const gfx::Size& size, jobject surface,
391 jobject media_crypto) {
392 JNIEnv* env = AttachCurrentThread();
393 DCHECK(VideoCodecToMimeType(codec));
395 if (!media_codec())
396 return false;
398 ScopedJavaLocalRef<jstring> j_mime =
399 ConvertUTF8ToJavaString(env, VideoCodecToMimeType(codec));
400 ScopedJavaLocalRef<jobject> j_format(
401 Java_MediaCodecBridge_createVideoFormat(
402 env, j_mime.obj(), size.width(), size.height()));
403 DCHECK(!j_format.is_null());
404 if (!Java_MediaCodecBridge_configureVideo(
405 env, media_codec(), j_format.obj(), surface, media_crypto, 0)) {
406 return false;
408 StartInternal();
409 return true;
412 AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec codec) {
413 const char* mime = AudioCodecToMimeType(codec);
414 return mime ? new AudioCodecBridge(mime) : NULL;
417 VideoCodecBridge* VideoCodecBridge::Create(const VideoCodec codec) {
418 const char* mime = VideoCodecToMimeType(codec);
419 return mime ? new VideoCodecBridge(mime) : NULL;
422 bool MediaCodecBridge::RegisterMediaCodecBridge(JNIEnv* env) {
423 return RegisterNativesImpl(env);
426 } // namespace media