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