ACodecBufferChannel.cpp revision 11b72100e02e02b6cd8a6b14cd2068c96dc49b7d
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,
92        bool secure,
93        const uint8_t *key,
94        const uint8_t *iv,
95        CryptoPlugin::Mode mode,
96        CryptoPlugin::Pattern pattern,
97        const CryptoPlugin::SubSample *subSamples,
98        size_t numSubSamples,
99        AString *errorDetailMsg) {
100    if (mCrypto == 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    void *dst_pointer = nullptr;
111    ICrypto::DestinationType dst_type = ICrypto::kDestinationTypeOpaqueHandle;
112
113    if (secure) {
114        sp<SecureBuffer> secureData = static_cast<SecureBuffer *>(it->mCodecBuffer.get());
115        dst_pointer = secureData->getDestinationPointer();
116        dst_type = secureData->getDestinationType();
117    } else {
118        dst_pointer = it->mCodecBuffer->base();
119        dst_type = ICrypto::kDestinationTypeVmPointer;
120    }
121
122    ssize_t result = mCrypto->decrypt(
123            dst_type,
124            key,
125            iv,
126            mode,
127            pattern,
128            it->mSharedEncryptedBuffer,
129            it->mClientBuffer->offset(),
130            subSamples,
131            numSubSamples,
132            dst_pointer,
133            errorDetailMsg);
134
135    if (result < 0) {
136        return result;
137    }
138
139    it->mCodecBuffer->setRange(0, result);
140
141    // Copy metadata from client to codec buffer.
142    it->mCodecBuffer->meta()->clear();
143    int64_t timeUs;
144    CHECK(it->mClientBuffer->meta()->findInt64("timeUs", &timeUs));
145    it->mCodecBuffer->meta()->setInt64("timeUs", timeUs);
146    int32_t eos;
147    if (it->mClientBuffer->meta()->findInt32("eos", &eos)) {
148        it->mCodecBuffer->meta()->setInt32("eos", eos);
149    }
150    int32_t csd;
151    if (it->mClientBuffer->meta()->findInt32("csd", &csd)) {
152        it->mCodecBuffer->meta()->setInt32("csd", csd);
153    }
154
155    ALOGV("queueSecureInputBuffer #%d", it->mBufferId);
156    sp<AMessage> msg = mInputBufferFilled->dup();
157    msg->setObject("buffer", it->mCodecBuffer);
158    msg->setInt32("buffer-id", it->mBufferId);
159    msg->post();
160    return OK;
161}
162
163status_t ACodecBufferChannel::renderOutputBuffer(
164        const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
165    std::shared_ptr<const std::vector<const BufferInfo>> array(
166            std::atomic_load(&mOutputBuffers));
167    BufferInfoIterator it = findClientBuffer(array, buffer);
168    if (it == array->end()) {
169        return -ENOENT;
170    }
171
172    ALOGV("renderOutputBuffer #%d", it->mBufferId);
173    sp<AMessage> msg = mOutputBufferDrained->dup();
174    msg->setObject("buffer", buffer);
175    msg->setInt32("buffer-id", it->mBufferId);
176    msg->setInt32("render", true);
177    msg->setInt64("timestampNs", timestampNs);
178    msg->post();
179    return OK;
180}
181
182status_t ACodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
183    std::shared_ptr<const std::vector<const BufferInfo>> array(
184            std::atomic_load(&mInputBuffers));
185    bool input = true;
186    BufferInfoIterator it = findClientBuffer(array, buffer);
187    if (it == array->end()) {
188        array = std::atomic_load(&mOutputBuffers);
189        input = false;
190        it = findClientBuffer(array, buffer);
191        if (it == array->end()) {
192            return -ENOENT;
193        }
194    }
195    ALOGV("discardBuffer #%d", it->mBufferId);
196    sp<AMessage> msg = input ? mInputBufferFilled->dup() : mOutputBufferDrained->dup();
197    msg->setObject("buffer", it->mCodecBuffer);
198    msg->setInt32("buffer-id", it->mBufferId);
199    msg->setInt32("discarded", true);
200    msg->post();
201    return OK;
202}
203
204void ACodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
205    std::shared_ptr<const std::vector<const BufferInfo>> inputBuffers(
206            std::atomic_load(&mInputBuffers));
207    array->clear();
208    for (const BufferInfo &elem : *inputBuffers) {
209        array->push_back(elem.mClientBuffer);
210    }
211}
212
213void ACodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
214    std::shared_ptr<const std::vector<const BufferInfo>> outputBuffers(
215            std::atomic_load(&mOutputBuffers));
216    array->clear();
217    for (const BufferInfo &elem : *outputBuffers) {
218        array->push_back(elem.mClientBuffer);
219    }
220}
221
222void ACodecBufferChannel::setInputBufferArray(const std::vector<BufferAndId> &array) {
223    bool secure = (mCrypto != nullptr);
224    if (secure) {
225        size_t totalSize = std::accumulate(
226                array.begin(), array.end(), 0u,
227                [alignment = MemoryDealer::getAllocationAlignment()]
228                (size_t sum, const BufferAndId& elem) {
229                    return sum + align(elem.mBuffer->capacity(), alignment);
230                });
231        mDealer = new MemoryDealer(totalSize, "ACodecBufferChannel");
232    }
233    std::vector<const BufferInfo> inputBuffers;
234    for (const BufferAndId &elem : array) {
235        sp<IMemory> sharedEncryptedBuffer;
236        if (secure) {
237            sharedEncryptedBuffer = mDealer->allocate(elem.mBuffer->capacity());
238        }
239        inputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, sharedEncryptedBuffer);
240    }
241    std::atomic_store(
242            &mInputBuffers,
243            std::make_shared<const std::vector<const BufferInfo>>(inputBuffers));
244}
245
246void ACodecBufferChannel::setOutputBufferArray(const std::vector<BufferAndId> &array) {
247    std::vector<const BufferInfo> outputBuffers;
248    for (const BufferAndId &elem : array) {
249        outputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, nullptr);
250    }
251    std::atomic_store(
252            &mOutputBuffers,
253            std::make_shared<const std::vector<const BufferInfo>>(outputBuffers));
254}
255
256void ACodecBufferChannel::fillThisBuffer(IOMX::buffer_id bufferId) {
257    ALOGV("fillThisBuffer #%d", bufferId);
258    std::shared_ptr<const std::vector<const BufferInfo>> array(
259            std::atomic_load(&mInputBuffers));
260    BufferInfoIterator it = findBufferId(array, bufferId);
261
262    if (it == array->end()) {
263        ALOGE("fillThisBuffer: unrecognized buffer #%d", bufferId);
264        return;
265    }
266    if (it->mClientBuffer != it->mCodecBuffer) {
267        it->mClientBuffer->setFormat(it->mCodecBuffer->format());
268    }
269
270    mCallback->onInputBufferAvailable(
271            std::distance(array->begin(), it),
272            it->mClientBuffer);
273}
274
275void ACodecBufferChannel::drainThisBuffer(
276        IOMX::buffer_id bufferId,
277        OMX_U32 omxFlags) {
278    ALOGV("drainThisBuffer #%d", bufferId);
279    std::shared_ptr<const std::vector<const BufferInfo>> array(
280            std::atomic_load(&mOutputBuffers));
281    BufferInfoIterator it = findBufferId(array, bufferId);
282
283    if (it == array->end()) {
284        ALOGE("drainThisBuffer: unrecognized buffer #%d", bufferId);
285        return;
286    }
287    if (it->mClientBuffer != it->mCodecBuffer) {
288        it->mClientBuffer->setFormat(it->mCodecBuffer->format());
289    }
290
291    uint32_t flags = 0;
292    if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
293        flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME;
294    }
295    if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
296        flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
297    }
298    if (omxFlags & OMX_BUFFERFLAG_EOS) {
299        flags |= MediaCodec::BUFFER_FLAG_EOS;
300    }
301    it->mClientBuffer->meta()->setInt32("flags", flags);
302
303    mCallback->onOutputBufferAvailable(
304            std::distance(array->begin(), it),
305            it->mClientBuffer);
306}
307
308}  // namespace android
309