1 /*
2 * Copyright (C) 2019 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 "C2Decoder"
19 #include <log/log.h>
20
21 #include "C2Decoder.h"
22 #include <iostream>
23
createCodec2Component(string compName,AMediaFormat * format)24 int32_t C2Decoder::createCodec2Component(string compName, AMediaFormat *format) {
25 ALOGV("In %s", __func__);
26 mListener.reset(new CodecListener(
27 [this](std::list<std::unique_ptr<C2Work>> &workItems) { handleWorkDone(workItems); }));
28 if (!mListener) return -1;
29
30 const char *mime = nullptr;
31 AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
32 if (!mime) {
33 ALOGE("Error in AMediaFormat_getString");
34 return -1;
35 }
36 // Configure the plugin with Input properties
37 std::vector<C2Param *> configParam;
38 if (!strncmp(mime, "audio/", 6)) {
39 int32_t sampleRate, numChannels;
40 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &sampleRate);
41 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &numChannels);
42 C2StreamSampleRateInfo::output sampleRateInfo(0u, sampleRate);
43 C2StreamChannelCountInfo::output channelCountInfo(0u, numChannels);
44 configParam.push_back(&sampleRateInfo);
45 configParam.push_back(&channelCountInfo);
46
47 } else {
48 int32_t width, height;
49 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width);
50 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height);
51 C2StreamPictureSizeInfo::input inputSize(0u, width, height);
52 configParam.push_back(&inputSize);
53 }
54
55 int64_t sTime = mStats->getCurTime();
56 if (mClient->CreateComponentByName(compName.c_str(), mListener, &mComponent, &mClient) !=
57 C2_OK) {
58 ALOGE("Create component failed for %s", compName.c_str());
59 return -1;
60 }
61 std::vector<std::unique_ptr<C2SettingResult>> failures;
62 int32_t status = mComponent->config(configParam, C2_DONT_BLOCK, &failures);
63 if (failures.size() != 0) {
64 ALOGE("Invalid Configuration");
65 return -1;
66 }
67
68 status |= mComponent->start();
69 int64_t eTime = mStats->getCurTime();
70 int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
71 mStats->setInitTime(timeTaken);
72 return status;
73 }
74
decodeFrames(uint8_t * inputBuffer,vector<AMediaCodecBufferInfo> & frameInfo)75 int32_t C2Decoder::decodeFrames(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfo) {
76 ALOGV("In %s", __func__);
77 typedef std::unique_lock<std::mutex> ULock;
78 c2_status_t status = C2_OK;
79 mStats->setStartTime();
80 while (1) {
81 if (mNumInputFrame == frameInfo.size()) break;
82 std::unique_ptr<C2Work> work;
83 // Prepare C2Work
84 {
85 ULock l(mQueueLock);
86 if (mWorkQueue.empty()) mQueueCondition.wait_for(l, MAX_RETRY * TIME_OUT);
87 if (!mWorkQueue.empty()) {
88 mStats->addInputTime();
89 work.swap(mWorkQueue.front());
90 mWorkQueue.pop_front();
91 } else {
92 std::cout << "Wait for generating C2Work exceeded timeout" << std::endl;
93 return -1;
94 }
95 }
96
97 uint32_t flags = frameInfo[mNumInputFrame].flags;
98 if (flags == AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) {
99 flags = C2FrameData::FLAG_CODEC_CONFIG;
100 }
101 if (mNumInputFrame == (frameInfo.size() - 1)) {
102 flags |= C2FrameData::FLAG_END_OF_STREAM;
103 }
104 work->input.flags = (C2FrameData::flags_t)flags;
105 work->input.ordinal.timestamp = frameInfo[mNumInputFrame].presentationTimeUs;
106 work->input.ordinal.frameIndex = mNumInputFrame;
107 work->input.buffers.clear();
108 int size = frameInfo[mNumInputFrame].size;
109 int alignedSize = ALIGN(size, PAGE_SIZE);
110 if (size) {
111 std::shared_ptr<C2LinearBlock> block;
112 status = mLinearPool->fetchLinearBlock(
113 alignedSize, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
114 if (status != C2_OK || block == nullptr) {
115 std::cout << "C2LinearBlock::map() failed : " << status << std::endl;
116 return status;
117 }
118
119 C2WriteView view = block->map().get();
120 if (view.error() != C2_OK) {
121 std::cout << "C2LinearBlock::map() failed : " << view.error() << std::endl;
122 return view.error();
123 }
124 memcpy(view.base(), inputBuffer + mOffset, size);
125 work->input.buffers.emplace_back(new LinearBuffer(block, size));
126 mStats->addFrameSize(size);
127 }
128 work->worklets.clear();
129 work->worklets.emplace_back(new C2Worklet);
130
131 std::list<std::unique_ptr<C2Work>> items;
132 items.push_back(std::move(work));
133 // queue() invokes process() function of C2 Plugin.
134 status = mComponent->queue(&items);
135 if (status != C2_OK) {
136 ALOGE("queue failed");
137 return status;
138 }
139 ALOGV("Frame #%d size = %d queued", mNumInputFrame, size);
140 mNumInputFrame++;
141 mOffset += size;
142 }
143 return status;
144 }
145
deInitCodec()146 void C2Decoder::deInitCodec() {
147 ALOGV("In %s", __func__);
148 if (!mComponent) return;
149
150 int64_t sTime = mStats->getCurTime();
151 mComponent->stop();
152 mComponent->release();
153 mComponent = nullptr;
154 int64_t eTime = mStats->getCurTime();
155 int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
156 mStats->setDeInitTime(timeTaken);
157 }
158
dumpStatistics(string inputReference,int64_t durationUs,string componentName,string statsFile)159 void C2Decoder::dumpStatistics(string inputReference, int64_t durationUs, string componentName,
160 string statsFile) {
161 string operation = "c2decode";
162 string mode = "async";
163 mStats->dumpStatistics(operation, inputReference, durationUs, componentName, mode, statsFile);
164 }
165
resetDecoder()166 void C2Decoder::resetDecoder() {
167 mOffset = 0;
168 mNumInputFrame = 0;
169 if (mStats) mStats->reset();
170 }
171