Converter.cpp revision 8d16bbc5a354d302abfd912b8d88d9c7feb3948f
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 break; 247 } 248 249 int64_t nowUs = ALooper::GetNowUs(); 250 251 if (mFirstSilentFrameUs < 0ll) { 252 mFirstSilentFrameUs = nowUs; 253 } else if (nowUs >= mFirstSilentFrameUs + 10000000ll) { 254 mInSilentMode = true; 255 ALOGI("audio in silent mode now."); 256 break; 257 } 258 } else { 259 if (mInSilentMode) { 260 ALOGI("audio no longer in silent mode."); 261 } 262 mInSilentMode = false; 263 mFirstSilentFrameUs = -1ll; 264 } 265 } 266#endif 267 268 mInputBufferQueue.push_back(accessUnit); 269 270 feedEncoderInputBuffers(); 271 272 scheduleDoMoreWork(); 273 } 274 break; 275 } 276 277 case kWhatDoMoreWork: 278 { 279 mDoMoreWorkPending = false; 280 281 if (mEncoder == NULL) { 282 break; 283 } 284 285 status_t err = doMoreWork(); 286 287 if (err != OK) { 288 notifyError(err); 289 } else { 290 scheduleDoMoreWork(); 291 } 292 break; 293 } 294 295 case kWhatRequestIDRFrame: 296 { 297 if (mEncoder == NULL) { 298 break; 299 } 300 301 if (mIsVideo) { 302 ALOGI("requesting IDR frame"); 303 mEncoder->requestIDRFrame(); 304 } 305 break; 306 } 307 308 case kWhatShutdown: 309 { 310 ALOGI("shutting down encoder"); 311 mEncoder->release(); 312 mEncoder.clear(); 313 314 AString mime; 315 CHECK(mInputFormat->findString("mime", &mime)); 316 ALOGI("encoder (%s) shut down.", mime.c_str()); 317 break; 318 } 319 320 default: 321 TRESPASS(); 322 } 323} 324 325void Converter::scheduleDoMoreWork() { 326 if (mDoMoreWorkPending) { 327 return; 328 } 329 330 mDoMoreWorkPending = true; 331 (new AMessage(kWhatDoMoreWork, id()))->post(1000ll); 332} 333 334status_t Converter::feedEncoderInputBuffers() { 335 while (!mInputBufferQueue.empty() 336 && !mAvailEncoderInputIndices.empty()) { 337 sp<ABuffer> buffer = *mInputBufferQueue.begin(); 338 mInputBufferQueue.erase(mInputBufferQueue.begin()); 339 340 size_t bufferIndex = *mAvailEncoderInputIndices.begin(); 341 mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin()); 342 343 int64_t timeUs = 0ll; 344 uint32_t flags = 0; 345 346 if (buffer != NULL) { 347 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 348 349 memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(), 350 buffer->data(), 351 buffer->size()); 352 353 void *mediaBuffer; 354 if (buffer->meta()->findPointer("mediaBuffer", &mediaBuffer) 355 && mediaBuffer != NULL) { 356 mEncoderInputBuffers.itemAt(bufferIndex)->meta() 357 ->setPointer("mediaBuffer", mediaBuffer); 358 359 buffer->meta()->setPointer("mediaBuffer", NULL); 360 } 361 } else { 362 flags = MediaCodec::BUFFER_FLAG_EOS; 363 } 364 365 status_t err = mEncoder->queueInputBuffer( 366 bufferIndex, 0, (buffer == NULL) ? 0 : buffer->size(), 367 timeUs, flags); 368 369 if (err != OK) { 370 return err; 371 } 372 } 373 374 return OK; 375} 376 377status_t Converter::doMoreWork() { 378 size_t bufferIndex; 379 status_t err = mEncoder->dequeueInputBuffer(&bufferIndex); 380 381 if (err == OK) { 382 mAvailEncoderInputIndices.push_back(bufferIndex); 383 feedEncoderInputBuffers(); 384 } 385 386 for (;;) { 387 size_t offset; 388 size_t size; 389 int64_t timeUs; 390 uint32_t flags; 391 err = mEncoder->dequeueOutputBuffer( 392 &bufferIndex, &offset, &size, &timeUs, &flags); 393 394 if (err != OK) { 395 if (err == -EAGAIN) { 396 err = OK; 397 } 398 break; 399 } 400 401 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 402 sp<AMessage> notify = mNotify->dup(); 403 notify->setInt32("what", kWhatEOS); 404 notify->post(); 405 } else { 406 sp<ABuffer> buffer = new ABuffer(size); 407 buffer->meta()->setInt64("timeUs", timeUs); 408 409 ALOGV("[%s] time %lld us (%.2f secs)", 410 mIsVideo ? "video" : "audio", timeUs, timeUs / 1E6); 411 412 memcpy(buffer->data(), 413 mEncoderOutputBuffers.itemAt(bufferIndex)->base() + offset, 414 size); 415 416 if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) { 417 mOutputFormat->setBuffer("csd-0", buffer); 418 } else { 419 sp<AMessage> notify = mNotify->dup(); 420 notify->setInt32("what", kWhatAccessUnit); 421 notify->setBuffer("accessUnit", buffer); 422 notify->post(); 423 } 424 } 425 426 mEncoder->releaseOutputBuffer(bufferIndex); 427 428 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 429 break; 430 } 431 } 432 433 return err; 434} 435 436void Converter::requestIDRFrame() { 437 (new AMessage(kWhatRequestIDRFrame, id()))->post(); 438} 439 440} // namespace android 441