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