Converter.cpp revision 44b59fd9326026d3f82dec25cde48c589b0438e7
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 mDoMoreWorkPending(false) { 44 mInitCheck = initEncoder(); 45} 46 47Converter::~Converter() { 48 if (mEncoder != NULL) { 49 mEncoder->release(); 50 mEncoder.clear(); 51 } 52} 53 54status_t Converter::initCheck() const { 55 return mInitCheck; 56} 57 58size_t Converter::getInputBufferCount() const { 59 return mEncoderInputBuffers.size(); 60} 61 62sp<AMessage> Converter::getOutputFormat() const { 63 return mOutputFormat; 64} 65 66static int32_t getBitrate(const char *propName, int32_t defaultValue) { 67 char val[PROPERTY_VALUE_MAX]; 68 if (property_get(propName, val, NULL)) { 69 char *end; 70 unsigned long x = strtoul(val, &end, 10); 71 72 if (*end == '\0' && end > val && x > 0) { 73 return x; 74 } 75 } 76 77 return defaultValue; 78} 79 80status_t Converter::initEncoder() { 81 AString inputMIME; 82 CHECK(mInputFormat->findString("mime", &inputMIME)); 83 84 AString outputMIME; 85 bool isAudio = false; 86 if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) { 87 outputMIME = MEDIA_MIMETYPE_AUDIO_AAC; 88 isAudio = true; 89 } else if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) { 90 outputMIME = MEDIA_MIMETYPE_VIDEO_AVC; 91 } else { 92 TRESPASS(); 93 } 94 95 mEncoder = MediaCodec::CreateByType( 96 mCodecLooper, outputMIME.c_str(), true /* encoder */); 97 98 if (mEncoder == NULL) { 99 return ERROR_UNSUPPORTED; 100 } 101 102 mOutputFormat = mInputFormat->dup(); 103 mOutputFormat->setString("mime", outputMIME.c_str()); 104 105 int32_t audioBitrate = getBitrate("media.wfd.audio-bitrate", 64000); 106 int32_t videoBitrate = getBitrate("media.wfd.video-bitrate", 10000000); 107 108 ALOGI("using audio bitrate of %d bps, video bitrate of %d bps", 109 audioBitrate, videoBitrate); 110 111 if (isAudio) { 112 mOutputFormat->setInt32("bitrate", audioBitrate); 113 } else { 114 mOutputFormat->setInt32("bitrate", videoBitrate); 115 mOutputFormat->setInt32("frame-rate", 60); 116 mOutputFormat->setInt32("i-frame-interval", 3); // Iframes every 3 secs 117 } 118 119 ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str()); 120 121 status_t err = mEncoder->configure( 122 mOutputFormat, 123 NULL /* nativeWindow */, 124 NULL /* crypto */, 125 MediaCodec::CONFIGURE_FLAG_ENCODE); 126 127 if (err != OK) { 128 return err; 129 } 130 131 err = mEncoder->start(); 132 133 if (err != OK) { 134 return err; 135 } 136 137 err = mEncoder->getInputBuffers(&mEncoderInputBuffers); 138 139 if (err != OK) { 140 return err; 141 } 142 143 return mEncoder->getOutputBuffers(&mEncoderOutputBuffers); 144} 145 146void Converter::feedAccessUnit(const sp<ABuffer> &accessUnit) { 147 sp<AMessage> msg = new AMessage(kWhatFeedAccessUnit, id()); 148 msg->setBuffer("accessUnit", accessUnit); 149 msg->post(); 150} 151 152void Converter::signalEOS() { 153 (new AMessage(kWhatInputEOS, id()))->post(); 154} 155 156void Converter::notifyError(status_t err) { 157 sp<AMessage> notify = mNotify->dup(); 158 notify->setInt32("what", kWhatError); 159 notify->setInt32("err", err); 160 notify->post(); 161} 162 163void Converter::onMessageReceived(const sp<AMessage> &msg) { 164 switch (msg->what()) { 165 case kWhatFeedAccessUnit: 166 { 167 sp<ABuffer> accessUnit; 168 CHECK(msg->findBuffer("accessUnit", &accessUnit)); 169 170 mInputBufferQueue.push_back(accessUnit); 171 172 feedEncoderInputBuffers(); 173 174 scheduleDoMoreWork(); 175 break; 176 } 177 178 case kWhatInputEOS: 179 { 180 mInputBufferQueue.push_back(NULL); 181 182 feedEncoderInputBuffers(); 183 184 scheduleDoMoreWork(); 185 break; 186 } 187 188 case kWhatDoMoreWork: 189 { 190 mDoMoreWorkPending = false; 191 status_t err = doMoreWork(); 192 193 if (err != OK) { 194 notifyError(err); 195 } else { 196 scheduleDoMoreWork(); 197 } 198 break; 199 } 200 201 default: 202 TRESPASS(); 203 } 204} 205 206void Converter::scheduleDoMoreWork() { 207 if (mDoMoreWorkPending) { 208 return; 209 } 210 211 mDoMoreWorkPending = true; 212 (new AMessage(kWhatDoMoreWork, id()))->post(1000ll); 213} 214 215status_t Converter::feedEncoderInputBuffers() { 216 while (!mInputBufferQueue.empty() 217 && !mAvailEncoderInputIndices.empty()) { 218 sp<ABuffer> buffer = *mInputBufferQueue.begin(); 219 mInputBufferQueue.erase(mInputBufferQueue.begin()); 220 221 size_t bufferIndex = *mAvailEncoderInputIndices.begin(); 222 mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin()); 223 224 int64_t timeUs = 0ll; 225 uint32_t flags = 0; 226 227 if (buffer != NULL) { 228 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 229 230 memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(), 231 buffer->data(), 232 buffer->size()); 233 234 void *mediaBuffer; 235 if (buffer->meta()->findPointer("mediaBuffer", &mediaBuffer) 236 && mediaBuffer != NULL) { 237 mEncoderInputBuffers.itemAt(bufferIndex)->meta() 238 ->setPointer("mediaBuffer", mediaBuffer); 239 240 buffer->meta()->setPointer("mediaBuffer", NULL); 241 } 242 } else { 243 flags = MediaCodec::BUFFER_FLAG_EOS; 244 } 245 246 status_t err = mEncoder->queueInputBuffer( 247 bufferIndex, 0, (buffer == NULL) ? 0 : buffer->size(), 248 timeUs, flags); 249 250 if (err != OK) { 251 return err; 252 } 253 } 254 255 return OK; 256} 257 258status_t Converter::doMoreWork() { 259 size_t bufferIndex; 260 status_t err = mEncoder->dequeueInputBuffer(&bufferIndex); 261 262 if (err == OK) { 263 mAvailEncoderInputIndices.push_back(bufferIndex); 264 feedEncoderInputBuffers(); 265 } 266 267 size_t offset; 268 size_t size; 269 int64_t timeUs; 270 uint32_t flags; 271 err = mEncoder->dequeueOutputBuffer( 272 &bufferIndex, &offset, &size, &timeUs, &flags); 273 274 if (err == OK) { 275 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 276 sp<AMessage> notify = mNotify->dup(); 277 notify->setInt32("what", kWhatEOS); 278 notify->post(); 279 } else { 280 sp<ABuffer> buffer = new ABuffer(size); 281 buffer->meta()->setInt64("timeUs", timeUs); 282 283 memcpy(buffer->data(), 284 mEncoderOutputBuffers.itemAt(bufferIndex)->base() + offset, 285 size); 286 287 if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) { 288 mOutputFormat->setBuffer("csd-0", buffer); 289 } else { 290 sp<AMessage> notify = mNotify->dup(); 291 notify->setInt32("what", kWhatAccessUnit); 292 notify->setBuffer("accessUnit", buffer); 293 notify->post(); 294 } 295 } 296 297 err = mEncoder->releaseOutputBuffer(bufferIndex); 298 } else if (err == -EAGAIN) { 299 err = OK; 300 } 301 302 return err; 303} 304 305} // namespace android 306 307