NdkMediaCodec.cpp revision cdb42cdc5ccb785edabe1ee6407134fbae5662a9
1/* 2 * Copyright (C) 2014 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 "NdkMediaCodec" 19 20#include "NdkMediaCodec.h" 21#include "NdkMediaFormatPriv.h" 22 23#include <utils/Log.h> 24#include <utils/StrongPointer.h> 25#include <gui/Surface.h> 26 27#include <media/ICrypto.h> 28#include <media/stagefright/foundation/ALooper.h> 29#include <media/stagefright/foundation/AMessage.h> 30#include <media/stagefright/foundation/ABuffer.h> 31 32#include <media/stagefright/MediaCodec.h> 33#include <media/stagefright/MediaErrors.h> 34 35using namespace android; 36 37 38static int translate_error(status_t err) { 39 if (err == OK) { 40 return OK; 41 } else if (err == -EAGAIN) { 42 return AMEDIACODEC_INFO_TRY_AGAIN_LATER; 43 } 44 ALOGE("sf error code: %d", err); 45 return -1000; 46} 47 48enum { 49 kWhatActivityNotify, 50 kWhatRequestActivityNotifications, 51 kWhatStopActivityNotifications, 52}; 53 54 55class CodecHandler: public AHandler { 56private: 57 AMediaCodec* mCodec; 58public: 59 CodecHandler(AMediaCodec *codec); 60 virtual void onMessageReceived(const sp<AMessage> &msg); 61}; 62 63struct AMediaCodec { 64 sp<android::MediaCodec> mCodec; 65 sp<ALooper> mLooper; 66 sp<CodecHandler> mHandler; 67 sp<AMessage> mActivityNotification; 68 int32_t mGeneration; 69 bool mRequestedActivityNotification; 70 OnCodecEvent mCallback; 71 void *mCallbackUserData; 72}; 73 74CodecHandler::CodecHandler(AMediaCodec *codec) { 75 mCodec = codec; 76} 77 78void CodecHandler::onMessageReceived(const sp<AMessage> &msg) { 79 80 switch (msg->what()) { 81 case kWhatRequestActivityNotifications: 82 { 83 if (mCodec->mRequestedActivityNotification) { 84 break; 85 } 86 87 mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification); 88 mCodec->mRequestedActivityNotification = true; 89 break; 90 } 91 92 case kWhatActivityNotify: 93 { 94 { 95 int32_t generation; 96 msg->findInt32("generation", &generation); 97 98 if (generation != mCodec->mGeneration) { 99 // stale 100 break; 101 } 102 103 mCodec->mRequestedActivityNotification = false; 104 } 105 106 if (mCodec->mCallback) { 107 mCodec->mCallback(mCodec, mCodec->mCallbackUserData); 108 } 109 break; 110 } 111 112 case kWhatStopActivityNotifications: 113 { 114 uint32_t replyID; 115 msg->senderAwaitsResponse(&replyID); 116 117 mCodec->mGeneration++; 118 mCodec->mRequestedActivityNotification = false; 119 120 sp<AMessage> response = new AMessage; 121 response->postReply(replyID); 122 break; 123 } 124 125 default: 126 ALOGE("shouldn't be here"); 127 break; 128 } 129 130} 131 132 133static void requestActivityNotification(AMediaCodec *codec) { 134 (new AMessage(kWhatRequestActivityNotifications, codec->mHandler->id()))->post(); 135} 136 137extern "C" { 138 139static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool encoder) { 140 AMediaCodec *mData = new AMediaCodec(); 141 mData->mLooper = new ALooper; 142 mData->mLooper->setName("NDK MediaCodec_looper"); 143 status_t ret = mData->mLooper->start( 144 false, // runOnCallingThread 145 true, // canCallJava XXX 146 PRIORITY_FOREGROUND); 147 if (name_is_type) { 148 mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder); 149 } else { 150 mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name); 151 } 152 mData->mHandler = new CodecHandler(mData); 153 mData->mLooper->registerHandler(mData->mHandler); 154 mData->mGeneration = 1; 155 mData->mRequestedActivityNotification = false; 156 mData->mCallback = NULL; 157 158 return mData; 159} 160 161 162AMediaCodec* AMediaCodec_createCodecByName(const char *name) { 163 return createAMediaCodec(name, false, false); 164} 165 166AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) { 167 return createAMediaCodec(mime_type, true, false); 168} 169 170AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { 171 return createAMediaCodec(name, true, true); 172} 173 174int AMediaCodec_delete(AMediaCodec *mData) { 175 if (mData->mCodec != NULL) { 176 mData->mCodec->release(); 177 mData->mCodec.clear(); 178 } 179 180 if (mData->mLooper != NULL) { 181 mData->mLooper->unregisterHandler(mData->mHandler->id()); 182 mData->mLooper->stop(); 183 mData->mLooper.clear(); 184 } 185 delete mData; 186 return OK; 187} 188 189int AMediaCodec_configure( 190 AMediaCodec *mData, const AMediaFormat* format, ANativeWindow* window, uint32_t flags) { 191 sp<AMessage> nativeFormat; 192 AMediaFormat_getFormat(format, &nativeFormat); 193 ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); 194 sp<Surface> surface = NULL; 195 if (window != NULL) { 196 surface = (Surface*) window; 197 } 198 199 return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, flags)); 200} 201 202int AMediaCodec_start(AMediaCodec *mData) { 203 status_t ret = mData->mCodec->start(); 204 if (ret != OK) { 205 return translate_error(ret); 206 } 207 mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler->id()); 208 mData->mActivityNotification->setInt32("generation", mData->mGeneration); 209 requestActivityNotification(mData); 210 return OK; 211} 212 213int AMediaCodec_stop(AMediaCodec *mData) { 214 int ret = translate_error(mData->mCodec->stop()); 215 216 sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler->id()); 217 sp<AMessage> response; 218 msg->postAndAwaitResponse(&response); 219 mData->mActivityNotification.clear(); 220 221 return ret; 222} 223 224int AMediaCodec_flush(AMediaCodec *mData) { 225 return translate_error(mData->mCodec->flush()); 226} 227 228ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { 229 size_t idx; 230 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs); 231 requestActivityNotification(mData); 232 if (ret == OK) { 233 return idx; 234 } 235 return translate_error(ret); 236} 237 238uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 239 android::Vector<android::sp<android::ABuffer> > abufs; 240 if (mData->mCodec->getInputBuffers(&abufs) == 0) { 241 size_t n = abufs.size(); 242 if (idx >= n) { 243 ALOGE("buffer index %d out of range", idx); 244 return NULL; 245 } 246 if (out_size != NULL) { 247 *out_size = abufs[idx]->capacity(); 248 } 249 return abufs[idx]->data(); 250 } 251 ALOGE("couldn't get input buffers"); 252 return NULL; 253} 254 255uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 256 android::Vector<android::sp<android::ABuffer> > abufs; 257 if (mData->mCodec->getOutputBuffers(&abufs) == 0) { 258 size_t n = abufs.size(); 259 if (idx >= n) { 260 ALOGE("buffer index %d out of range", idx); 261 return NULL; 262 } 263 if (out_size != NULL) { 264 *out_size = abufs[idx]->capacity(); 265 } 266 return abufs[idx]->data(); 267 } 268 ALOGE("couldn't get output buffers"); 269 return NULL; 270} 271 272int AMediaCodec_queueInputBuffer(AMediaCodec *mData, 273 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { 274 275 AString errorMsg; 276 status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg); 277 return translate_error(ret); 278} 279 280ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData, 281 AMediaCodecBufferInfo *info, int64_t timeoutUs) { 282 size_t idx; 283 size_t offset; 284 size_t size; 285 uint32_t flags; 286 int64_t presentationTimeUs; 287 status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs, 288 &flags, timeoutUs); 289 requestActivityNotification(mData); 290 switch (ret) { 291 case OK: 292 info->offset = offset; 293 info->size = size; 294 info->flags = flags; 295 info->presentationTimeUs = presentationTimeUs; 296 return idx; 297 case -EAGAIN: 298 return AMEDIACODEC_INFO_TRY_AGAIN_LATER; 299 case android::INFO_FORMAT_CHANGED: 300 return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED; 301 case INFO_OUTPUT_BUFFERS_CHANGED: 302 return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED; 303 default: 304 break; 305 } 306 return translate_error(ret); 307} 308 309AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { 310 sp<AMessage> format; 311 mData->mCodec->getOutputFormat(&format); 312 return AMediaFormat_fromMsg(&format); 313} 314 315int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) { 316 if (render) { 317 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx)); 318 } else { 319 return translate_error(mData->mCodec->releaseOutputBuffer(idx)); 320 } 321} 322 323int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) { 324 mData->mCallback = callback; 325 mData->mCallbackUserData = userdata; 326 return OK; 327} 328 329 330} // extern "C" 331 332