blob: 1789f7500458d56c29fdcc0fed4beea0f96cd6a8 [file] [log] [blame]
Marco Nelissen0c3be872014-05-01 10:14:44 -07001/*
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
Marco Nelissencdb42cd2014-05-08 14:46:05 -070048enum {
49 kWhatActivityNotify,
50 kWhatRequestActivityNotifications,
51 kWhatStopActivityNotifications,
Marco Nelissen0c3be872014-05-01 10:14:44 -070052};
53
Marco Nelissen0c3be872014-05-01 10:14:44 -070054
Marco Nelissencdb42cd2014-05-08 14:46:05 -070055class CodecHandler: public AHandler {
56private:
57 AMediaCodec* mCodec;
58public:
59 CodecHandler(AMediaCodec *codec);
60 virtual void onMessageReceived(const sp<AMessage> &msg);
61};
Marco Nelissen0c3be872014-05-01 10:14:44 -070062
63struct AMediaCodec {
64 sp<android::MediaCodec> mCodec;
65 sp<ALooper> mLooper;
66 sp<CodecHandler> mHandler;
Marco Nelissencdb42cd2014-05-08 14:46:05 -070067 sp<AMessage> mActivityNotification;
68 int32_t mGeneration;
69 bool mRequestedActivityNotification;
70 OnCodecEvent mCallback;
71 void *mCallbackUserData;
Marco Nelissen0c3be872014-05-01 10:14:44 -070072};
73
Marco Nelissencdb42cd2014-05-08 14:46:05 -070074CodecHandler::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
Marco Nelissen0c3be872014-05-01 10:14:44 -0700137extern "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);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700147 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 }
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700152 mData->mHandler = new CodecHandler(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700153 mData->mLooper->registerHandler(mData->mHandler);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700154 mData->mGeneration = 1;
155 mData->mRequestedActivityNotification = false;
156 mData->mCallback = NULL;
157
Marco Nelissen0c3be872014-05-01 10:14:44 -0700158 return mData;
159}
160
161
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700162AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700163 return createAMediaCodec(name, false, false);
164}
165
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700166AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700167 return createAMediaCodec(mime_type, true, false);
168}
169
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700170AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
171 return createAMediaCodec(name, true, true);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700172}
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
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700189int AMediaCodec_configure(
190 AMediaCodec *mData, const AMediaFormat* format, ANativeWindow* window, uint32_t flags) {
Marco Nelissen0c3be872014-05-01 10:14:44 -0700191 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
Marco Nelissen86aa02c2014-05-07 16:03:54 -0700199 return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, flags));
Marco Nelissen0c3be872014-05-01 10:14:44 -0700200}
201
202int AMediaCodec_start(AMediaCodec *mData) {
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700203 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;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700211}
212
213int AMediaCodec_stop(AMediaCodec *mData) {
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700214 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;
Marco Nelissen0c3be872014-05-01 10:14:44 -0700222}
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);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700231 requestActivityNotification(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700232 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);
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700289 requestActivityNotification(mData);
Marco Nelissen0c3be872014-05-01 10:14:44 -0700290 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
Marco Nelissencdb42cd2014-05-08 14:46:05 -0700323int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) {
324 mData->mCallback = callback;
325 mData->mCallbackUserData = userdata;
326 return OK;
327}
328
329
Marco Nelissen0c3be872014-05-01 10:14:44 -0700330} // extern "C"
331