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