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 "decoder"
19 
20 #include <iostream>
21 
22 #include "Decoder.h"
23 
readSampleData(uint8_t * inputBuffer,int32_t & offset,vector<AMediaCodecBufferInfo> & frameInfo,uint8_t * buf,int32_t frameID,size_t bufSize)24 tuple<ssize_t, uint32_t, int64_t> readSampleData(uint8_t *inputBuffer, int32_t &offset,
25                                                  vector<AMediaCodecBufferInfo> &frameInfo,
26                                                  uint8_t *buf, int32_t frameID, size_t bufSize) {
27     ALOGV("In %s", __func__);
28     if (frameID == (int32_t)frameInfo.size()) {
29         return make_tuple(0, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM, 0);
30     }
31     uint32_t flags = frameInfo[frameID].flags;
32     int64_t timestamp = frameInfo[frameID].presentationTimeUs;
33     ssize_t bytesCount = frameInfo[frameID].size;
34     if (bufSize < bytesCount) {
35         ALOGE("Error : Buffer size is insufficient to read sample");
36         return make_tuple(0, AMEDIA_ERROR_MALFORMED, 0);
37     }
38 
39     memcpy(buf, inputBuffer + offset, bytesCount);
40     offset += bytesCount;
41     return make_tuple(bytesCount, flags, timestamp);
42 }
43 
onInputAvailable(AMediaCodec * mediaCodec,int32_t bufIdx)44 void Decoder::onInputAvailable(AMediaCodec *mediaCodec, int32_t bufIdx) {
45     ALOGV("In %s", __func__);
46     if (mediaCodec == mCodec && mediaCodec) {
47         if (mSawInputEOS || bufIdx < 0) return;
48         if (mSignalledError) {
49             CallBackHandle::mSawError = true;
50             mDecoderDoneCondition.notify_one();
51             return;
52         }
53 
54         size_t bufSize;
55         uint8_t *buf = AMediaCodec_getInputBuffer(mCodec, bufIdx, &bufSize);
56         if (!buf) {
57             mErrorCode = AMEDIA_ERROR_IO;
58             mSignalledError = true;
59             mDecoderDoneCondition.notify_one();
60             return;
61         }
62 
63         ssize_t bytesRead = 0;
64         uint32_t flag = 0;
65         int64_t presentationTimeUs = 0;
66         tie(bytesRead, flag, presentationTimeUs) =
67                 readSampleData(mInputBuffer, mOffset, mFrameMetaData, buf, mNumInputFrame, bufSize);
68         if (flag == AMEDIA_ERROR_MALFORMED) {
69             mErrorCode = (media_status_t)flag;
70             mSignalledError = true;
71             mDecoderDoneCondition.notify_one();
72             return;
73         }
74 
75         if (flag == AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) mSawInputEOS = true;
76         ALOGV("%s bytesRead : %zd presentationTimeUs : %" PRId64 " mSawInputEOS : %s", __FUNCTION__,
77               bytesRead, presentationTimeUs, mSawInputEOS ? "TRUE" : "FALSE");
78 
79         media_status_t status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */,
80                                                              bytesRead, presentationTimeUs, flag);
81         if (AMEDIA_OK != status) {
82             mErrorCode = status;
83             mSignalledError = true;
84             mDecoderDoneCondition.notify_one();
85             return;
86         }
87         mStats->addFrameSize(bytesRead);
88         mNumInputFrame++;
89     }
90 }
91 
onOutputAvailable(AMediaCodec * mediaCodec,int32_t bufIdx,AMediaCodecBufferInfo * bufferInfo)92 void Decoder::onOutputAvailable(AMediaCodec *mediaCodec, int32_t bufIdx,
93                                 AMediaCodecBufferInfo *bufferInfo) {
94     ALOGV("In %s", __func__);
95     if (mediaCodec == mCodec && mediaCodec) {
96         if (mSawOutputEOS || bufIdx < 0) return;
97         if (mSignalledError) {
98             CallBackHandle::mSawError = true;
99             mDecoderDoneCondition.notify_one();
100             return;
101         }
102 
103         if (mOutFp != nullptr) {
104             size_t bufSize;
105             uint8_t *buf = AMediaCodec_getOutputBuffer(mCodec, bufIdx, &bufSize);
106             if (buf) {
107                 fwrite(buf, sizeof(char), bufferInfo->size, mOutFp);
108                 ALOGV("bytes written into file  %d\n", bufferInfo->size);
109             }
110         }
111 
112         AMediaCodec_releaseOutputBuffer(mCodec, bufIdx, false);
113         mSawOutputEOS = (0 != (bufferInfo->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM));
114         mNumOutputFrame++;
115         ALOGV("%s index : %d  mSawOutputEOS : %s count : %u", __FUNCTION__, bufIdx,
116               mSawOutputEOS ? "TRUE" : "FALSE", mNumOutputFrame);
117 
118         if (mSawOutputEOS) {
119             CallBackHandle::mIsDone = true;
120             mDecoderDoneCondition.notify_one();
121         }
122     }
123 }
124 
onFormatChanged(AMediaCodec * mediaCodec,AMediaFormat * format)125 void Decoder::onFormatChanged(AMediaCodec *mediaCodec, AMediaFormat *format) {
126     ALOGV("In %s", __func__);
127     if (mediaCodec == mCodec && mediaCodec) {
128         ALOGV("%s { %s }", __FUNCTION__, AMediaFormat_toString(format));
129         mFormat = format;
130     }
131 }
132 
onError(AMediaCodec * mediaCodec,media_status_t err)133 void Decoder::onError(AMediaCodec *mediaCodec, media_status_t err) {
134     ALOGV("In %s", __func__);
135     if (mediaCodec == mCodec && mediaCodec) {
136         ALOGE("Received Error %d", err);
137         mErrorCode = err;
138         mSignalledError = true;
139         mDecoderDoneCondition.notify_one();
140     }
141 }
142 
setupDecoder()143 void Decoder::setupDecoder() {
144     if (!mFormat) mFormat = mExtractor->getFormat();
145 }
146 
getFormat()147 AMediaFormat *Decoder::getFormat() {
148     ALOGV("In %s", __func__);
149     return AMediaCodec_getOutputFormat(mCodec);
150 }
151 
decode(uint8_t * inputBuffer,vector<AMediaCodecBufferInfo> & frameInfo,string & codecName,bool asyncMode,FILE * outFp)152 int32_t Decoder::decode(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfo,
153                         string &codecName, bool asyncMode, FILE *outFp) {
154     ALOGV("In %s", __func__);
155     mInputBuffer = inputBuffer;
156     mFrameMetaData = frameInfo;
157     mOffset = 0;
158     mOutFp = outFp;
159 
160     const char *mime = nullptr;
161     AMediaFormat_getString(mFormat, AMEDIAFORMAT_KEY_MIME, &mime);
162     if (!mime) return AMEDIA_ERROR_INVALID_OBJECT;
163 
164     int64_t sTime = mStats->getCurTime();
165     mCodec = createMediaCodec(mFormat, mime, codecName, false /*isEncoder*/);
166     if (!mCodec) return AMEDIA_ERROR_INVALID_OBJECT;
167 
168     if (asyncMode) {
169         AMediaCodecOnAsyncNotifyCallback aCB = {OnInputAvailableCB, OnOutputAvailableCB,
170                                                 OnFormatChangedCB, OnErrorCB};
171         AMediaCodec_setAsyncNotifyCallback(mCodec, aCB, this);
172 
173         mIOThread = thread(&CallBackHandle::ioThread, this);
174     }
175 
176     AMediaCodec_start(mCodec);
177     int64_t eTime = mStats->getCurTime();
178     int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
179     mStats->setInitTime(timeTaken);
180 
181     mStats->setStartTime();
182     if (!asyncMode) {
183         while (!mSawOutputEOS && !mSignalledError) {
184             /* Queue input data */
185             if (!mSawInputEOS) {
186                 ssize_t inIdx = AMediaCodec_dequeueInputBuffer(mCodec, kQueueDequeueTimeoutUs);
187                 if (inIdx < 0 && inIdx != AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
188                     ALOGE("AMediaCodec_dequeueInputBuffer returned invalid index %zd\n", inIdx);
189                     mErrorCode = (media_status_t)inIdx;
190                     return mErrorCode;
191                 } else if (inIdx >= 0) {
192                     mStats->addInputTime();
193                     onInputAvailable(mCodec, inIdx);
194                 }
195             }
196 
197             /* Dequeue output data */
198             AMediaCodecBufferInfo info;
199             ssize_t outIdx = AMediaCodec_dequeueOutputBuffer(mCodec, &info, kQueueDequeueTimeoutUs);
200             if (outIdx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
201                 mFormat = AMediaCodec_getOutputFormat(mCodec);
202                 const char *s = AMediaFormat_toString(mFormat);
203                 ALOGI("Output format: %s\n", s);
204             } else if (outIdx >= 0) {
205                 mStats->addOutputTime();
206                 onOutputAvailable(mCodec, outIdx, &info);
207             } else if (!(outIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER ||
208                          outIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)) {
209                 ALOGE("AMediaCodec_dequeueOutputBuffer returned invalid index %zd\n", outIdx);
210                 mErrorCode = (media_status_t)outIdx;
211                 return mErrorCode;
212             }
213         }
214     } else {
215         unique_lock<mutex> lock(mMutex);
216         mDecoderDoneCondition.wait(lock, [this]() { return (mSawOutputEOS || mSignalledError); });
217     }
218     if (mSignalledError) {
219         ALOGE("Received Error while Decoding");
220         return mErrorCode;
221     }
222 
223     if (codecName.empty()) {
224         char *decName;
225         AMediaCodec_getName(mCodec, &decName);
226         codecName.assign(decName);
227         AMediaCodec_releaseName(mCodec, decName);
228     }
229     return AMEDIA_OK;
230 }
231 
deInitCodec()232 void Decoder::deInitCodec() {
233     if (mFormat) {
234         AMediaFormat_delete(mFormat);
235         mFormat = nullptr;
236     }
237     if (!mCodec) return;
238     int64_t sTime = mStats->getCurTime();
239     AMediaCodec_stop(mCodec);
240     AMediaCodec_delete(mCodec);
241     int64_t eTime = mStats->getCurTime();
242     int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
243     mStats->setDeInitTime(timeTaken);
244 }
245 
dumpStatistics(string inputReference,string componentName,string mode,string statsFile)246 void Decoder::dumpStatistics(string inputReference, string componentName, string mode,
247                              string statsFile) {
248     int64_t durationUs = mExtractor->getClipDuration();
249     string operation = "decode";
250     mStats->dumpStatistics(operation, inputReference, durationUs, componentName, mode, statsFile);
251 }
252 
resetDecoder()253 void Decoder::resetDecoder() {
254     if (mStats) mStats->reset();
255     if (mInputBuffer) mInputBuffer = nullptr;
256     if (!mFrameMetaData.empty()) mFrameMetaData.clear();
257 }
258