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