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