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