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