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 "encoder"
19
20 #include <fstream>
21
22 #include "Encoder.h"
23
onInputAvailable(AMediaCodec * mediaCodec,int32_t bufIdx)24 void Encoder::onInputAvailable(AMediaCodec *mediaCodec, int32_t bufIdx) {
25 ALOGV("In %s", __func__);
26 if (mediaCodec == mCodec && mediaCodec) {
27 if (mSawInputEOS || bufIdx < 0) return;
28 if (mSignalledError) {
29 CallBackHandle::mSawError = true;
30 mEncoderDoneCondition.notify_one();
31 return;
32 }
33
34 size_t bufSize = 0;
35 char *buf = (char *)AMediaCodec_getInputBuffer(mCodec, bufIdx, &bufSize);
36 if (!buf) {
37 mErrorCode = AMEDIA_ERROR_IO;
38 mSignalledError = true;
39 mEncoderDoneCondition.notify_one();
40 return;
41 }
42
43 if (mInputBufferSize < mOffset) {
44 ALOGE("Out of bound access of input buffer\n");
45 mErrorCode = AMEDIA_ERROR_MALFORMED;
46 mSignalledError = true;
47 mEncoderDoneCondition.notify_one();
48 return;
49 }
50 size_t bytesToRead = mParams.frameSize;
51 if (mInputBufferSize - mOffset < mParams.frameSize) {
52 bytesToRead = mInputBufferSize - mOffset;
53 }
54 //b/148655275 - Update Frame size, as Format value may not be valid
55 if (bufSize < bytesToRead) {
56 if(mNumInputFrame == 0) {
57 mParams.frameSize = bufSize;
58 bytesToRead = bufSize;
59 mParams.numFrames = (mInputBufferSize + mParams.frameSize - 1) / mParams.frameSize;
60 } else {
61 ALOGE("bytes to read %zu bufSize %zu \n", bytesToRead, bufSize);
62 mErrorCode = AMEDIA_ERROR_MALFORMED;
63 mSignalledError = true;
64 mEncoderDoneCondition.notify_one();
65 return;
66 }
67 }
68 if (bytesToRead < mParams.frameSize && mNumInputFrame < mParams.numFrames - 1) {
69 ALOGE("Partial frame at frameID %d bytesToRead %zu frameSize %d total numFrames %d\n",
70 mNumInputFrame, bytesToRead, mParams.frameSize, mParams.numFrames);
71 mErrorCode = AMEDIA_ERROR_MALFORMED;
72 mSignalledError = true;
73 mEncoderDoneCondition.notify_one();
74 return;
75 }
76 mEleStream->read(buf, bytesToRead);
77 size_t bytesgcount = mEleStream->gcount();
78 if (bytesgcount != bytesToRead) {
79 ALOGE("bytes to read %zu actual bytes read %zu \n", bytesToRead, bytesgcount);
80 mErrorCode = AMEDIA_ERROR_MALFORMED;
81 mSignalledError = true;
82 mEncoderDoneCondition.notify_one();
83 return;
84 }
85
86 uint32_t flag = 0;
87 if (mNumInputFrame == mParams.numFrames - 1 || bytesToRead == 0) {
88 ALOGD("Sending EOS on input Last frame\n");
89 flag |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
90 }
91
92 uint64_t presentationTimeUs;
93 if (!strncmp(mMime, "video/", 6)) {
94 presentationTimeUs = mNumInputFrame * (1000000 / mParams.frameRate);
95 } else {
96 presentationTimeUs =
97 (uint64_t)mNumInputFrame * mParams.frameSize * 1000000 / mParams.sampleRate;
98 }
99
100 if (flag == AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) mSawInputEOS = true;
101 ALOGV("%s bytesRead : %zd presentationTimeUs : %" PRIu64 " mSawInputEOS : %s", __FUNCTION__,
102 bytesToRead, presentationTimeUs, mSawInputEOS ? "TRUE" : "FALSE");
103
104 media_status_t status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */,
105 bytesToRead, presentationTimeUs, flag);
106 if (AMEDIA_OK != status) {
107 mErrorCode = status;
108 mSignalledError = true;
109 mEncoderDoneCondition.notify_one();
110 return;
111 }
112 mNumInputFrame++;
113 mOffset += bytesToRead;
114 }
115 }
116
onOutputAvailable(AMediaCodec * mediaCodec,int32_t bufIdx,AMediaCodecBufferInfo * bufferInfo)117 void Encoder::onOutputAvailable(AMediaCodec *mediaCodec, int32_t bufIdx,
118 AMediaCodecBufferInfo *bufferInfo) {
119 ALOGV("In %s", __func__);
120 if (mediaCodec == mCodec && mediaCodec) {
121 if (mSawOutputEOS || bufIdx < 0) return;
122 if (mSignalledError) {
123 CallBackHandle::mSawError = true;
124 mEncoderDoneCondition.notify_one();
125 return;
126 }
127
128 mStats->addFrameSize(bufferInfo->size);
129 AMediaCodec_releaseOutputBuffer(mCodec, bufIdx, false);
130 mSawOutputEOS = (0 != (bufferInfo->flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM));
131 mNumOutputFrame++;
132 ALOGV("%s index : %d mSawOutputEOS : %s count : %u", __FUNCTION__, bufIdx,
133 mSawOutputEOS ? "TRUE" : "FALSE", mNumOutputFrame);
134 if (mSawOutputEOS) {
135 CallBackHandle::mIsDone = true;
136 mEncoderDoneCondition.notify_one();
137 }
138 }
139 }
140
onFormatChanged(AMediaCodec * mediaCodec,AMediaFormat * format)141 void Encoder::onFormatChanged(AMediaCodec *mediaCodec, AMediaFormat *format) {
142 ALOGV("In %s", __func__);
143 if (mediaCodec == mCodec && mediaCodec) {
144 ALOGV("%s { %s }", __FUNCTION__, AMediaFormat_toString(format));
145 mFormat = format;
146 }
147 }
148
onError(AMediaCodec * mediaCodec,media_status_t err)149 void Encoder::onError(AMediaCodec *mediaCodec, media_status_t err) {
150 ALOGV("In %s", __func__);
151 if (mediaCodec == mCodec && mediaCodec) {
152 ALOGE("Received Error %d", err);
153 mErrorCode = err;
154 mSignalledError = true;
155 mEncoderDoneCondition.notify_one();
156 }
157 }
158
setupEncoder()159 void Encoder::setupEncoder() {
160 if (!mFormat) mFormat = AMediaFormat_new();
161 }
162
deInitCodec()163 void Encoder::deInitCodec() {
164 if (mFormat) {
165 AMediaFormat_delete(mFormat);
166 mFormat = nullptr;
167 }
168 if (!mCodec) return;
169 int64_t sTime = mStats->getCurTime();
170 AMediaCodec_stop(mCodec);
171 AMediaCodec_delete(mCodec);
172 int64_t eTime = mStats->getCurTime();
173 int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
174 mStats->setDeInitTime(timeTaken);
175 }
176
resetEncoder()177 void Encoder::resetEncoder() {
178 if (mStats) mStats->reset();
179 if (mEleStream) mEleStream = nullptr;
180 if (mMime) mMime = nullptr;
181 mInputBufferSize = 0;
182 memset(&mParams, 0, sizeof mParams);
183 }
184
dumpStatistics(string inputReference,int64_t durationUs,string componentName,string mode,string statsFile)185 void Encoder::dumpStatistics(string inputReference, int64_t durationUs, string componentName,
186 string mode, string statsFile) {
187 string operation = "encode";
188 mStats->dumpStatistics(operation, inputReference, durationUs, componentName, mode, statsFile);
189 }
190
encode(string & codecName,ifstream & eleStream,size_t eleSize,bool asyncMode,encParameter encParams,char * mime)191 int32_t Encoder::encode(string &codecName, ifstream &eleStream, size_t eleSize, bool asyncMode,
192 encParameter encParams, char *mime) {
193 ALOGV("In %s", __func__);
194 mEleStream = &eleStream;
195 mInputBufferSize = eleSize;
196 mParams = encParams;
197 mOffset = 0;
198 mMime = mime;
199 AMediaFormat_setString(mFormat, AMEDIAFORMAT_KEY_MIME, mMime);
200
201 // Set Format
202 if (!strncmp(mMime, "video/", 6)) {
203 AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_WIDTH, mParams.width);
204 AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_HEIGHT, mParams.height);
205 AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_FRAME_RATE, mParams.frameRate);
206 AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, mParams.iFrameInterval);
207 AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_BIT_RATE, mParams.bitrate);
208 AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, mParams.colorFormat);
209 if (mParams.profile != -1 && mParams.level != -1) {
210 AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_PROFILE, mParams.profile);
211 AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_LEVEL, mParams.level);
212 }
213 } else {
214 AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, mParams.sampleRate);
215 AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mParams.numChannels);
216 AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_BIT_RATE, mParams.bitrate);
217 }
218 const char *s = AMediaFormat_toString(mFormat);
219 ALOGI("Input format: %s\n", s);
220
221 int64_t sTime = mStats->getCurTime();
222 mCodec = createMediaCodec(mFormat, mMime, codecName, true /*isEncoder*/);
223 if (!mCodec) return AMEDIA_ERROR_INVALID_OBJECT;
224 int64_t eTime = mStats->getCurTime();
225 int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
226
227 if (!strncmp(mMime, "video/", 6)) {
228 mParams.frameSize = mParams.width * mParams.height * 3 / 2;
229 } else {
230 mParams.frameSize = kDefaultAudioEncodeFrameSize;
231 // Get mInputMaxBufSize
232 AMediaFormat *inputFormat = AMediaCodec_getInputFormat(mCodec);
233 AMediaFormat_getInt32(inputFormat, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, &mParams.maxFrameSize);
234 if (mParams.maxFrameSize < 0) {
235 mParams.maxFrameSize = kDefaultAudioEncodeFrameSize;
236 }
237 if (mParams.frameSize > mParams.maxFrameSize) {
238 mParams.frameSize = mParams.maxFrameSize;
239 }
240 }
241 mParams.numFrames = (mInputBufferSize + mParams.frameSize - 1) / mParams.frameSize;
242
243 sTime = mStats->getCurTime();
244 if (asyncMode) {
245 AMediaCodecOnAsyncNotifyCallback aCB = {OnInputAvailableCB, OnOutputAvailableCB,
246 OnFormatChangedCB, OnErrorCB};
247 AMediaCodec_setAsyncNotifyCallback(mCodec, aCB, this);
248 mIOThread = thread(&CallBackHandle::ioThread, this);
249 }
250 AMediaCodec_start(mCodec);
251 eTime = mStats->getCurTime();
252 timeTaken += mStats->getTimeDiff(sTime, eTime);
253 mStats->setInitTime(timeTaken);
254
255 mStats->setStartTime();
256 if (!asyncMode) {
257 while (!mSawOutputEOS && !mSignalledError) {
258 // Queue input data
259 if (!mSawInputEOS) {
260 ssize_t inIdx = AMediaCodec_dequeueInputBuffer(mCodec, kQueueDequeueTimeoutUs);
261 if (inIdx < 0 && inIdx != AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
262 ALOGE("AMediaCodec_dequeueInputBuffer returned invalid index %zd\n", inIdx);
263 mErrorCode = (media_status_t)inIdx;
264 return mErrorCode;
265 } else if (inIdx >= 0) {
266 mStats->addInputTime();
267 onInputAvailable(mCodec, inIdx);
268 }
269 }
270
271 // Dequeue output data
272 AMediaCodecBufferInfo info;
273 ssize_t outIdx = AMediaCodec_dequeueOutputBuffer(mCodec, &info, kQueueDequeueTimeoutUs);
274 if (outIdx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
275 mFormat = AMediaCodec_getOutputFormat(mCodec);
276 const char *s = AMediaFormat_toString(mFormat);
277 ALOGI("Output format: %s\n", s);
278 } else if (outIdx >= 0) {
279 mStats->addOutputTime();
280 onOutputAvailable(mCodec, outIdx, &info);
281 } else if (!(outIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER ||
282 outIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)) {
283 ALOGE("AMediaCodec_dequeueOutputBuffer returned invalid index %zd\n", outIdx);
284 mErrorCode = (media_status_t)outIdx;
285 return mErrorCode;
286 }
287 }
288 } else {
289 unique_lock<mutex> lock(mMutex);
290 mEncoderDoneCondition.wait(lock, [this]() { return (mSawOutputEOS || mSignalledError); });
291 }
292 if (mSignalledError) {
293 ALOGE("Received Error while Encoding");
294 return mErrorCode;
295 }
296
297 if (codecName.empty()) {
298 char *encName;
299 AMediaCodec_getName(mCodec, &encName);
300 codecName.assign(encName);
301 AMediaCodec_releaseName(mCodec, encName);
302 }
303 return AMEDIA_OK;
304 }
305