NdkMediaCodec.cpp revision 86aa02ce274826dc80ffa00766b16172c47503fd
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_createCodecByName(const char *name) { 92 return createAMediaCodec(name, false, false); 93} 94 95AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) { 96 return createAMediaCodec(mime_type, true, false); 97} 98 99AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { 100 return createAMediaCodec(name, true, 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( 119 AMediaCodec *mData, const AMediaFormat* format, ANativeWindow* window, uint32_t flags) { 120 sp<AMessage> nativeFormat; 121 AMediaFormat_getFormat(format, &nativeFormat); 122 ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); 123 sp<Surface> surface = NULL; 124 if (window != NULL) { 125 surface = (Surface*) window; 126 } 127 128 return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, flags)); 129} 130 131int AMediaCodec_start(AMediaCodec *mData) { 132 return translate_error(mData->mCodec->start()); 133} 134 135int AMediaCodec_stop(AMediaCodec *mData) { 136 return translate_error(mData->mCodec->stop()); 137} 138 139int AMediaCodec_flush(AMediaCodec *mData) { 140 return translate_error(mData->mCodec->flush()); 141} 142 143ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { 144 size_t idx; 145 status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs); 146 if (ret == OK) { 147 return idx; 148 } 149 return translate_error(ret); 150} 151 152uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 153 android::Vector<android::sp<android::ABuffer> > abufs; 154 if (mData->mCodec->getInputBuffers(&abufs) == 0) { 155 size_t n = abufs.size(); 156 if (idx >= n) { 157 ALOGE("buffer index %d out of range", idx); 158 return NULL; 159 } 160 if (out_size != NULL) { 161 *out_size = abufs[idx]->capacity(); 162 } 163 return abufs[idx]->data(); 164 } 165 ALOGE("couldn't get input buffers"); 166 return NULL; 167} 168 169uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { 170 android::Vector<android::sp<android::ABuffer> > abufs; 171 if (mData->mCodec->getOutputBuffers(&abufs) == 0) { 172 size_t n = abufs.size(); 173 if (idx >= n) { 174 ALOGE("buffer index %d out of range", idx); 175 return NULL; 176 } 177 if (out_size != NULL) { 178 *out_size = abufs[idx]->capacity(); 179 } 180 return abufs[idx]->data(); 181 } 182 ALOGE("couldn't get output buffers"); 183 return NULL; 184} 185 186int AMediaCodec_queueInputBuffer(AMediaCodec *mData, 187 size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { 188 189 AString errorMsg; 190 status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg); 191 return translate_error(ret); 192} 193 194ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData, 195 AMediaCodecBufferInfo *info, int64_t timeoutUs) { 196 size_t idx; 197 size_t offset; 198 size_t size; 199 uint32_t flags; 200 int64_t presentationTimeUs; 201 status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs, 202 &flags, timeoutUs); 203 204 switch (ret) { 205 case OK: 206 info->offset = offset; 207 info->size = size; 208 info->flags = flags; 209 info->presentationTimeUs = presentationTimeUs; 210 return idx; 211 case -EAGAIN: 212 return AMEDIACODEC_INFO_TRY_AGAIN_LATER; 213 case android::INFO_FORMAT_CHANGED: 214 return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED; 215 case INFO_OUTPUT_BUFFERS_CHANGED: 216 return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED; 217 default: 218 break; 219 } 220 return translate_error(ret); 221} 222 223AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { 224 sp<AMessage> format; 225 mData->mCodec->getOutputFormat(&format); 226 return AMediaFormat_fromMsg(&format); 227} 228 229int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) { 230 if (render) { 231 return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx)); 232 } else { 233 return translate_error(mData->mCodec->releaseOutputBuffer(idx)); 234 } 235} 236 237} // extern "C" 238 239