| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2015 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/base/android/ndk_media_codec_bridge.h" |
| 6 |
| 7 #include <media/NdkMediaError.h> |
| 8 #include <media/NdkMediaFormat.h> |
| 9 |
| 10 #include <limits> |
| 11 |
| 12 #include "base/files/file_path.h" |
| 13 #include "base/logging.h" |
| 14 #include "base/native_library.h" |
| 15 #include "base/strings/string_util.h" |
| 16 #include "media/base/decrypt_config.h" |
| 17 |
| 18 namespace { |
| 19 const char kMediaFormatKeyCropLeft[] = "crop-left"; |
| 20 const char kMediaFormatKeyCropRight[] = "crop-right"; |
| 21 const char kMediaFormatKeyCropBottom[] = "crop-bottom"; |
| 22 const char kMediaFormatKeyCropTop[] = "crop-top"; |
| 23 } |
| 24 |
| 25 namespace media { |
| 26 |
| 27 // Translate media_status_t to MediaCodecStatus. |
| 28 static MediaCodecStatus TranslateMediaCodecStatus(media_status_t status) { |
| 29 switch (status) { |
| 30 case AMEDIA_OK: |
| 31 return MEDIA_CODEC_OK; |
| 32 case AMEDIA_DRM_NEED_KEY: |
| 33 return MEDIA_CODEC_NO_KEY; |
| 34 default: |
| 35 return MEDIA_CODEC_ERROR; |
| 36 } |
| 37 } |
| 38 |
| 39 NdkMediaCodecBridge::~NdkMediaCodecBridge() {} |
| 40 |
| 41 NdkMediaCodecBridge::NdkMediaCodecBridge(const std::string& mime, |
| 42 bool is_secure, |
| 43 MediaCodecDirection direction) { |
| 44 if (base::StartsWith(mime, "video", base::CompareCase::SENSITIVE) && |
| 45 is_secure && direction == MEDIA_CODEC_DECODER) { |
| 46 // TODO(qinmin): get the secure decoder name from java. |
| 47 NOTIMPLEMENTED(); |
| 48 return; |
| 49 } |
| 50 |
| 51 if (direction == MEDIA_CODEC_DECODER) |
| 52 media_codec_.reset(AMediaCodec_createDecoderByType(mime.c_str())); |
| 53 else |
| 54 media_codec_.reset(AMediaCodec_createEncoderByType(mime.c_str())); |
| 55 } |
| 56 |
| 57 MediaCodecStatus NdkMediaCodecBridge::Reset() { |
| 58 media_status_t status = AMediaCodec_flush(media_codec_.get()); |
| 59 return TranslateMediaCodecStatus(status); |
| 60 } |
| 61 |
| 62 bool NdkMediaCodecBridge::Start() { |
| 63 return AMEDIA_OK == AMediaCodec_start(media_codec_.get()); |
| 64 } |
| 65 |
| 66 void NdkMediaCodecBridge::Stop() { |
| 67 AMediaCodec_stop(media_codec_.get()); |
| 68 } |
| 69 |
| 70 void NdkMediaCodecBridge::GetOutputFormat(int* width, int* height) { |
| 71 AMediaFormat* format = AMediaCodec_getOutputFormat(media_codec_.get()); |
| 72 int left, right, bottom, top; |
| 73 bool has_left = AMediaFormat_getInt32(format, kMediaFormatKeyCropLeft, &left); |
| 74 bool has_right = |
| 75 AMediaFormat_getInt32(format, kMediaFormatKeyCropRight, &right); |
| 76 bool has_bottom = |
| 77 AMediaFormat_getInt32(format, kMediaFormatKeyCropBottom, &bottom); |
| 78 bool has_top = AMediaFormat_getInt32(format, kMediaFormatKeyCropTop, &top); |
| 79 if (has_left && has_right && has_bottom && has_top) { |
| 80 // Use crop size as it is more accurate. right and bottom are inclusive. |
| 81 *width = right - left + 1; |
| 82 *height = top - bottom + 1; |
| 83 } else { |
| 84 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, width); |
| 85 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, height); |
| 86 } |
| 87 } |
| 88 |
| 89 int NdkMediaCodecBridge::GetOutputSamplingRate() { |
| 90 AMediaFormat* format = AMediaCodec_getOutputFormat(media_codec_.get()); |
| 91 int sample_rate = 0; |
| 92 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &sample_rate); |
| 93 DCHECK(sample_rate != 0); |
| 94 return sample_rate; |
| 95 } |
| 96 |
| 97 MediaCodecStatus NdkMediaCodecBridge::QueueInputBuffer( |
| 98 int index, |
| 99 const uint8_t* data, |
| 100 size_t data_size, |
| 101 const base::TimeDelta& presentation_time) { |
| 102 if (data_size > |
| 103 base::checked_cast<size_t>(std::numeric_limits<int32_t>::max())) { |
| 104 return MEDIA_CODEC_ERROR; |
| 105 } |
| 106 if (data && !FillInputBuffer(index, data, data_size)) |
| 107 return MEDIA_CODEC_ERROR; |
| 108 |
| 109 media_status_t status = |
| 110 AMediaCodec_queueInputBuffer(media_codec_.get(), index, 0, data_size, |
| 111 presentation_time.InMicroseconds(), 0); |
| 112 return TranslateMediaCodecStatus(status); |
| 113 } |
| 114 |
| 115 MediaCodecStatus NdkMediaCodecBridge::QueueSecureInputBuffer( |
| 116 int index, |
| 117 const uint8_t* data, |
| 118 size_t data_size, |
| 119 const std::vector<char>& key_id, |
| 120 const std::vector<char>& iv, |
| 121 const SubsampleEntry* subsamples, |
| 122 int subsamples_size, |
| 123 const base::TimeDelta& presentation_time) { |
| 124 if (data_size > |
| 125 base::checked_cast<size_t>(std::numeric_limits<int32_t>::max())) { |
| 126 return MEDIA_CODEC_ERROR; |
| 127 } |
| 128 if (key_id.size() > 16 || iv.size()) |
| 129 return MEDIA_CODEC_ERROR; |
| 130 if (data && !FillInputBuffer(index, data, data_size)) |
| 131 return MEDIA_CODEC_ERROR; |
| 132 |
| 133 int new_subsamples_size = subsamples_size == 0 ? 1 : subsamples_size; |
| 134 std::vector<size_t> clear_data, encrypted_data; |
| 135 if (subsamples_size == 0) { |
| 136 DCHECK(!subsamples); |
| 137 clear_data.push_back(0); |
| 138 encrypted_data.push_back(data_size); |
| 139 } else { |
| 140 DCHECK_GT(subsamples_size, 0); |
| 141 DCHECK(subsamples); |
| 142 for (int i = 0; i < subsamples_size; ++i) { |
| 143 DCHECK(subsamples[i].clear_bytes <= std::numeric_limits<uint16_t>::max()); |
| 144 if (subsamples[i].cypher_bytes > |
| 145 static_cast<int32_t>(std::numeric_limits<int32_t>::max())) { |
| 146 return MEDIA_CODEC_ERROR; |
| 147 } |
| 148 clear_data.push_back(subsamples[i].clear_bytes); |
| 149 encrypted_data.push_back(subsamples[i].cypher_bytes); |
| 150 } |
| 151 } |
| 152 |
| 153 AMediaCodecCryptoInfo* crypto_info = AMediaCodecCryptoInfo_new( |
| 154 new_subsamples_size, |
| 155 reinterpret_cast<uint8_t*>(const_cast<char*>(key_id.data())), |
| 156 reinterpret_cast<uint8_t*>(const_cast<char*>(iv.data())), |
| 157 AMEDIACODECRYPTOINFO_MODE_AES_CTR, clear_data.data(), |
| 158 encrypted_data.data()); |
| 159 |
| 160 media_status_t status = AMediaCodec_queueSecureInputBuffer( |
| 161 media_codec_.get(), index, 0, crypto_info, |
| 162 presentation_time.InMicroseconds(), 0); |
| 163 AMediaCodecCryptoInfo_delete(crypto_info); |
| 164 return TranslateMediaCodecStatus(status); |
| 165 } |
| 166 |
| 167 void NdkMediaCodecBridge::QueueEOS(int input_buffer_index) { |
| 168 AMediaCodec_queueInputBuffer(media_codec_.get(), input_buffer_index, 0, 0, 0, |
| 169 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM); |
| 170 } |
| 171 |
| 172 MediaCodecStatus NdkMediaCodecBridge::DequeueInputBuffer( |
| 173 const base::TimeDelta& timeout, |
| 174 int* index) { |
| 175 *index = AMediaCodec_dequeueInputBuffer(media_codec_.get(), |
| 176 timeout.InMicroseconds()); |
| 177 if (*index >= 0) |
| 178 return MEDIA_CODEC_OK; |
| 179 else if (*index == AMEDIACODEC_INFO_TRY_AGAIN_LATER) |
| 180 return MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER; |
| 181 else |
| 182 return MEDIA_CODEC_ERROR; |
| 183 } |
| 184 |
| 185 MediaCodecStatus NdkMediaCodecBridge::DequeueOutputBuffer( |
| 186 const base::TimeDelta& timeout, |
| 187 int* index, |
| 188 size_t* offset, |
| 189 size_t* size, |
| 190 base::TimeDelta* presentation_time, |
| 191 bool* end_of_stream, |
| 192 bool* key_frame) { |
| 193 AMediaCodecBufferInfo buffer_info; |
| 194 *index = AMediaCodec_dequeueOutputBuffer(media_codec_.get(), &buffer_info, |
| 195 timeout.InMicroseconds()); |
| 196 *offset = buffer_info.offset; |
| 197 *size = buffer_info.size; |
| 198 *presentation_time = |
| 199 base::TimeDelta::FromMicroseconds(buffer_info.presentationTimeUs); |
| 200 if (end_of_stream) |
| 201 *end_of_stream = buffer_info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM; |
| 202 if (key_frame) |
| 203 *key_frame = false; // This is deprecated. |
| 204 if (*index >= 0) |
| 205 return MEDIA_CODEC_OK; |
| 206 else if (*index == AMEDIACODEC_INFO_TRY_AGAIN_LATER) |
| 207 return MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER; |
| 208 else |
| 209 return MEDIA_CODEC_ERROR; |
| 210 } |
| 211 |
| 212 void NdkMediaCodecBridge::ReleaseOutputBuffer(int index, bool render) { |
| 213 AMediaCodec_releaseOutputBuffer(media_codec_.get(), index, render); |
| 214 } |
| 215 |
| 216 void NdkMediaCodecBridge::GetInputBuffer(int input_buffer_index, |
| 217 uint8_t** data, |
| 218 size_t* capacity) { |
| 219 *data = AMediaCodec_getInputBuffer(media_codec_.get(), input_buffer_index, |
| 220 capacity); |
| 221 } |
| 222 |
| 223 bool NdkMediaCodecBridge::CopyFromOutputBuffer(int index, |
| 224 size_t offset, |
| 225 void* dst, |
| 226 int dst_size) { |
| 227 size_t capacity; |
| 228 uint8_t* src_data = |
| 229 AMediaCodec_getOutputBuffer(media_codec_.get(), index, &capacity); |
| 230 |
| 231 if (capacity < offset || capacity - offset < static_cast<size_t>(dst_size)) |
| 232 return false; |
| 233 |
| 234 memcpy(dst, src_data + offset, dst_size); |
| 235 return true; |
| 236 } |
| 237 |
| 238 } // namespace media |
| OLD | NEW |