blob: 390b2e27fc9eab2a482037a095afb7a21b718559 [file] [log] [blame]
Andreas Huber35213f12012-08-29 11:41:50 -07001/*
2 * Copyright 2012, 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 "Converter"
19#include <utils/Log.h>
20
21#include "Converter.h"
22
Andreas Huber13da4ed2012-09-12 14:06:17 -070023#include <cutils/properties.h>
Andreas Huber35213f12012-08-29 11:41:50 -070024#include <gui/SurfaceTextureClient.h>
25#include <media/ICrypto.h>
26#include <media/stagefright/foundation/ABuffer.h>
27#include <media/stagefright/foundation/ADebug.h>
28#include <media/stagefright/foundation/AMessage.h>
29#include <media/stagefright/MediaCodec.h>
30#include <media/stagefright/MediaDefs.h>
31#include <media/stagefright/MediaErrors.h>
32
33namespace android {
34
35Converter::Converter(
36 const sp<AMessage> &notify,
37 const sp<ALooper> &codecLooper,
38 const sp<AMessage> &format)
39 : mInitCheck(NO_INIT),
40 mNotify(notify),
41 mCodecLooper(codecLooper),
42 mInputFormat(format),
Andreas Huber03e2ffa2012-09-13 16:43:51 -070043 mIsVideo(false),
Andreas Huber35213f12012-08-29 11:41:50 -070044 mDoMoreWorkPending(false) {
Andreas Huber03e2ffa2012-09-13 16:43:51 -070045 AString mime;
46 CHECK(mInputFormat->findString("mime", &mime));
47
48 if (!strncasecmp("video/", mime.c_str(), 6)) {
49 mIsVideo = true;
50 }
51
Andreas Huber35213f12012-08-29 11:41:50 -070052 mInitCheck = initEncoder();
53}
54
55Converter::~Converter() {
56 if (mEncoder != NULL) {
57 mEncoder->release();
58 mEncoder.clear();
59 }
Andreas Huber596b4cd2012-09-12 16:25:14 -070060
61 AString mime;
62 CHECK(mInputFormat->findString("mime", &mime));
63 ALOGI("encoder (%s) shut down.", mime.c_str());
Andreas Huber35213f12012-08-29 11:41:50 -070064}
65
66status_t Converter::initCheck() const {
67 return mInitCheck;
68}
69
Andreas Huber7f066392012-09-04 16:30:49 -070070size_t Converter::getInputBufferCount() const {
71 return mEncoderInputBuffers.size();
72}
73
Andreas Huber35213f12012-08-29 11:41:50 -070074sp<AMessage> Converter::getOutputFormat() const {
75 return mOutputFormat;
76}
77
Andreas Huber13da4ed2012-09-12 14:06:17 -070078static int32_t getBitrate(const char *propName, int32_t defaultValue) {
79 char val[PROPERTY_VALUE_MAX];
80 if (property_get(propName, val, NULL)) {
81 char *end;
82 unsigned long x = strtoul(val, &end, 10);
83
84 if (*end == '\0' && end > val && x > 0) {
85 return x;
86 }
87 }
88
89 return defaultValue;
90}
91
Andreas Huber35213f12012-08-29 11:41:50 -070092status_t Converter::initEncoder() {
93 AString inputMIME;
94 CHECK(mInputFormat->findString("mime", &inputMIME));
95
96 AString outputMIME;
97 bool isAudio = false;
98 if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) {
99 outputMIME = MEDIA_MIMETYPE_AUDIO_AAC;
100 isAudio = true;
101 } else if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) {
102 outputMIME = MEDIA_MIMETYPE_VIDEO_AVC;
103 } else {
104 TRESPASS();
105 }
106
107 mEncoder = MediaCodec::CreateByType(
108 mCodecLooper, outputMIME.c_str(), true /* encoder */);
109
110 if (mEncoder == NULL) {
111 return ERROR_UNSUPPORTED;
112 }
113
114 mOutputFormat = mInputFormat->dup();
115 mOutputFormat->setString("mime", outputMIME.c_str());
116
Andreas Huber13da4ed2012-09-12 14:06:17 -0700117 int32_t audioBitrate = getBitrate("media.wfd.audio-bitrate", 64000);
118 int32_t videoBitrate = getBitrate("media.wfd.video-bitrate", 10000000);
119
120 ALOGI("using audio bitrate of %d bps, video bitrate of %d bps",
121 audioBitrate, videoBitrate);
122
Andreas Huber35213f12012-08-29 11:41:50 -0700123 if (isAudio) {
Andreas Huber13da4ed2012-09-12 14:06:17 -0700124 mOutputFormat->setInt32("bitrate", audioBitrate);
Andreas Huber35213f12012-08-29 11:41:50 -0700125 } else {
Andreas Huber13da4ed2012-09-12 14:06:17 -0700126 mOutputFormat->setInt32("bitrate", videoBitrate);
Andreas Huberb5d99d12012-09-12 16:48:23 -0700127 mOutputFormat->setInt32("frame-rate", 30);
Andreas Huber35213f12012-08-29 11:41:50 -0700128 mOutputFormat->setInt32("i-frame-interval", 3); // Iframes every 3 secs
129 }
130
131 ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str());
132
133 status_t err = mEncoder->configure(
134 mOutputFormat,
135 NULL /* nativeWindow */,
136 NULL /* crypto */,
137 MediaCodec::CONFIGURE_FLAG_ENCODE);
138
139 if (err != OK) {
140 return err;
141 }
142
143 err = mEncoder->start();
144
145 if (err != OK) {
146 return err;
147 }
148
149 err = mEncoder->getInputBuffers(&mEncoderInputBuffers);
150
151 if (err != OK) {
152 return err;
153 }
154
155 return mEncoder->getOutputBuffers(&mEncoderOutputBuffers);
156}
157
158void Converter::feedAccessUnit(const sp<ABuffer> &accessUnit) {
159 sp<AMessage> msg = new AMessage(kWhatFeedAccessUnit, id());
160 msg->setBuffer("accessUnit", accessUnit);
161 msg->post();
162}
163
164void Converter::signalEOS() {
165 (new AMessage(kWhatInputEOS, id()))->post();
166}
167
168void Converter::notifyError(status_t err) {
169 sp<AMessage> notify = mNotify->dup();
170 notify->setInt32("what", kWhatError);
171 notify->setInt32("err", err);
172 notify->post();
173}
174
175void Converter::onMessageReceived(const sp<AMessage> &msg) {
176 switch (msg->what()) {
177 case kWhatFeedAccessUnit:
178 {
179 sp<ABuffer> accessUnit;
180 CHECK(msg->findBuffer("accessUnit", &accessUnit));
181
182 mInputBufferQueue.push_back(accessUnit);
183
184 feedEncoderInputBuffers();
185
186 scheduleDoMoreWork();
187 break;
188 }
189
190 case kWhatInputEOS:
191 {
192 mInputBufferQueue.push_back(NULL);
193
194 feedEncoderInputBuffers();
195
196 scheduleDoMoreWork();
197 break;
198 }
199
200 case kWhatDoMoreWork:
201 {
202 mDoMoreWorkPending = false;
203 status_t err = doMoreWork();
204
205 if (err != OK) {
206 notifyError(err);
207 } else {
208 scheduleDoMoreWork();
209 }
210 break;
211 }
212
Andreas Huber03e2ffa2012-09-13 16:43:51 -0700213 case kWhatRequestIDRFrame:
214 {
215 if (mIsVideo) {
216 ALOGI("requesting IDR frame");
217 mEncoder->requestIDRFrame();
218 }
219 break;
220 }
221
Andreas Huber35213f12012-08-29 11:41:50 -0700222 default:
223 TRESPASS();
224 }
225}
226
227void Converter::scheduleDoMoreWork() {
228 if (mDoMoreWorkPending) {
229 return;
230 }
231
232 mDoMoreWorkPending = true;
233 (new AMessage(kWhatDoMoreWork, id()))->post(1000ll);
234}
235
236status_t Converter::feedEncoderInputBuffers() {
237 while (!mInputBufferQueue.empty()
238 && !mAvailEncoderInputIndices.empty()) {
239 sp<ABuffer> buffer = *mInputBufferQueue.begin();
240 mInputBufferQueue.erase(mInputBufferQueue.begin());
241
242 size_t bufferIndex = *mAvailEncoderInputIndices.begin();
243 mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin());
244
245 int64_t timeUs = 0ll;
246 uint32_t flags = 0;
247
248 if (buffer != NULL) {
249 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
250
251 memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(),
252 buffer->data(),
253 buffer->size());
254
255 void *mediaBuffer;
256 if (buffer->meta()->findPointer("mediaBuffer", &mediaBuffer)
257 && mediaBuffer != NULL) {
258 mEncoderInputBuffers.itemAt(bufferIndex)->meta()
259 ->setPointer("mediaBuffer", mediaBuffer);
260
261 buffer->meta()->setPointer("mediaBuffer", NULL);
262 }
263 } else {
264 flags = MediaCodec::BUFFER_FLAG_EOS;
265 }
266
267 status_t err = mEncoder->queueInputBuffer(
268 bufferIndex, 0, (buffer == NULL) ? 0 : buffer->size(),
269 timeUs, flags);
270
271 if (err != OK) {
272 return err;
273 }
274 }
275
276 return OK;
277}
278
279status_t Converter::doMoreWork() {
280 size_t bufferIndex;
281 status_t err = mEncoder->dequeueInputBuffer(&bufferIndex);
282
283 if (err == OK) {
284 mAvailEncoderInputIndices.push_back(bufferIndex);
285 feedEncoderInputBuffers();
286 }
287
288 size_t offset;
289 size_t size;
290 int64_t timeUs;
291 uint32_t flags;
292 err = mEncoder->dequeueOutputBuffer(
293 &bufferIndex, &offset, &size, &timeUs, &flags);
294
295 if (err == OK) {
296 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
297 sp<AMessage> notify = mNotify->dup();
298 notify->setInt32("what", kWhatEOS);
299 notify->post();
300 } else {
301 sp<ABuffer> buffer = new ABuffer(size);
302 buffer->meta()->setInt64("timeUs", timeUs);
303
304 memcpy(buffer->data(),
305 mEncoderOutputBuffers.itemAt(bufferIndex)->base() + offset,
306 size);
307
308 if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
309 mOutputFormat->setBuffer("csd-0", buffer);
310 } else {
311 sp<AMessage> notify = mNotify->dup();
312 notify->setInt32("what", kWhatAccessUnit);
313 notify->setBuffer("accessUnit", buffer);
314 notify->post();
315 }
316 }
317
318 err = mEncoder->releaseOutputBuffer(bufferIndex);
319 } else if (err == -EAGAIN) {
320 err = OK;
321 }
322
323 return err;
324}
325
Andreas Huber03e2ffa2012-09-13 16:43:51 -0700326void Converter::requestIDRFrame() {
327 (new AMessage(kWhatRequestIDRFrame, id()))->post();
328}
329
Andreas Huber35213f12012-08-29 11:41:50 -0700330} // namespace android
331