OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/base/android/media_codec_bridge.h" | 5 #include "media/base/android/media_codec_bridge.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <limits> | 8 #include <limits> |
| 9 #include <memory> |
| 10 #include <utility> |
9 | 11 |
| 12 #include "base/android/build_info.h" |
| 13 #include "base/android/jni_android.h" |
| 14 #include "base/android/jni_array.h" |
| 15 #include "base/android/jni_string.h" |
10 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/numerics/safe_conversions.h" |
11 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
| 19 #include "jni/MediaCodecBridge_jni.h" |
| 20 #include "media/base/android/media_codec_util.h" |
| 21 #include "media/base/bit_reader.h" |
12 #include "media/base/subsample_entry.h" | 22 #include "media/base/subsample_entry.h" |
13 | 23 |
| 24 using base::android::AttachCurrentThread; |
| 25 using base::android::ConvertJavaStringToUTF8; |
| 26 using base::android::ConvertUTF8ToJavaString; |
| 27 using base::android::JavaIntArrayToIntVector; |
| 28 using base::android::ScopedJavaLocalRef; |
| 29 |
| 30 #define RETURN_ON_ERROR(condition) \ |
| 31 do { \ |
| 32 if (!(condition)) { \ |
| 33 LOG(ERROR) << "Unable to parse AAC header: " #condition; \ |
| 34 return false; \ |
| 35 } \ |
| 36 } while (0) |
| 37 |
14 namespace media { | 38 namespace media { |
| 39 namespace { |
15 | 40 |
16 MediaCodecBridge::MediaCodecBridge() {} | 41 enum { |
| 42 kBufferFlagSyncFrame = 1, // BUFFER_FLAG_SYNC_FRAME |
| 43 kBufferFlagEndOfStream = 4, // BUFFER_FLAG_END_OF_STREAM |
| 44 kConfigureFlagEncode = 1, // CONFIGURE_FLAG_ENCODE |
| 45 }; |
17 | 46 |
18 MediaCodecBridge::~MediaCodecBridge() {} | 47 const std::string AudioCodecToAndroidMimeType(const AudioCodec& codec) { |
| 48 switch (codec) { |
| 49 case kCodecMP3: |
| 50 return "audio/mpeg"; |
| 51 case kCodecVorbis: |
| 52 return "audio/vorbis"; |
| 53 case kCodecOpus: |
| 54 return "audio/opus"; |
| 55 case kCodecAAC: |
| 56 return "audio/mp4a-latm"; |
| 57 case kCodecAC3: |
| 58 return "audio/ac3"; |
| 59 case kCodecEAC3: |
| 60 return "audio/eac3"; |
| 61 default: |
| 62 return std::string(); |
| 63 } |
| 64 } |
| 65 |
| 66 const std::string VideoCodecToAndroidMimeType(const VideoCodec& codec) { |
| 67 switch (codec) { |
| 68 case kCodecH264: |
| 69 return "video/avc"; |
| 70 case kCodecHEVC: |
| 71 return "video/hevc"; |
| 72 case kCodecVP8: |
| 73 return "video/x-vnd.on2.vp8"; |
| 74 case kCodecVP9: |
| 75 return "video/x-vnd.on2.vp9"; |
| 76 default: |
| 77 return std::string(); |
| 78 } |
| 79 } |
| 80 |
| 81 static ScopedJavaLocalRef<jintArray> |
| 82 ToJavaIntArray(JNIEnv* env, std::unique_ptr<jint[]> native_array, int size) { |
| 83 ScopedJavaLocalRef<jintArray> j_array(env, env->NewIntArray(size)); |
| 84 env->SetIntArrayRegion(j_array.obj(), 0, size, native_array.get()); |
| 85 return j_array; |
| 86 } |
| 87 |
| 88 } // namespace |
| 89 |
| 90 MediaCodecBridge::MediaCodecBridge() = default; |
| 91 |
| 92 MediaCodecBridge::MediaCodecBridge(const std::string& mime, |
| 93 bool is_secure, |
| 94 MediaCodecDirection direction, |
| 95 bool require_software_codec) { |
| 96 JNIEnv* env = AttachCurrentThread(); |
| 97 DCHECK(!mime.empty()); |
| 98 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
| 99 j_media_codec_.Reset(Java_MediaCodecBridge_create( |
| 100 env, j_mime, is_secure, direction, require_software_codec)); |
| 101 } |
| 102 |
| 103 MediaCodecBridge::~MediaCodecBridge() { |
| 104 JNIEnv* env = AttachCurrentThread(); |
| 105 if (j_media_codec_.obj()) |
| 106 Java_MediaCodecBridge_release(env, j_media_codec_); |
| 107 } |
| 108 |
| 109 bool MediaCodecBridge::Start() { |
| 110 JNIEnv* env = AttachCurrentThread(); |
| 111 return Java_MediaCodecBridge_start(env, j_media_codec_); |
| 112 } |
| 113 |
| 114 void MediaCodecBridge::Stop() { |
| 115 JNIEnv* env = AttachCurrentThread(); |
| 116 Java_MediaCodecBridge_stop(env, j_media_codec_); |
| 117 } |
| 118 |
| 119 MediaCodecStatus MediaCodecBridge::Flush() { |
| 120 JNIEnv* env = AttachCurrentThread(); |
| 121 return static_cast<MediaCodecStatus>( |
| 122 Java_MediaCodecBridge_flush(env, j_media_codec_)); |
| 123 } |
| 124 |
| 125 MediaCodecStatus MediaCodecBridge::GetOutputSize(gfx::Size* size) { |
| 126 JNIEnv* env = AttachCurrentThread(); |
| 127 ScopedJavaLocalRef<jobject> result = |
| 128 Java_MediaCodecBridge_getOutputFormat(env, j_media_codec_); |
| 129 MediaCodecStatus status = static_cast<MediaCodecStatus>( |
| 130 Java_GetOutputFormatResult_status(env, result)); |
| 131 if (status == MEDIA_CODEC_OK) { |
| 132 size->SetSize(Java_GetOutputFormatResult_width(env, result), |
| 133 Java_GetOutputFormatResult_height(env, result)); |
| 134 } |
| 135 return status; |
| 136 } |
| 137 |
| 138 MediaCodecStatus MediaCodecBridge::GetOutputSamplingRate(int* sampling_rate) { |
| 139 JNIEnv* env = AttachCurrentThread(); |
| 140 ScopedJavaLocalRef<jobject> result = |
| 141 Java_MediaCodecBridge_getOutputFormat(env, j_media_codec_); |
| 142 MediaCodecStatus status = static_cast<MediaCodecStatus>( |
| 143 Java_GetOutputFormatResult_status(env, result)); |
| 144 if (status == MEDIA_CODEC_OK) |
| 145 *sampling_rate = Java_GetOutputFormatResult_sampleRate(env, result); |
| 146 return status; |
| 147 } |
| 148 |
| 149 MediaCodecStatus MediaCodecBridge::GetOutputChannelCount(int* channel_count) { |
| 150 JNIEnv* env = AttachCurrentThread(); |
| 151 ScopedJavaLocalRef<jobject> result = |
| 152 Java_MediaCodecBridge_getOutputFormat(env, j_media_codec_); |
| 153 MediaCodecStatus status = static_cast<MediaCodecStatus>( |
| 154 Java_GetOutputFormatResult_status(env, result)); |
| 155 if (status == MEDIA_CODEC_OK) |
| 156 *channel_count = Java_GetOutputFormatResult_channelCount(env, result); |
| 157 return status; |
| 158 } |
| 159 |
| 160 MediaCodecStatus MediaCodecBridge::QueueInputBuffer( |
| 161 int index, |
| 162 const uint8_t* data, |
| 163 size_t data_size, |
| 164 base::TimeDelta presentation_time) { |
| 165 DVLOG(3) << __func__ << " " << index << ": " << data_size; |
| 166 if (data_size > |
| 167 base::checked_cast<size_t>(std::numeric_limits<int32_t>::max())) { |
| 168 return MEDIA_CODEC_ERROR; |
| 169 } |
| 170 if (data && !FillInputBuffer(index, data, data_size)) |
| 171 return MEDIA_CODEC_ERROR; |
| 172 JNIEnv* env = AttachCurrentThread(); |
| 173 return static_cast<MediaCodecStatus>(Java_MediaCodecBridge_queueInputBuffer( |
| 174 env, j_media_codec_, index, 0, data_size, |
| 175 presentation_time.InMicroseconds(), 0)); |
| 176 } |
19 | 177 |
20 MediaCodecStatus MediaCodecBridge::QueueSecureInputBuffer( | 178 MediaCodecStatus MediaCodecBridge::QueueSecureInputBuffer( |
21 int index, | 179 int index, |
22 const uint8_t* data, | 180 const uint8_t* data, |
23 size_t data_size, | 181 size_t data_size, |
24 const std::string& key_id, | 182 const std::string& key_id, |
25 const std::string& iv, | 183 const std::string& iv, |
26 const std::vector<SubsampleEntry>& subsamples, | 184 const std::vector<SubsampleEntry>& subsamples, |
27 const EncryptionScheme& encryption_scheme, | 185 const EncryptionScheme& encryption_scheme, |
28 base::TimeDelta presentation_time) { | 186 base::TimeDelta presentation_time) { |
29 const std::vector<char> key_vec(key_id.begin(), key_id.end()); | 187 DVLOG(3) << __func__ << " " << index << ": " << data_size; |
30 const std::vector<char> iv_vec(iv.begin(), iv.end()); | 188 if (data_size > |
31 return QueueSecureInputBuffer(index, data, data_size, key_vec, iv_vec, | 189 base::checked_cast<size_t>(std::numeric_limits<int32_t>::max())) { |
32 subsamples.empty() ? nullptr : &subsamples[0], | 190 return MEDIA_CODEC_ERROR; |
33 (int)subsamples.size(), encryption_scheme, | 191 } |
34 presentation_time); | 192 if (data && !FillInputBuffer(index, data, data_size)) |
| 193 return MEDIA_CODEC_ERROR; |
| 194 |
| 195 JNIEnv* env = AttachCurrentThread(); |
| 196 ScopedJavaLocalRef<jbyteArray> j_key_id = base::android::ToJavaByteArray( |
| 197 env, reinterpret_cast<const uint8_t*>(key_id.data()), key_id.size()); |
| 198 ScopedJavaLocalRef<jbyteArray> j_iv = base::android::ToJavaByteArray( |
| 199 env, reinterpret_cast<const uint8_t*>(iv.data()), iv.size()); |
| 200 |
| 201 // The MediaCodec.CryptoInfo documentation says to pass NULL for |clear_array| |
| 202 // to indicate that all data is encrypted. But it doesn't specify what |
| 203 // |cypher_array| and |subsamples_size| should be in that case. We pass |
| 204 // one subsample here just to be on the safe side. |
| 205 int num_subsamples = std::max(1u, subsamples.size()); |
| 206 |
| 207 std::unique_ptr<jint[]> native_clear_array(new jint[num_subsamples]); |
| 208 std::unique_ptr<jint[]> native_cypher_array(new jint[num_subsamples]); |
| 209 |
| 210 if (subsamples.empty()) { |
| 211 native_clear_array[0] = 0; |
| 212 native_cypher_array[0] = data_size; |
| 213 } else { |
| 214 for (size_t i = 0; i < subsamples.size(); ++i) { |
| 215 DCHECK(subsamples[i].clear_bytes <= std::numeric_limits<uint16_t>::max()); |
| 216 if (subsamples[i].cypher_bytes > |
| 217 static_cast<uint32_t>(std::numeric_limits<jint>::max())) { |
| 218 return MEDIA_CODEC_ERROR; |
| 219 } |
| 220 |
| 221 native_clear_array[i] = subsamples[i].clear_bytes; |
| 222 native_cypher_array[i] = subsamples[i].cypher_bytes; |
| 223 } |
| 224 } |
| 225 |
| 226 ScopedJavaLocalRef<jintArray> clear_array = |
| 227 ToJavaIntArray(env, std::move(native_clear_array), num_subsamples); |
| 228 ScopedJavaLocalRef<jintArray> cypher_array = |
| 229 ToJavaIntArray(env, std::move(native_cypher_array), num_subsamples); |
| 230 |
| 231 return static_cast<MediaCodecStatus>( |
| 232 Java_MediaCodecBridge_queueSecureInputBuffer( |
| 233 env, j_media_codec_.obj(), index, 0, j_iv.obj(), j_key_id.obj(), |
| 234 clear_array, cypher_array, num_subsamples, |
| 235 static_cast<int>(encryption_scheme.mode()), |
| 236 static_cast<int>(encryption_scheme.pattern().encrypt_blocks()), |
| 237 static_cast<int>(encryption_scheme.pattern().skip_blocks()), |
| 238 presentation_time.InMicroseconds())); |
| 239 } |
| 240 |
| 241 void MediaCodecBridge::QueueEOS(int input_buffer_index) { |
| 242 DVLOG(3) << __func__ << ": " << input_buffer_index; |
| 243 JNIEnv* env = AttachCurrentThread(); |
| 244 Java_MediaCodecBridge_queueInputBuffer( |
| 245 env, j_media_codec_, input_buffer_index, 0, 0, 0, kBufferFlagEndOfStream); |
| 246 } |
| 247 |
| 248 MediaCodecStatus MediaCodecBridge::DequeueInputBuffer(base::TimeDelta timeout, |
| 249 int* index) { |
| 250 JNIEnv* env = AttachCurrentThread(); |
| 251 ScopedJavaLocalRef<jobject> result = Java_MediaCodecBridge_dequeueInputBuffer( |
| 252 env, j_media_codec_, timeout.InMicroseconds()); |
| 253 *index = Java_DequeueInputResult_index(env, result); |
| 254 MediaCodecStatus status = static_cast<MediaCodecStatus>( |
| 255 Java_DequeueInputResult_status(env, result)); |
| 256 DVLOG(3) << __func__ << ": status: " << status << ", index: " << *index; |
| 257 return status; |
| 258 } |
| 259 |
| 260 MediaCodecStatus MediaCodecBridge::DequeueOutputBuffer( |
| 261 base::TimeDelta timeout, |
| 262 int* index, |
| 263 size_t* offset, |
| 264 size_t* size, |
| 265 base::TimeDelta* presentation_time, |
| 266 bool* end_of_stream, |
| 267 bool* key_frame) { |
| 268 JNIEnv* env = AttachCurrentThread(); |
| 269 ScopedJavaLocalRef<jobject> result = |
| 270 Java_MediaCodecBridge_dequeueOutputBuffer(env, j_media_codec_, |
| 271 timeout.InMicroseconds()); |
| 272 *index = Java_DequeueOutputResult_index(env, result); |
| 273 *offset = |
| 274 base::checked_cast<size_t>(Java_DequeueOutputResult_offset(env, result)); |
| 275 *size = base::checked_cast<size_t>( |
| 276 Java_DequeueOutputResult_numBytes(env, result)); |
| 277 if (presentation_time) { |
| 278 *presentation_time = base::TimeDelta::FromMicroseconds( |
| 279 Java_DequeueOutputResult_presentationTimeMicroseconds(env, result)); |
| 280 } |
| 281 int flags = Java_DequeueOutputResult_flags(env, result); |
| 282 if (end_of_stream) |
| 283 *end_of_stream = flags & kBufferFlagEndOfStream; |
| 284 if (key_frame) |
| 285 *key_frame = flags & kBufferFlagSyncFrame; |
| 286 MediaCodecStatus status = static_cast<MediaCodecStatus>( |
| 287 Java_DequeueOutputResult_status(env, result)); |
| 288 DVLOG(3) << __func__ << ": status: " << status << ", index: " << *index |
| 289 << ", offset: " << *offset << ", size: " << *size |
| 290 << ", flags: " << flags; |
| 291 return status; |
| 292 } |
| 293 |
| 294 void MediaCodecBridge::ReleaseOutputBuffer(int index, bool render) { |
| 295 DVLOG(3) << __func__ << ": " << index; |
| 296 JNIEnv* env = AttachCurrentThread(); |
| 297 Java_MediaCodecBridge_releaseOutputBuffer(env, j_media_codec_, index, render); |
| 298 } |
| 299 |
| 300 MediaCodecStatus MediaCodecBridge::GetInputBuffer(int input_buffer_index, |
| 301 uint8_t** data, |
| 302 size_t* capacity) { |
| 303 JNIEnv* env = AttachCurrentThread(); |
| 304 ScopedJavaLocalRef<jobject> j_buffer(Java_MediaCodecBridge_getInputBuffer( |
| 305 env, j_media_codec_, input_buffer_index)); |
| 306 if (j_buffer.is_null()) |
| 307 return MEDIA_CODEC_ERROR; |
| 308 |
| 309 *data = static_cast<uint8_t*>(env->GetDirectBufferAddress(j_buffer.obj())); |
| 310 *capacity = |
| 311 base::checked_cast<size_t>(env->GetDirectBufferCapacity(j_buffer.obj())); |
| 312 return MEDIA_CODEC_OK; |
35 } | 313 } |
36 | 314 |
37 MediaCodecStatus MediaCodecBridge::CopyFromOutputBuffer(int index, | 315 MediaCodecStatus MediaCodecBridge::CopyFromOutputBuffer(int index, |
38 size_t offset, | 316 size_t offset, |
39 void* dst, | 317 void* dst, |
40 size_t num) { | 318 size_t num) { |
41 const uint8_t* src_data = nullptr; | 319 const uint8_t* src_data = nullptr; |
42 size_t src_capacity = 0; | 320 size_t src_capacity = 0; |
43 MediaCodecStatus status = | 321 MediaCodecStatus status = |
44 GetOutputBufferAddress(index, offset, &src_data, &src_capacity); | 322 GetOutputBufferAddress(index, offset, &src_data, &src_capacity); |
45 if (status == MEDIA_CODEC_OK) { | 323 if (status == MEDIA_CODEC_OK) { |
46 CHECK_GE(src_capacity, num); | 324 CHECK_GE(src_capacity, num); |
47 memcpy(dst, src_data, num); | 325 memcpy(dst, src_data, num); |
48 } | 326 } |
49 return status; | 327 return status; |
50 } | 328 } |
51 | 329 |
| 330 MediaCodecStatus MediaCodecBridge::GetOutputBufferAddress(int index, |
| 331 size_t offset, |
| 332 const uint8_t** addr, |
| 333 size_t* capacity) { |
| 334 JNIEnv* env = AttachCurrentThread(); |
| 335 ScopedJavaLocalRef<jobject> j_buffer( |
| 336 Java_MediaCodecBridge_getOutputBuffer(env, j_media_codec_, index)); |
| 337 if (j_buffer.is_null()) |
| 338 return MEDIA_CODEC_ERROR; |
| 339 const size_t total_capacity = env->GetDirectBufferCapacity(j_buffer.obj()); |
| 340 CHECK_GE(total_capacity, offset); |
| 341 *addr = reinterpret_cast<const uint8_t*>( |
| 342 env->GetDirectBufferAddress(j_buffer.obj())) + |
| 343 offset; |
| 344 *capacity = total_capacity - offset; |
| 345 return MEDIA_CODEC_OK; |
| 346 } |
| 347 |
| 348 std::string MediaCodecBridge::GetName() { |
| 349 if (base::android::BuildInfo::GetInstance()->sdk_int() < 18) |
| 350 return ""; |
| 351 JNIEnv* env = AttachCurrentThread(); |
| 352 ScopedJavaLocalRef<jstring> j_name = |
| 353 Java_MediaCodecBridge_getName(env, j_media_codec_); |
| 354 return ConvertJavaStringToUTF8(env, j_name); |
| 355 } |
| 356 |
52 bool MediaCodecBridge::FillInputBuffer(int index, | 357 bool MediaCodecBridge::FillInputBuffer(int index, |
53 const uint8_t* data, | 358 const uint8_t* data, |
54 size_t size) { | 359 size_t size) { |
55 uint8_t* dst = nullptr; | 360 uint8_t* dst = nullptr; |
56 size_t capacity = 0; | 361 size_t capacity = 0; |
57 if (GetInputBuffer(index, &dst, &capacity) != MEDIA_CODEC_OK) { | 362 if (GetInputBuffer(index, &dst, &capacity) != MEDIA_CODEC_OK) { |
58 LOG(ERROR) << "GetInputBuffer failed"; | 363 LOG(ERROR) << "GetInputBuffer failed"; |
59 return false; | 364 return false; |
60 } | 365 } |
61 CHECK(dst); | 366 CHECK(dst); |
62 | 367 |
63 if (size > capacity) { | 368 if (size > capacity) { |
64 LOG(ERROR) << "Input buffer size " << size | 369 LOG(ERROR) << "Input buffer size " << size |
65 << " exceeds MediaCodec input buffer capacity: " << capacity; | 370 << " exceeds MediaCodec input buffer capacity: " << capacity; |
66 return false; | 371 return false; |
67 } | 372 } |
68 | 373 |
69 memcpy(dst, data, size); | 374 memcpy(dst, data, size); |
70 return true; | 375 return true; |
71 } | 376 } |
72 | 377 |
| 378 // static |
| 379 AudioCodecBridge* AudioCodecBridge::Create(const AudioCodec& codec) { |
| 380 if (!MediaCodecUtil::IsMediaCodecAvailable()) |
| 381 return nullptr; |
| 382 |
| 383 const std::string mime = AudioCodecToAndroidMimeType(codec); |
| 384 if (mime.empty()) |
| 385 return nullptr; |
| 386 |
| 387 std::unique_ptr<AudioCodecBridge> bridge(new AudioCodecBridge(mime)); |
| 388 if (!bridge->media_codec()) |
| 389 return nullptr; |
| 390 |
| 391 return bridge.release(); |
| 392 } |
| 393 |
| 394 // static |
| 395 bool AudioCodecBridge::IsKnownUnaccelerated(const AudioCodec& codec) { |
| 396 return MediaCodecUtil::IsKnownUnaccelerated( |
| 397 AudioCodecToAndroidMimeType(codec), MEDIA_CODEC_DECODER); |
| 398 } |
| 399 |
| 400 AudioCodecBridge::AudioCodecBridge(const std::string& mime) |
| 401 // Audio codec doesn't care about security level and there is no need for |
| 402 // audio encoding yet. |
| 403 : MediaCodecBridge(mime, false, MEDIA_CODEC_DECODER, false) {} |
| 404 |
| 405 bool AudioCodecBridge::ConfigureAndStart(const AudioDecoderConfig& config, |
| 406 jobject media_crypto) { |
| 407 const int channel_count = |
| 408 ChannelLayoutToChannelCount(config.channel_layout()); |
| 409 const int64_t codec_delay_ns = base::Time::kNanosecondsPerSecond * |
| 410 config.codec_delay() / |
| 411 config.samples_per_second(); |
| 412 const int64_t seek_preroll_ns = |
| 413 1000LL * config.seek_preroll().InMicroseconds(); |
| 414 |
| 415 return ConfigureAndStart(config.codec(), config.samples_per_second(), |
| 416 channel_count, config.extra_data().data(), |
| 417 config.extra_data().size(), codec_delay_ns, |
| 418 seek_preroll_ns, media_crypto); |
| 419 } |
| 420 |
| 421 bool AudioCodecBridge::ConfigureAndStart(const AudioCodec& codec, |
| 422 int sample_rate, |
| 423 int channel_count, |
| 424 const uint8_t* extra_data, |
| 425 size_t extra_data_size, |
| 426 int64_t codec_delay_ns, |
| 427 int64_t seek_preroll_ns, |
| 428 jobject media_crypto) { |
| 429 DVLOG(2) << __func__ << ": " |
| 430 << " codec:" << GetCodecName(codec) |
| 431 << " samples_per_second:" << sample_rate |
| 432 << " channel_count:" << channel_count |
| 433 << " codec_delay_ns:" << codec_delay_ns |
| 434 << " seek_preroll_ns:" << seek_preroll_ns |
| 435 << " extra data size:" << extra_data_size |
| 436 << " media_crypto:" << media_crypto; |
| 437 DCHECK(media_codec()); |
| 438 |
| 439 std::string codec_string = AudioCodecToAndroidMimeType(codec); |
| 440 if (codec_string.empty()) |
| 441 return false; |
| 442 |
| 443 JNIEnv* env = AttachCurrentThread(); |
| 444 |
| 445 ScopedJavaLocalRef<jstring> j_mime = |
| 446 ConvertUTF8ToJavaString(env, codec_string); |
| 447 ScopedJavaLocalRef<jobject> j_format(Java_MediaCodecBridge_createAudioFormat( |
| 448 env, j_mime, sample_rate, channel_count)); |
| 449 DCHECK(!j_format.is_null()); |
| 450 |
| 451 if (!ConfigureMediaFormat(j_format.obj(), codec, extra_data, extra_data_size, |
| 452 codec_delay_ns, seek_preroll_ns)) { |
| 453 return false; |
| 454 } |
| 455 |
| 456 if (!Java_MediaCodecBridge_configureAudio(env, media_codec(), j_format, |
| 457 media_crypto, 0)) { |
| 458 return false; |
| 459 } |
| 460 |
| 461 return Start(); |
| 462 } |
| 463 |
| 464 bool AudioCodecBridge::ConfigureMediaFormat(jobject j_format, |
| 465 const AudioCodec& codec, |
| 466 const uint8_t* extra_data, |
| 467 size_t extra_data_size, |
| 468 int64_t codec_delay_ns, |
| 469 int64_t seek_preroll_ns) { |
| 470 if (extra_data_size == 0 && codec != kCodecOpus) |
| 471 return true; |
| 472 |
| 473 JNIEnv* env = AttachCurrentThread(); |
| 474 switch (codec) { |
| 475 case kCodecVorbis: { |
| 476 if (extra_data[0] != 2) { |
| 477 LOG(ERROR) << "Invalid number of vorbis headers before the codec " |
| 478 << "header: " << extra_data[0]; |
| 479 return false; |
| 480 } |
| 481 |
| 482 size_t header_length[2]; |
| 483 // |total_length| keeps track of the total number of bytes before the last |
| 484 // header. |
| 485 size_t total_length = 1; |
| 486 const uint8_t* current_pos = extra_data; |
| 487 // Calculate the length of the first 2 headers. |
| 488 for (int i = 0; i < 2; ++i) { |
| 489 header_length[i] = 0; |
| 490 while (total_length < extra_data_size) { |
| 491 size_t size = *(++current_pos); |
| 492 total_length += 1 + size; |
| 493 if (total_length > 0x80000000) { |
| 494 LOG(ERROR) << "Vorbis header size too large"; |
| 495 return false; |
| 496 } |
| 497 header_length[i] += size; |
| 498 if (size < 0xFF) |
| 499 break; |
| 500 } |
| 501 if (total_length >= extra_data_size) { |
| 502 LOG(ERROR) << "Invalid vorbis header size in the extra data"; |
| 503 return false; |
| 504 } |
| 505 } |
| 506 current_pos++; |
| 507 // The first header is identification header. |
| 508 ScopedJavaLocalRef<jbyteArray> first_header = |
| 509 base::android::ToJavaByteArray(env, current_pos, header_length[0]); |
| 510 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, |
| 511 first_header); |
| 512 // The last header is codec header. |
| 513 ScopedJavaLocalRef<jbyteArray> last_header = |
| 514 base::android::ToJavaByteArray(env, extra_data + total_length, |
| 515 extra_data_size - total_length); |
| 516 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, last_header); |
| 517 break; |
| 518 } |
| 519 case kCodecAAC: { |
| 520 media::BitReader reader(extra_data, extra_data_size); |
| 521 |
| 522 // The following code is copied from aac.cc |
| 523 // TODO(qinmin): refactor the code in aac.cc to make it more reusable. |
| 524 uint8_t profile = 0; |
| 525 uint8_t frequency_index = 0; |
| 526 uint8_t channel_config = 0; |
| 527 RETURN_ON_ERROR(reader.ReadBits(5, &profile)); |
| 528 RETURN_ON_ERROR(reader.ReadBits(4, &frequency_index)); |
| 529 |
| 530 if (0xf == frequency_index) |
| 531 RETURN_ON_ERROR(reader.SkipBits(24)); |
| 532 RETURN_ON_ERROR(reader.ReadBits(4, &channel_config)); |
| 533 |
| 534 if (profile == 5 || profile == 29) { |
| 535 // Read extension config. |
| 536 RETURN_ON_ERROR(reader.ReadBits(4, &frequency_index)); |
| 537 if (frequency_index == 0xf) |
| 538 RETURN_ON_ERROR(reader.SkipBits(24)); |
| 539 RETURN_ON_ERROR(reader.ReadBits(5, &profile)); |
| 540 } |
| 541 |
| 542 if (profile < 1 || profile > 4 || frequency_index == 0xf || |
| 543 channel_config > 7) { |
| 544 LOG(ERROR) << "Invalid AAC header"; |
| 545 return false; |
| 546 } |
| 547 |
| 548 const size_t kCsdLength = 2; |
| 549 uint8_t csd[kCsdLength]; |
| 550 csd[0] = profile << 3 | frequency_index >> 1; |
| 551 csd[1] = (frequency_index & 0x01) << 7 | channel_config << 3; |
| 552 ScopedJavaLocalRef<jbyteArray> byte_array = |
| 553 base::android::ToJavaByteArray(env, csd, kCsdLength); |
| 554 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, byte_array); |
| 555 |
| 556 // TODO(qinmin): pass an extra variable to this function to determine |
| 557 // whether we need to call this. |
| 558 Java_MediaCodecBridge_setFrameHasADTSHeader(env, j_format); |
| 559 break; |
| 560 } |
| 561 case kCodecOpus: { |
| 562 if (!extra_data || extra_data_size == 0 || codec_delay_ns < 0 || |
| 563 seek_preroll_ns < 0) { |
| 564 LOG(ERROR) << "Invalid Opus Header"; |
| 565 return false; |
| 566 } |
| 567 |
| 568 // csd0 - Opus Header |
| 569 ScopedJavaLocalRef<jbyteArray> csd0 = |
| 570 base::android::ToJavaByteArray(env, extra_data, extra_data_size); |
| 571 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, csd0); |
| 572 |
| 573 // csd1 - Codec Delay |
| 574 ScopedJavaLocalRef<jbyteArray> csd1 = base::android::ToJavaByteArray( |
| 575 env, reinterpret_cast<const uint8_t*>(&codec_delay_ns), |
| 576 sizeof(int64_t)); |
| 577 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, csd1); |
| 578 |
| 579 // csd2 - Seek Preroll |
| 580 ScopedJavaLocalRef<jbyteArray> csd2 = base::android::ToJavaByteArray( |
| 581 env, reinterpret_cast<const uint8_t*>(&seek_preroll_ns), |
| 582 sizeof(int64_t)); |
| 583 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 2, csd2); |
| 584 break; |
| 585 } |
| 586 default: |
| 587 LOG(ERROR) << "Invalid header encountered for codec: " |
| 588 << AudioCodecToAndroidMimeType(codec); |
| 589 return false; |
| 590 } |
| 591 return true; |
| 592 } |
| 593 |
| 594 // static |
| 595 bool VideoCodecBridge::IsKnownUnaccelerated(const VideoCodec& codec, |
| 596 MediaCodecDirection direction) { |
| 597 return MediaCodecUtil::IsKnownUnaccelerated( |
| 598 VideoCodecToAndroidMimeType(codec), direction); |
| 599 } |
| 600 |
| 601 // static |
| 602 VideoCodecBridge* VideoCodecBridge::CreateDecoder( |
| 603 const VideoCodec& codec, |
| 604 bool is_secure, |
| 605 const gfx::Size& size, |
| 606 jobject surface, |
| 607 jobject media_crypto, |
| 608 const std::vector<uint8_t>& csd0, |
| 609 const std::vector<uint8_t>& csd1, |
| 610 bool allow_adaptive_playback, |
| 611 bool require_software_codec) { |
| 612 if (!MediaCodecUtil::IsMediaCodecAvailable()) |
| 613 return nullptr; |
| 614 |
| 615 const std::string mime = VideoCodecToAndroidMimeType(codec); |
| 616 if (mime.empty()) |
| 617 return nullptr; |
| 618 |
| 619 std::unique_ptr<VideoCodecBridge> bridge(new VideoCodecBridge( |
| 620 mime, is_secure, MEDIA_CODEC_DECODER, require_software_codec)); |
| 621 if (!bridge->media_codec()) |
| 622 return nullptr; |
| 623 |
| 624 JNIEnv* env = AttachCurrentThread(); |
| 625 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
| 626 ScopedJavaLocalRef<jobject> j_format( |
| 627 Java_MediaCodecBridge_createVideoDecoderFormat(env, j_mime, size.width(), |
| 628 size.height())); |
| 629 DCHECK(!j_format.is_null()); |
| 630 |
| 631 if (!csd0.empty()) { |
| 632 ScopedJavaLocalRef<jbyteArray> j_csd0 = |
| 633 base::android::ToJavaByteArray(env, csd0.data(), csd0.size()); |
| 634 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 0, j_csd0); |
| 635 } |
| 636 |
| 637 if (!csd1.empty()) { |
| 638 ScopedJavaLocalRef<jbyteArray> j_csd1 = |
| 639 base::android::ToJavaByteArray(env, csd1.data(), csd1.size()); |
| 640 Java_MediaCodecBridge_setCodecSpecificData(env, j_format, 1, j_csd1); |
| 641 } |
| 642 |
| 643 if (!Java_MediaCodecBridge_configureVideo(env, bridge->media_codec(), |
| 644 j_format, surface, media_crypto, 0, |
| 645 allow_adaptive_playback)) { |
| 646 return nullptr; |
| 647 } |
| 648 |
| 649 return bridge->Start() ? bridge.release() : nullptr; |
| 650 } |
| 651 |
| 652 // static |
| 653 VideoCodecBridge* VideoCodecBridge::CreateEncoder(const VideoCodec& codec, |
| 654 const gfx::Size& size, |
| 655 int bit_rate, |
| 656 int frame_rate, |
| 657 int i_frame_interval, |
| 658 int color_format) { |
| 659 if (!MediaCodecUtil::IsMediaCodecAvailable()) |
| 660 return nullptr; |
| 661 |
| 662 const std::string mime = VideoCodecToAndroidMimeType(codec); |
| 663 if (mime.empty()) |
| 664 return nullptr; |
| 665 |
| 666 std::unique_ptr<VideoCodecBridge> bridge( |
| 667 new VideoCodecBridge(mime, false, MEDIA_CODEC_ENCODER, false)); |
| 668 if (!bridge->media_codec()) |
| 669 return nullptr; |
| 670 |
| 671 JNIEnv* env = AttachCurrentThread(); |
| 672 ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime); |
| 673 ScopedJavaLocalRef<jobject> j_format( |
| 674 Java_MediaCodecBridge_createVideoEncoderFormat( |
| 675 env, bridge->media_codec(), j_mime, size.width(), size.height(), |
| 676 bit_rate, frame_rate, i_frame_interval, color_format)); |
| 677 DCHECK(!j_format.is_null()); |
| 678 if (!Java_MediaCodecBridge_configureVideo(env, bridge->media_codec(), |
| 679 j_format, nullptr, nullptr, |
| 680 kConfigureFlagEncode, true)) { |
| 681 return nullptr; |
| 682 } |
| 683 |
| 684 return bridge->Start() ? bridge.release() : nullptr; |
| 685 } |
| 686 |
| 687 VideoCodecBridge::VideoCodecBridge(const std::string& mime, |
| 688 bool is_secure, |
| 689 MediaCodecDirection direction, |
| 690 bool require_software_codec) |
| 691 : MediaCodecBridge(mime, is_secure, direction, require_software_codec), |
| 692 adaptive_playback_supported_for_testing_(-1) {} |
| 693 |
| 694 bool VideoCodecBridge::SetSurface(jobject surface) { |
| 695 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 23); |
| 696 JNIEnv* env = AttachCurrentThread(); |
| 697 return Java_MediaCodecBridge_setSurface(env, media_codec(), surface); |
| 698 } |
| 699 |
| 700 void VideoCodecBridge::SetVideoBitrate(int bps, int frame_rate) { |
| 701 JNIEnv* env = AttachCurrentThread(); |
| 702 Java_MediaCodecBridge_setVideoBitrate(env, media_codec(), bps, frame_rate); |
| 703 } |
| 704 |
| 705 void VideoCodecBridge::RequestKeyFrameSoon() { |
| 706 JNIEnv* env = AttachCurrentThread(); |
| 707 Java_MediaCodecBridge_requestKeyFrameSoon(env, media_codec()); |
| 708 } |
| 709 |
| 710 bool VideoCodecBridge::IsAdaptivePlaybackSupported(int width, int height) { |
| 711 if (adaptive_playback_supported_for_testing_ == 0) |
| 712 return false; |
| 713 else if (adaptive_playback_supported_for_testing_ > 0) |
| 714 return true; |
| 715 JNIEnv* env = AttachCurrentThread(); |
| 716 return Java_MediaCodecBridge_isAdaptivePlaybackSupported(env, media_codec(), |
| 717 width, height); |
| 718 } |
| 719 |
73 } // namespace media | 720 } // namespace media |
OLD | NEW |