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