Converter.cpp revision 8fdd88b073275812ccd2279e3f657a4b5960bfa3
1/* 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 23#include <cutils/properties.h> 24#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> ¬ify, 37 const sp<ALooper> &codecLooper, 38 const sp<AMessage> &format) 39 : mInitCheck(NO_INIT), 40 mNotify(notify), 41 mCodecLooper(codecLooper), 42 mInputFormat(format), 43 mIsVideo(false), 44 mDoMoreWorkPending(false) { 45 AString mime; 46 CHECK(mInputFormat->findString("mime", &mime)); 47 48 if (!strncasecmp("video/", mime.c_str(), 6)) { 49 mIsVideo = true; 50 } 51 52 mInitCheck = initEncoder(); 53} 54 55Converter::~Converter() { 56 if (mEncoder != NULL) { 57 mEncoder->release(); 58 mEncoder.clear(); 59 } 60 61 AString mime; 62 CHECK(mInputFormat->findString("mime", &mime)); 63 ALOGI("encoder (%s) shut down.", mime.c_str()); 64} 65 66status_t Converter::initCheck() const { 67 return mInitCheck; 68} 69 70size_t Converter::getInputBufferCount() const { 71 return mEncoderInputBuffers.size(); 72} 73 74sp<AMessage> Converter::getOutputFormat() const { 75 return mOutputFormat; 76} 77 78static 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 92status_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 117 int32_t audioBitrate = getBitrate("media.wfd.audio-bitrate", 64000); 118 int32_t videoBitrate = getBitrate("media.wfd.video-bitrate", 2500000); 119 120 ALOGI("using audio bitrate of %d bps, video bitrate of %d bps", 121 audioBitrate, videoBitrate); 122 123 if (isAudio) { 124 mOutputFormat->setInt32("bitrate", audioBitrate); 125 } else { 126 mOutputFormat->setInt32("bitrate", videoBitrate); 127 mOutputFormat->setInt32("frame-rate", 30); 128 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 213 case kWhatRequestIDRFrame: 214 { 215 if (mIsVideo) { 216 ALOGI("requesting IDR frame"); 217 mEncoder->requestIDRFrame(); 218 } 219 break; 220 } 221 222 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 326void Converter::requestIDRFrame() { 327 (new AMessage(kWhatRequestIDRFrame, id()))->post(); 328} 329 330} // namespace android 331