1 /*
2 * Copyright 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ACodecBufferChannel"
19 #include <utils/Log.h>
20
21 #include <numeric>
22
23 #include <android/media/IDescrambler.h>
24 #include <binder/MemoryDealer.h>
25 #include <media/openmax/OMX_Core.h>
26 #include <media/stagefright/foundation/AMessage.h>
27 #include <media/stagefright/foundation/AUtils.h>
28 #include <media/stagefright/MediaCodec.h>
29 #include <media/MediaCodecBuffer.h>
30 #include <system/window.h>
31
32 #include "include/ACodecBufferChannel.h"
33 #include "include/SecureBuffer.h"
34 #include "include/SharedMemoryBuffer.h"
35
36 namespace android {
37 using binder::Status;
38 using MediaDescrambler::DescrambleInfo;
39 using BufferInfo = ACodecBufferChannel::BufferInfo;
40 using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
41
~ACodecBufferChannel()42 ACodecBufferChannel::~ACodecBufferChannel() {
43 if (mCrypto != nullptr && mDealer != nullptr && mHeapSeqNum >= 0) {
44 mCrypto->unsetHeap(mHeapSeqNum);
45 }
46 }
47
findClientBuffer(const std::shared_ptr<const std::vector<const BufferInfo>> & array,const sp<MediaCodecBuffer> & buffer)48 static BufferInfoIterator findClientBuffer(
49 const std::shared_ptr<const std::vector<const BufferInfo>> &array,
50 const sp<MediaCodecBuffer> &buffer) {
51 return std::find_if(
52 array->begin(), array->end(),
53 [buffer](const BufferInfo &info) { return info.mClientBuffer == buffer; });
54 }
55
findBufferId(const std::shared_ptr<const std::vector<const BufferInfo>> & array,IOMX::buffer_id bufferId)56 static BufferInfoIterator findBufferId(
57 const std::shared_ptr<const std::vector<const BufferInfo>> &array,
58 IOMX::buffer_id bufferId) {
59 return std::find_if(
60 array->begin(), array->end(),
61 [bufferId](const BufferInfo &info) { return bufferId == info.mBufferId; });
62 }
63
BufferInfo(const sp<MediaCodecBuffer> & buffer,IOMX::buffer_id bufferId,const sp<IMemory> & sharedEncryptedBuffer)64 ACodecBufferChannel::BufferInfo::BufferInfo(
65 const sp<MediaCodecBuffer> &buffer,
66 IOMX::buffer_id bufferId,
67 const sp<IMemory> &sharedEncryptedBuffer)
68 : mClientBuffer(
69 (sharedEncryptedBuffer == nullptr)
70 ? buffer
71 : new SharedMemoryBuffer(buffer->format(), sharedEncryptedBuffer)),
72 mCodecBuffer(buffer),
73 mBufferId(bufferId),
74 mSharedEncryptedBuffer(sharedEncryptedBuffer) {
75 }
76
ACodecBufferChannel(const sp<AMessage> & inputBufferFilled,const sp<AMessage> & outputBufferDrained)77 ACodecBufferChannel::ACodecBufferChannel(
78 const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained)
79 : mInputBufferFilled(inputBufferFilled),
80 mOutputBufferDrained(outputBufferDrained),
81 mHeapSeqNum(-1) {
82 }
83
queueInputBuffer(const sp<MediaCodecBuffer> & buffer)84 status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
85 if (mDealer != nullptr) {
86 return -ENOSYS;
87 }
88 std::shared_ptr<const std::vector<const BufferInfo>> array(
89 std::atomic_load(&mInputBuffers));
90 BufferInfoIterator it = findClientBuffer(array, buffer);
91 if (it == array->end()) {
92 return -ENOENT;
93 }
94 ALOGV("queueInputBuffer #%d", it->mBufferId);
95 sp<AMessage> msg = mInputBufferFilled->dup();
96 msg->setObject("buffer", it->mCodecBuffer);
97 msg->setInt32("buffer-id", it->mBufferId);
98 msg->post();
99 return OK;
100 }
101
queueSecureInputBuffer(const sp<MediaCodecBuffer> & buffer,bool secure,const uint8_t * key,const uint8_t * iv,CryptoPlugin::Mode mode,CryptoPlugin::Pattern pattern,const CryptoPlugin::SubSample * subSamples,size_t numSubSamples,AString * errorDetailMsg)102 status_t ACodecBufferChannel::queueSecureInputBuffer(
103 const sp<MediaCodecBuffer> &buffer, bool secure, const uint8_t *key,
104 const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern,
105 const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
106 AString *errorDetailMsg) {
107 if (!hasCryptoOrDescrambler() || mDealer == nullptr) {
108 return -ENOSYS;
109 }
110 std::shared_ptr<const std::vector<const BufferInfo>> array(
111 std::atomic_load(&mInputBuffers));
112 BufferInfoIterator it = findClientBuffer(array, buffer);
113 if (it == array->end()) {
114 return -ENOENT;
115 }
116
117 ICrypto::DestinationBuffer destination;
118 if (secure) {
119 sp<SecureBuffer> secureData =
120 static_cast<SecureBuffer *>(it->mCodecBuffer.get());
121 destination.mType = secureData->getDestinationType();
122 if (destination.mType != ICrypto::kDestinationTypeNativeHandle) {
123 return BAD_VALUE;
124 }
125 destination.mHandle =
126 static_cast<native_handle_t *>(secureData->getDestinationPointer());
127 } else {
128 destination.mType = ICrypto::kDestinationTypeSharedMemory;
129 destination.mSharedMemory = mDecryptDestination;
130 }
131
132 ICrypto::SourceBuffer source;
133 source.mSharedMemory = it->mSharedEncryptedBuffer;
134 source.mHeapSeqNum = mHeapSeqNum;
135
136 ssize_t result = -1;
137 if (mCrypto != NULL) {
138 result = mCrypto->decrypt(key, iv, mode, pattern,
139 source, it->mClientBuffer->offset(),
140 subSamples, numSubSamples, destination, errorDetailMsg);
141 } else {
142 DescrambleInfo descrambleInfo;
143 descrambleInfo.dstType = destination.mType ==
144 ICrypto::kDestinationTypeSharedMemory ?
145 DescrambleInfo::kDestinationTypeVmPointer :
146 DescrambleInfo::kDestinationTypeNativeHandle;
147 descrambleInfo.scramblingControl = key != NULL ?
148 (DescramblerPlugin::ScramblingControl)key[0] :
149 DescramblerPlugin::kScrambling_Unscrambled;
150 descrambleInfo.numSubSamples = numSubSamples;
151 descrambleInfo.subSamples = (DescramblerPlugin::SubSample *)subSamples;
152 descrambleInfo.srcMem = it->mSharedEncryptedBuffer;
153 descrambleInfo.srcOffset = 0;
154 descrambleInfo.dstPtr = NULL;
155 descrambleInfo.dstOffset = 0;
156
157 int32_t descrambleResult = -1;
158 Status status = mDescrambler->descramble(descrambleInfo, &descrambleResult);
159
160 if (status.isOk()) {
161 result = descrambleResult;
162 }
163
164 if (result < 0) {
165 ALOGE("descramble failed, exceptionCode=%d, err=%d, result=%zd",
166 status.exceptionCode(), status.transactionError(), result);
167 } else {
168 ALOGV("descramble succeeded, result=%zd", result);
169 }
170
171 if (result > 0 && destination.mType == ICrypto::kDestinationTypeSharedMemory) {
172 memcpy(destination.mSharedMemory->pointer(),
173 (uint8_t*)it->mSharedEncryptedBuffer->pointer(), result);
174 }
175 }
176
177 if (result < 0) {
178 return result;
179 }
180
181 if (destination.mType == ICrypto::kDestinationTypeSharedMemory) {
182 memcpy(it->mCodecBuffer->base(), destination.mSharedMemory->pointer(), result);
183 }
184
185 it->mCodecBuffer->setRange(0, result);
186
187 // Copy metadata from client to codec buffer.
188 it->mCodecBuffer->meta()->clear();
189 int64_t timeUs;
190 CHECK(it->mClientBuffer->meta()->findInt64("timeUs", &timeUs));
191 it->mCodecBuffer->meta()->setInt64("timeUs", timeUs);
192 int32_t eos;
193 if (it->mClientBuffer->meta()->findInt32("eos", &eos)) {
194 it->mCodecBuffer->meta()->setInt32("eos", eos);
195 }
196 int32_t csd;
197 if (it->mClientBuffer->meta()->findInt32("csd", &csd)) {
198 it->mCodecBuffer->meta()->setInt32("csd", csd);
199 }
200
201 ALOGV("queueSecureInputBuffer #%d", it->mBufferId);
202 sp<AMessage> msg = mInputBufferFilled->dup();
203 msg->setObject("buffer", it->mCodecBuffer);
204 msg->setInt32("buffer-id", it->mBufferId);
205 msg->post();
206 return OK;
207 }
208
renderOutputBuffer(const sp<MediaCodecBuffer> & buffer,int64_t timestampNs)209 status_t ACodecBufferChannel::renderOutputBuffer(
210 const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
211 std::shared_ptr<const std::vector<const BufferInfo>> array(
212 std::atomic_load(&mOutputBuffers));
213 BufferInfoIterator it = findClientBuffer(array, buffer);
214 if (it == array->end()) {
215 return -ENOENT;
216 }
217
218 ALOGV("renderOutputBuffer #%d", it->mBufferId);
219 sp<AMessage> msg = mOutputBufferDrained->dup();
220 msg->setObject("buffer", buffer);
221 msg->setInt32("buffer-id", it->mBufferId);
222 msg->setInt32("render", true);
223 msg->setInt64("timestampNs", timestampNs);
224 msg->post();
225 return OK;
226 }
227
discardBuffer(const sp<MediaCodecBuffer> & buffer)228 status_t ACodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
229 std::shared_ptr<const std::vector<const BufferInfo>> array(
230 std::atomic_load(&mInputBuffers));
231 bool input = true;
232 BufferInfoIterator it = findClientBuffer(array, buffer);
233 if (it == array->end()) {
234 array = std::atomic_load(&mOutputBuffers);
235 input = false;
236 it = findClientBuffer(array, buffer);
237 if (it == array->end()) {
238 return -ENOENT;
239 }
240 }
241 ALOGV("discardBuffer #%d", it->mBufferId);
242 sp<AMessage> msg = input ? mInputBufferFilled->dup() : mOutputBufferDrained->dup();
243 msg->setObject("buffer", it->mCodecBuffer);
244 msg->setInt32("buffer-id", it->mBufferId);
245 msg->setInt32("discarded", true);
246 msg->post();
247 return OK;
248 }
249
getInputBufferArray(Vector<sp<MediaCodecBuffer>> * array)250 void ACodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
251 std::shared_ptr<const std::vector<const BufferInfo>> inputBuffers(
252 std::atomic_load(&mInputBuffers));
253 array->clear();
254 for (const BufferInfo &elem : *inputBuffers) {
255 array->push_back(elem.mClientBuffer);
256 }
257 }
258
getOutputBufferArray(Vector<sp<MediaCodecBuffer>> * array)259 void ACodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
260 std::shared_ptr<const std::vector<const BufferInfo>> outputBuffers(
261 std::atomic_load(&mOutputBuffers));
262 array->clear();
263 for (const BufferInfo &elem : *outputBuffers) {
264 array->push_back(elem.mClientBuffer);
265 }
266 }
267
makeMemoryDealer(size_t heapSize)268 sp<MemoryDealer> ACodecBufferChannel::makeMemoryDealer(size_t heapSize) {
269 sp<MemoryDealer> dealer;
270 if (mDealer != nullptr && mCrypto != nullptr && mHeapSeqNum >= 0) {
271 mCrypto->unsetHeap(mHeapSeqNum);
272 }
273 dealer = new MemoryDealer(heapSize, "ACodecBufferChannel");
274 if (mCrypto != nullptr) {
275 int32_t seqNum = mCrypto->setHeap(dealer->getMemoryHeap());
276 if (seqNum >= 0) {
277 mHeapSeqNum = seqNum;
278 ALOGD("setHeap returned mHeapSeqNum=%d", mHeapSeqNum);
279 } else {
280 mHeapSeqNum = -1;
281 ALOGD("setHeap failed, setting mHeapSeqNum=-1");
282 }
283 }
284 return dealer;
285 }
286
setInputBufferArray(const std::vector<BufferAndId> & array)287 void ACodecBufferChannel::setInputBufferArray(const std::vector<BufferAndId> &array) {
288 if (hasCryptoOrDescrambler()) {
289 size_t totalSize = std::accumulate(
290 array.begin(), array.end(), 0u,
291 [alignment = MemoryDealer::getAllocationAlignment()]
292 (size_t sum, const BufferAndId& elem) {
293 return sum + align(elem.mBuffer->capacity(), alignment);
294 });
295 size_t maxSize = std::accumulate(
296 array.begin(), array.end(), 0u,
297 [alignment = MemoryDealer::getAllocationAlignment()]
298 (size_t max, const BufferAndId& elem) {
299 return std::max(max, align(elem.mBuffer->capacity(), alignment));
300 });
301 size_t destinationBufferSize = maxSize;
302 size_t heapSize = totalSize + destinationBufferSize;
303 if (heapSize > 0) {
304 mDealer = makeMemoryDealer(heapSize);
305 mDecryptDestination = mDealer->allocate(destinationBufferSize);
306 }
307 }
308 std::vector<const BufferInfo> inputBuffers;
309 for (const BufferAndId &elem : array) {
310 sp<IMemory> sharedEncryptedBuffer;
311 if (hasCryptoOrDescrambler()) {
312 sharedEncryptedBuffer = mDealer->allocate(elem.mBuffer->capacity());
313 }
314 inputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, sharedEncryptedBuffer);
315 }
316 std::atomic_store(
317 &mInputBuffers,
318 std::make_shared<const std::vector<const BufferInfo>>(inputBuffers));
319 }
320
setOutputBufferArray(const std::vector<BufferAndId> & array)321 void ACodecBufferChannel::setOutputBufferArray(const std::vector<BufferAndId> &array) {
322 std::vector<const BufferInfo> outputBuffers;
323 for (const BufferAndId &elem : array) {
324 outputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, nullptr);
325 }
326 std::atomic_store(
327 &mOutputBuffers,
328 std::make_shared<const std::vector<const BufferInfo>>(outputBuffers));
329 }
330
fillThisBuffer(IOMX::buffer_id bufferId)331 void ACodecBufferChannel::fillThisBuffer(IOMX::buffer_id bufferId) {
332 ALOGV("fillThisBuffer #%d", bufferId);
333 std::shared_ptr<const std::vector<const BufferInfo>> array(
334 std::atomic_load(&mInputBuffers));
335 BufferInfoIterator it = findBufferId(array, bufferId);
336
337 if (it == array->end()) {
338 ALOGE("fillThisBuffer: unrecognized buffer #%d", bufferId);
339 return;
340 }
341 if (it->mClientBuffer != it->mCodecBuffer) {
342 it->mClientBuffer->setFormat(it->mCodecBuffer->format());
343 }
344
345 mCallback->onInputBufferAvailable(
346 std::distance(array->begin(), it),
347 it->mClientBuffer);
348 }
349
drainThisBuffer(IOMX::buffer_id bufferId,OMX_U32 omxFlags)350 void ACodecBufferChannel::drainThisBuffer(
351 IOMX::buffer_id bufferId,
352 OMX_U32 omxFlags) {
353 ALOGV("drainThisBuffer #%d", bufferId);
354 std::shared_ptr<const std::vector<const BufferInfo>> array(
355 std::atomic_load(&mOutputBuffers));
356 BufferInfoIterator it = findBufferId(array, bufferId);
357
358 if (it == array->end()) {
359 ALOGE("drainThisBuffer: unrecognized buffer #%d", bufferId);
360 return;
361 }
362 if (it->mClientBuffer != it->mCodecBuffer) {
363 it->mClientBuffer->setFormat(it->mCodecBuffer->format());
364 }
365
366 uint32_t flags = 0;
367 if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
368 flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME;
369 }
370 if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
371 flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
372 }
373 if (omxFlags & OMX_BUFFERFLAG_EOS) {
374 flags |= MediaCodec::BUFFER_FLAG_EOS;
375 }
376 it->mClientBuffer->meta()->setInt32("flags", flags);
377
378 mCallback->onOutputBufferAvailable(
379 std::distance(array->begin(), it),
380 it->mClientBuffer);
381 }
382
383 } // namespace android
384