Converter.cpp revision cf2604f8940093e249ed7e5382c12ba544a48545
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 "MediaPuller.h" 24 25#include <cutils/properties.h> 26#include <gui/SurfaceTextureClient.h> 27#include <media/ICrypto.h> 28#include <media/stagefright/foundation/ABuffer.h> 29#include <media/stagefright/foundation/ADebug.h> 30#include <media/stagefright/foundation/AMessage.h> 31#include <media/stagefright/MediaBuffer.h> 32#include <media/stagefright/MediaCodec.h> 33#include <media/stagefright/MediaDefs.h> 34#include <media/stagefright/MediaErrors.h> 35 36namespace android { 37 38Converter::Converter( 39 const sp<AMessage> ¬ify, 40 const sp<ALooper> &codecLooper, 41 const sp<AMessage> &format) 42 : mInitCheck(NO_INIT), 43 mNotify(notify), 44 mCodecLooper(codecLooper), 45 mInputFormat(format), 46 mIsVideo(false), 47 mDoMoreWorkPending(false) 48#if ENABLE_SILENCE_DETECTION 49 ,mFirstSilentFrameUs(-1ll) 50 ,mInSilentMode(false) 51#endif 52 { 53 AString mime; 54 CHECK(mInputFormat->findString("mime", &mime)); 55 56 if (!strncasecmp("video/", mime.c_str(), 6)) { 57 mIsVideo = true; 58 } 59 60 mInitCheck = initEncoder(); 61 62 if (mInitCheck != OK) { 63 if (mEncoder != NULL) { 64 mEncoder->release(); 65 mEncoder.clear(); 66 } 67 } 68} 69 70Converter::~Converter() { 71 CHECK(mEncoder == NULL); 72} 73 74void Converter::shutdownAsync() { 75 ALOGV("shutdown"); 76 (new AMessage(kWhatShutdown, id()))->post(); 77} 78 79status_t Converter::initCheck() const { 80 return mInitCheck; 81} 82 83size_t Converter::getInputBufferCount() const { 84 return mEncoderInputBuffers.size(); 85} 86 87sp<AMessage> Converter::getOutputFormat() const { 88 return mOutputFormat; 89} 90 91static int32_t getBitrate(const char *propName, int32_t defaultValue) { 92 char val[PROPERTY_VALUE_MAX]; 93 if (property_get(propName, val, NULL)) { 94 char *end; 95 unsigned long x = strtoul(val, &end, 10); 96 97 if (*end == '\0' && end > val && x > 0) { 98 return x; 99 } 100 } 101 102 return defaultValue; 103} 104 105status_t Converter::initEncoder() { 106 AString inputMIME; 107 CHECK(mInputFormat->findString("mime", &inputMIME)); 108 109 AString outputMIME; 110 bool isAudio = false; 111 if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) { 112 outputMIME = MEDIA_MIMETYPE_AUDIO_AAC; 113 isAudio = true; 114 } else if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) { 115 outputMIME = MEDIA_MIMETYPE_VIDEO_AVC; 116 } else { 117 TRESPASS(); 118 } 119 120 mEncoder = MediaCodec::CreateByType( 121 mCodecLooper, outputMIME.c_str(), true /* encoder */); 122 123 if (mEncoder == NULL) { 124 return ERROR_UNSUPPORTED; 125 } 126 127 mOutputFormat = mInputFormat->dup(); 128 mOutputFormat->setString("mime", outputMIME.c_str()); 129 130 int32_t audioBitrate = getBitrate("media.wfd.audio-bitrate", 128000); 131 int32_t videoBitrate = getBitrate("media.wfd.video-bitrate", 5000000); 132 133 ALOGI("using audio bitrate of %d bps, video bitrate of %d bps", 134 audioBitrate, videoBitrate); 135 136 if (isAudio) { 137 mOutputFormat->setInt32("bitrate", audioBitrate); 138 } else { 139 mOutputFormat->setInt32("bitrate", videoBitrate); 140 mOutputFormat->setInt32("frame-rate", 30); 141 mOutputFormat->setInt32("i-frame-interval", 1); // Iframes every 1 secs 142 mOutputFormat->setInt32("prepend-sps-pps-to-idr-frames", 1); 143 } 144 145 ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str()); 146 147 status_t err = mEncoder->configure( 148 mOutputFormat, 149 NULL /* nativeWindow */, 150 NULL /* crypto */, 151 MediaCodec::CONFIGURE_FLAG_ENCODE); 152 153 if (err != OK) { 154 return err; 155 } 156 157 err = mEncoder->start(); 158 159 if (err != OK) { 160 return err; 161 } 162 163 err = mEncoder->getInputBuffers(&mEncoderInputBuffers); 164 165 if (err != OK) { 166 return err; 167 } 168 169 return mEncoder->getOutputBuffers(&mEncoderOutputBuffers); 170} 171 172void Converter::notifyError(status_t err) { 173 sp<AMessage> notify = mNotify->dup(); 174 notify->setInt32("what", kWhatError); 175 notify->setInt32("err", err); 176 notify->post(); 177} 178 179// static 180bool Converter::IsSilence(const sp<ABuffer> &accessUnit) { 181 const uint8_t *ptr = accessUnit->data(); 182 const uint8_t *end = ptr + accessUnit->size(); 183 while (ptr < end) { 184 if (*ptr != 0) { 185 return false; 186 } 187 ++ptr; 188 } 189 190 return true; 191} 192 193void Converter::onMessageReceived(const sp<AMessage> &msg) { 194 switch (msg->what()) { 195 case kWhatMediaPullerNotify: 196 { 197 int32_t what; 198 CHECK(msg->findInt32("what", &what)); 199 200 if (mEncoder == NULL) { 201 ALOGV("got msg '%s' after encoder shutdown.", 202 msg->debugString().c_str()); 203 204 if (what == MediaPuller::kWhatAccessUnit) { 205 sp<ABuffer> accessUnit; 206 CHECK(msg->findBuffer("accessUnit", &accessUnit)); 207 208 void *mbuf; 209 if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf) 210 && mbuf != NULL) { 211 ALOGV("releasing mbuf %p", mbuf); 212 213 accessUnit->meta()->setPointer("mediaBuffer", NULL); 214 215 static_cast<MediaBuffer *>(mbuf)->release(); 216 mbuf = NULL; 217 } 218 } 219 break; 220 } 221 222 if (what == MediaPuller::kWhatEOS) { 223 mInputBufferQueue.push_back(NULL); 224 225 feedEncoderInputBuffers(); 226 227 scheduleDoMoreWork(); 228 } else { 229 CHECK_EQ(what, MediaPuller::kWhatAccessUnit); 230 231 sp<ABuffer> accessUnit; 232 CHECK(msg->findBuffer("accessUnit", &accessUnit)); 233 234#if 0 235 void *mbuf; 236 if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf) 237 && mbuf != NULL) { 238 ALOGI("queueing mbuf %p", mbuf); 239 } 240#endif 241 242#if ENABLE_SILENCE_DETECTION 243 if (!mIsVideo) { 244 if (IsSilence(accessUnit)) { 245 if (!mInSilentMode) { 246 int64_t nowUs = ALooper::GetNowUs(); 247 248 if (mFirstSilentFrameUs < 0ll) { 249 mFirstSilentFrameUs = nowUs; 250 } else if (nowUs >= mFirstSilentFrameUs + 1000000ll) { 251 mInSilentMode = true; 252 ALOGI("audio in silent mode now."); 253 break; 254 } 255 } 256 } else { 257 if (mInSilentMode) { 258 ALOGI("audio no longer in silent mode."); 259 } 260 mInSilentMode = false; 261 mFirstSilentFrameUs = -1ll; 262 } 263 } 264#endif 265 266 mInputBufferQueue.push_back(accessUnit); 267 268 feedEncoderInputBuffers(); 269 270 scheduleDoMoreWork(); 271 } 272 break; 273 } 274 275 case kWhatDoMoreWork: 276 { 277 mDoMoreWorkPending = false; 278 279 if (mEncoder == NULL) { 280 break; 281 } 282 283 status_t err = doMoreWork(); 284 285 if (err != OK) { 286 notifyError(err); 287 } else { 288 scheduleDoMoreWork(); 289 } 290 break; 291 } 292 293 case kWhatRequestIDRFrame: 294 { 295 if (mEncoder == NULL) { 296 break; 297 } 298 299 if (mIsVideo) { 300 ALOGI("requesting IDR frame"); 301 mEncoder->requestIDRFrame(); 302 } 303 break; 304 } 305 306 case kWhatShutdown: 307 { 308 ALOGI("shutting down encoder"); 309 mEncoder->release(); 310 mEncoder.clear(); 311 312 AString mime; 313 CHECK(mInputFormat->findString("mime", &mime)); 314 ALOGI("encoder (%s) shut down.", mime.c_str()); 315 break; 316 } 317 318 default: 319 TRESPASS(); 320 } 321} 322 323void Converter::scheduleDoMoreWork() { 324 if (mDoMoreWorkPending) { 325 return; 326 } 327 328 mDoMoreWorkPending = true; 329 (new AMessage(kWhatDoMoreWork, id()))->post(mIsVideo ? 10000ll : 5000ll); 330} 331 332status_t Converter::feedEncoderInputBuffers() { 333 while (!mInputBufferQueue.empty() 334 && !mAvailEncoderInputIndices.empty()) { 335 sp<ABuffer> buffer = *mInputBufferQueue.begin(); 336 mInputBufferQueue.erase(mInputBufferQueue.begin()); 337 338 size_t bufferIndex = *mAvailEncoderInputIndices.begin(); 339 mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin()); 340 341 int64_t timeUs = 0ll; 342 uint32_t flags = 0; 343 344 if (buffer != NULL) { 345 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 346 347 memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(), 348 buffer->data(), 349 buffer->size()); 350 351 void *mediaBuffer; 352 if (buffer->meta()->findPointer("mediaBuffer", &mediaBuffer) 353 && mediaBuffer != NULL) { 354 mEncoderInputBuffers.itemAt(bufferIndex)->meta() 355 ->setPointer("mediaBuffer", mediaBuffer); 356 357 buffer->meta()->setPointer("mediaBuffer", NULL); 358 } 359 } else { 360 flags = MediaCodec::BUFFER_FLAG_EOS; 361 } 362 363 status_t err = mEncoder->queueInputBuffer( 364 bufferIndex, 0, (buffer == NULL) ? 0 : buffer->size(), 365 timeUs, flags); 366 367 if (err != OK) { 368 return err; 369 } 370 } 371 372 return OK; 373} 374 375status_t Converter::doMoreWork() { 376 size_t bufferIndex; 377 status_t err = mEncoder->dequeueInputBuffer(&bufferIndex); 378 379 if (err == OK) { 380 mAvailEncoderInputIndices.push_back(bufferIndex); 381 feedEncoderInputBuffers(); 382 } 383 384 for (;;) { 385 size_t offset; 386 size_t size; 387 int64_t timeUs; 388 uint32_t flags; 389 err = mEncoder->dequeueOutputBuffer( 390 &bufferIndex, &offset, &size, &timeUs, &flags); 391 392 if (err != OK) { 393 if (err == -EAGAIN) { 394 err = OK; 395 } 396 break; 397 } 398 399 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 400 sp<AMessage> notify = mNotify->dup(); 401 notify->setInt32("what", kWhatEOS); 402 notify->post(); 403 } else { 404 sp<ABuffer> buffer = new ABuffer(size); 405 buffer->meta()->setInt64("timeUs", timeUs); 406 407 if (!mIsVideo) { 408 ALOGV("audio time %lld us (%.2f secs)", timeUs, timeUs / 1E6); 409 } 410 411 memcpy(buffer->data(), 412 mEncoderOutputBuffers.itemAt(bufferIndex)->base() + offset, 413 size); 414 415 if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) { 416 mOutputFormat->setBuffer("csd-0", buffer); 417 } else { 418 sp<AMessage> notify = mNotify->dup(); 419 notify->setInt32("what", kWhatAccessUnit); 420 notify->setBuffer("accessUnit", buffer); 421 notify->post(); 422 } 423 } 424 425 mEncoder->releaseOutputBuffer(bufferIndex); 426 427 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 428 break; 429 } 430 } 431 432 return err; 433} 434 435void Converter::requestIDRFrame() { 436 (new AMessage(kWhatRequestIDRFrame, id()))->post(); 437} 438 439} // namespace android 440