NdkMediaCodec.cpp revision 0c3be875376adaee8d8e8dd917c64926e1513b29
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 48 49class CodecHandler: public AHandler { 50public: 51 CodecHandler(sp<android::MediaCodec>); 52 virtual void onMessageReceived(const sp<AMessage> &msg); 53}; 54 55CodecHandler::CodecHandler(sp<android::MediaCodec>) { 56 57} 58 59void CodecHandler::onMessageReceived(const sp<AMessage> &msg) { 60 ALOGI("handler got message %d", msg->what()); 61} 62 63struct AMediaCodec { 64 sp<android::MediaCodec> mCodec; 65 sp<ALooper> mLooper; 66 sp<CodecHandler> mHandler; 67}; 68 69extern "C" { 70 71static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool encoder) { 72 AMediaCodec *mData = new AMediaCodec(); 73 mData->mLooper = new ALooper; 74 mData->mLooper->setName("NDK MediaCodec_looper"); 75 status_t ret = mData->mLooper->start( 76 false, // runOnCallingThread 77 true, // canCallJava XXX 78 PRIORITY_FOREGROUND); 79 ALOGV("looper start: %d", ret); 80 if (name_is_type) { 81 mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder); 82 } else { 83 mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name); 84 } 85 mData->mHandler = new CodecHandler(mData->mCodec); 86 mData->mLooper->registerHandler(mData->mHandler); 87 return mData; 88} 89 90 91AMediaCodec* AMediaCodec_createByCodecName(const char *name) { 92 return createAMediaCodec(name, false, false); 93} 94 95AMediaCodec* AMediaCodec_createByCodecType(const char *mime_type) { 96 return createAMediaCodec(mime_type, true, false); 97} 98 99AMediaCodec* AMediaCodec_createEncoderByName(const char *name) { 100 return createAMediaCodec(name, false, true); 101} 102 103int AMediaCodec_delete(AMediaCodec *mData) { 104 if (mData->mCodec != NULL) { 105 mData->mCodec->release(); 106 mData->mCodec.clear(); 107 } 108 109 if (mData->mLooper != NULL) { 110 mData->mLooper->unregisterHandler(mData->mHandler->id()); 111 mData->mLooper->stop(); 112 mData->mLooper.clear(); 113 } 114 delete mData; 115 return OK; 116} 117 118int AMediaCodec_configure(AMediaCodec *mData, AMediaFormat *format, ANativeWindow* window) { 119 sp<AMessage> nativeFormat; 120 AMediaFormat_getFormat(format, &nativeFormat); 121 ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); 122 sp<Surface> surface = NULL; 123 if (window != NULL) { 124 surface = (Surface*) window; 125 } 126 127 return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, 0)); 128} 129 130int AMediaCodec_start(AMediaCodec *mData) { 131 return translate_error(mData->mCodec->start()); 132} 133 134int AMediaCodec_stop(AMediaCodec *mData) { 135 return translate_error(mData->mCodec->stop()); 136} 137 138int AMediaCodec_flush(AMediaCodec *mData) { 139 return translate_error(mData->mCodec->flush()); 140} 141 142ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { 143 size_t idx; 144 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs); 145 if (ret == OK) { 146 return idx; 147 } 148 return translate_error(ret); 149} 150 151uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 152 android::Vector<android::sp<android::ABuffer> > abufs; 153 if (mData->mCodec->getInputBuffers(&abufs) == 0) { 154 size_t n = abufs.size(); 155 if (idx >= n) { 156 ALOGE("buffer index %d out of range", idx); 157 return NULL; 158 } 159 if (out_size != NULL) { 160 *out_size = abufs[idx]->capacity(); 161 } 162 return abufs[idx]->data(); 163 } 164 ALOGE("couldn't get input buffers"); 165 return NULL; 166} 167 168uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 169 android::Vector<android::sp<android::ABuffer> > abufs; 170 if (mData->mCodec->getOutputBuffers(&abufs) == 0) { 171 size_t n = abufs.size(); 172 if (idx >= n) { 173 ALOGE("buffer index %d out of range", idx); 174 return NULL; 175 } 176 if (out_size != NULL) { 177 *out_size = abufs[idx]->capacity(); 178 } 179 return abufs[idx]->data(); 180 } 181 ALOGE("couldn't get output buffers"); 182 return NULL; 183} 184 185int AMediaCodec_queueInputBuffer(AMediaCodec *mData, 186 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { 187 188 AString errorMsg; 189 status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg); 190 return translate_error(ret); 191} 192 193ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData, 194 AMediaCodecBufferInfo *info, int64_t timeoutUs) { 195 size_t idx; 196 size_t offset; 197 size_t size; 198 uint32_t flags; 199 int64_t presentationTimeUs; 200 status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs, 201 &flags, timeoutUs); 202 203 switch (ret) { 204 case OK: 205 info->offset = offset; 206 info->size = size; 207 info->flags = flags; 208 info->presentationTimeUs = presentationTimeUs; 209 return idx; 210 case -EAGAIN: 211 return AMEDIACODEC_INFO_TRY_AGAIN_LATER; 212 case android::INFO_FORMAT_CHANGED: 213 return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED; 214 case INFO_OUTPUT_BUFFERS_CHANGED: 215 return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED; 216 default: 217 break; 218 } 219 return translate_error(ret); 220} 221 222AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { 223 sp<AMessage> format; 224 mData->mCodec->getOutputFormat(&format); 225 return AMediaFormat_fromMsg(&format); 226} 227 228int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) { 229 if (render) { 230 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx)); 231 } else { 232 return translate_error(mData->mCodec->releaseOutputBuffer(idx)); 233 } 234} 235 236} // extern "C" 237 238