• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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