ACodecBufferChannel.cpp revision 3c2c5556f44765abe7e3dc25584a2ccb316a9b14
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
36namespace android {
37using binder::Status;
38using MediaDescrambler::DescrambleInfo;
39using BufferInfo = ACodecBufferChannel::BufferInfo;
40using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
41
42static BufferInfoIterator findClientBuffer(
43        const std::shared_ptr<const std::vector<const BufferInfo>> &array,
44        const sp<MediaCodecBuffer> &buffer) {
45    return std::find_if(
46            array->begin(), array->end(),
47            [buffer](const BufferInfo &info) { return info.mClientBuffer == buffer; });
48}
49
50static BufferInfoIterator findBufferId(
51        const std::shared_ptr<const std::vector<const BufferInfo>> &array,
52        IOMX::buffer_id bufferId) {
53    return std::find_if(
54            array->begin(), array->end(),
55            [bufferId](const BufferInfo &info) { return bufferId == info.mBufferId; });
56}
57
58ACodecBufferChannel::BufferInfo::BufferInfo(
59        const sp<MediaCodecBuffer> &buffer,
60        IOMX::buffer_id bufferId,
61        const sp<IMemory> &sharedEncryptedBuffer)
62    : mClientBuffer(
63          (sharedEncryptedBuffer == nullptr)
64          ? buffer
65          : new SharedMemoryBuffer(buffer->format(), sharedEncryptedBuffer)),
66      mCodecBuffer(buffer),
67      mBufferId(bufferId),
68      mSharedEncryptedBuffer(sharedEncryptedBuffer) {
69}
70
71ACodecBufferChannel::ACodecBufferChannel(
72        const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained)
73    : mInputBufferFilled(inputBufferFilled),
74      mOutputBufferDrained(outputBufferDrained) {
75}
76
77status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
78    if (mDealer != nullptr) {
79        return -ENOSYS;
80    }
81    std::shared_ptr<const std::vector<const BufferInfo>> array(
82            std::atomic_load(&mInputBuffers));
83    BufferInfoIterator it = findClientBuffer(array, buffer);
84    if (it == array->end()) {
85        return -ENOENT;
86    }
87    ALOGV("queueInputBuffer #%d", it->mBufferId);
88    sp<AMessage> msg = mInputBufferFilled->dup();
89    msg->setObject("buffer", it->mCodecBuffer);
90    msg->setInt32("buffer-id", it->mBufferId);
91    msg->post();
92    return OK;
93}
94
95status_t ACodecBufferChannel::queueSecureInputBuffer(
96        const sp<MediaCodecBuffer> &buffer, bool secure, const uint8_t *key,
97        const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern,
98        const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
99        AString *errorDetailMsg) {
100    if (!hasCryptoOrDescrambler() || mDealer == nullptr) {
101        return -ENOSYS;
102    }
103    std::shared_ptr<const std::vector<const BufferInfo>> array(
104            std::atomic_load(&mInputBuffers));
105    BufferInfoIterator it = findClientBuffer(array, buffer);
106    if (it == array->end()) {
107        return -ENOENT;
108    }
109
110    ICrypto::DestinationBuffer destination;
111    if (secure) {
112        sp<SecureBuffer> secureData =
113                static_cast<SecureBuffer *>(it->mCodecBuffer.get());
114        destination.mType = secureData->getDestinationType();
115        if (destination.mType != ICrypto::kDestinationTypeNativeHandle) {
116            return BAD_VALUE;
117        }
118        destination.mHandle =
119                static_cast<native_handle_t *>(secureData->getDestinationPointer());
120    } else {
121        destination.mType = ICrypto::kDestinationTypeSharedMemory;
122        destination.mSharedMemory = mDecryptDestination;
123    }
124
125    ssize_t result = -1;
126    if (mCrypto != NULL) {
127        result = mCrypto->decrypt(key, iv, mode, pattern,
128                    it->mSharedEncryptedBuffer, it->mClientBuffer->offset(),
129                    subSamples, numSubSamples, destination, errorDetailMsg);
130    } else {
131        DescrambleInfo descrambleInfo;
132        descrambleInfo.dstType = destination.mType ==
133                ICrypto::kDestinationTypeSharedMemory ?
134                DescrambleInfo::kDestinationTypeVmPointer :
135                DescrambleInfo::kDestinationTypeNativeHandle;
136        descrambleInfo.scramblingControl = key != NULL ?
137                (DescramblerPlugin::ScramblingControl)key[0] :
138                DescramblerPlugin::kScrambling_Unscrambled;
139        descrambleInfo.numSubSamples = numSubSamples;
140        descrambleInfo.subSamples = (DescramblerPlugin::SubSample *)subSamples;
141        descrambleInfo.srcMem = it->mSharedEncryptedBuffer;
142        descrambleInfo.srcOffset = 0;
143        descrambleInfo.dstPtr = NULL;
144        descrambleInfo.dstOffset = 0;
145
146        int32_t descrambleResult = -1;
147        Status status = mDescrambler->descramble(descrambleInfo, &descrambleResult);
148
149        if (status.isOk()) {
150            result = descrambleResult;
151        }
152
153        if (result < 0) {
154            ALOGE("descramble failed, exceptionCode=%d, err=%d, result=%zd",
155                    status.exceptionCode(), status.transactionError(), result);
156        } else {
157            ALOGV("descramble succeeded, result=%zd", result);
158        }
159
160        if (result > 0 && destination.mType == ICrypto::kDestinationTypeSharedMemory) {
161            memcpy(destination.mSharedMemory->pointer(),
162                    (uint8_t*)it->mSharedEncryptedBuffer->pointer(), result);
163        }
164    }
165
166    if (result < 0) {
167        return result;
168    }
169
170    if (destination.mType == ICrypto::kDestinationTypeSharedMemory) {
171        memcpy(it->mCodecBuffer->base(), destination.mSharedMemory->pointer(), result);
172    }
173
174    it->mCodecBuffer->setRange(0, result);
175
176    // Copy metadata from client to codec buffer.
177    it->mCodecBuffer->meta()->clear();
178    int64_t timeUs;
179    CHECK(it->mClientBuffer->meta()->findInt64("timeUs", &timeUs));
180    it->mCodecBuffer->meta()->setInt64("timeUs", timeUs);
181    int32_t eos;
182    if (it->mClientBuffer->meta()->findInt32("eos", &eos)) {
183        it->mCodecBuffer->meta()->setInt32("eos", eos);
184    }
185    int32_t csd;
186    if (it->mClientBuffer->meta()->findInt32("csd", &csd)) {
187        it->mCodecBuffer->meta()->setInt32("csd", csd);
188    }
189
190    ALOGV("queueSecureInputBuffer #%d", it->mBufferId);
191    sp<AMessage> msg = mInputBufferFilled->dup();
192    msg->setObject("buffer", it->mCodecBuffer);
193    msg->setInt32("buffer-id", it->mBufferId);
194    msg->post();
195    return OK;
196}
197
198status_t ACodecBufferChannel::renderOutputBuffer(
199        const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
200    std::shared_ptr<const std::vector<const BufferInfo>> array(
201            std::atomic_load(&mOutputBuffers));
202    BufferInfoIterator it = findClientBuffer(array, buffer);
203    if (it == array->end()) {
204        return -ENOENT;
205    }
206
207    ALOGV("renderOutputBuffer #%d", it->mBufferId);
208    sp<AMessage> msg = mOutputBufferDrained->dup();
209    msg->setObject("buffer", buffer);
210    msg->setInt32("buffer-id", it->mBufferId);
211    msg->setInt32("render", true);
212    msg->setInt64("timestampNs", timestampNs);
213    msg->post();
214    return OK;
215}
216
217status_t ACodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
218    std::shared_ptr<const std::vector<const BufferInfo>> array(
219            std::atomic_load(&mInputBuffers));
220    bool input = true;
221    BufferInfoIterator it = findClientBuffer(array, buffer);
222    if (it == array->end()) {
223        array = std::atomic_load(&mOutputBuffers);
224        input = false;
225        it = findClientBuffer(array, buffer);
226        if (it == array->end()) {
227            return -ENOENT;
228        }
229    }
230    ALOGV("discardBuffer #%d", it->mBufferId);
231    sp<AMessage> msg = input ? mInputBufferFilled->dup() : mOutputBufferDrained->dup();
232    msg->setObject("buffer", it->mCodecBuffer);
233    msg->setInt32("buffer-id", it->mBufferId);
234    msg->setInt32("discarded", true);
235    msg->post();
236    return OK;
237}
238
239void ACodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
240    std::shared_ptr<const std::vector<const BufferInfo>> inputBuffers(
241            std::atomic_load(&mInputBuffers));
242    array->clear();
243    for (const BufferInfo &elem : *inputBuffers) {
244        array->push_back(elem.mClientBuffer);
245    }
246}
247
248void ACodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
249    std::shared_ptr<const std::vector<const BufferInfo>> outputBuffers(
250            std::atomic_load(&mOutputBuffers));
251    array->clear();
252    for (const BufferInfo &elem : *outputBuffers) {
253        array->push_back(elem.mClientBuffer);
254    }
255}
256
257void ACodecBufferChannel::setInputBufferArray(const std::vector<BufferAndId> &array) {
258    if (hasCryptoOrDescrambler()) {
259        size_t totalSize = std::accumulate(
260                array.begin(), array.end(), 0u,
261                [alignment = MemoryDealer::getAllocationAlignment()]
262                (size_t sum, const BufferAndId& elem) {
263                    return sum + align(elem.mBuffer->capacity(), alignment);
264                });
265        size_t maxSize = std::accumulate(
266                array.begin(), array.end(), 0u,
267                [alignment = MemoryDealer::getAllocationAlignment()]
268                (size_t max, const BufferAndId& elem) {
269                    return std::max(max, align(elem.mBuffer->capacity(), alignment));
270                });
271        mDealer = new MemoryDealer(totalSize + maxSize, "ACodecBufferChannel");
272        mDecryptDestination = mDealer->allocate(maxSize);
273    }
274    std::vector<const BufferInfo> inputBuffers;
275    for (const BufferAndId &elem : array) {
276        sp<IMemory> sharedEncryptedBuffer;
277        if (hasCryptoOrDescrambler()) {
278            sharedEncryptedBuffer = mDealer->allocate(elem.mBuffer->capacity());
279        }
280        inputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, sharedEncryptedBuffer);
281    }
282    std::atomic_store(
283            &mInputBuffers,
284            std::make_shared<const std::vector<const BufferInfo>>(inputBuffers));
285}
286
287void ACodecBufferChannel::setOutputBufferArray(const std::vector<BufferAndId> &array) {
288    std::vector<const BufferInfo> outputBuffers;
289    for (const BufferAndId &elem : array) {
290        outputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, nullptr);
291    }
292    std::atomic_store(
293            &mOutputBuffers,
294            std::make_shared<const std::vector<const BufferInfo>>(outputBuffers));
295}
296
297void ACodecBufferChannel::fillThisBuffer(IOMX::buffer_id bufferId) {
298    ALOGV("fillThisBuffer #%d", bufferId);
299    std::shared_ptr<const std::vector<const BufferInfo>> array(
300            std::atomic_load(&mInputBuffers));
301    BufferInfoIterator it = findBufferId(array, bufferId);
302
303    if (it == array->end()) {
304        ALOGE("fillThisBuffer: unrecognized buffer #%d", bufferId);
305        return;
306    }
307    if (it->mClientBuffer != it->mCodecBuffer) {
308        it->mClientBuffer->setFormat(it->mCodecBuffer->format());
309    }
310
311    mCallback->onInputBufferAvailable(
312            std::distance(array->begin(), it),
313            it->mClientBuffer);
314}
315
316void ACodecBufferChannel::drainThisBuffer(
317        IOMX::buffer_id bufferId,
318        OMX_U32 omxFlags) {
319    ALOGV("drainThisBuffer #%d", bufferId);
320    std::shared_ptr<const std::vector<const BufferInfo>> array(
321            std::atomic_load(&mOutputBuffers));
322    BufferInfoIterator it = findBufferId(array, bufferId);
323
324    if (it == array->end()) {
325        ALOGE("drainThisBuffer: unrecognized buffer #%d", bufferId);
326        return;
327    }
328    if (it->mClientBuffer != it->mCodecBuffer) {
329        it->mClientBuffer->setFormat(it->mCodecBuffer->format());
330    }
331
332    uint32_t flags = 0;
333    if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
334        flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME;
335    }
336    if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
337        flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
338    }
339    if (omxFlags & OMX_BUFFERFLAG_EOS) {
340        flags |= MediaCodec::BUFFER_FLAG_EOS;
341    }
342    it->mClientBuffer->meta()->setInt32("flags", flags);
343
344    mCallback->onOutputBufferAvailable(
345            std::distance(array->begin(), it),
346            it->mClientBuffer);
347}
348
349}  // namespace android
350