NdkMediaCodec.cpp revision 19431587cec960606a8756fa2767bc4bce987318
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#include <inttypes.h>
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "NdkMediaCodec"
21
22#include "NdkMediaCodec.h"
23#include "NdkMediaError.h"
24#include "NdkMediaCryptoPriv.h"
25#include "NdkMediaFormatPriv.h"
26
27#include <utils/Log.h>
28#include <utils/StrongPointer.h>
29#include <gui/Surface.h>
30
31#include <media/stagefright/foundation/ALooper.h>
32#include <media/stagefright/foundation/AMessage.h>
33
34#include <media/stagefright/MediaCodec.h>
35#include <media/stagefright/MediaErrors.h>
36#include <media/MediaCodecBuffer.h>
37#include <android/native_window.h>
38
39using namespace android;
40
41
42static media_status_t translate_error(status_t err) {
43    if (err == OK) {
44        return AMEDIA_OK;
45    } else if (err == -EAGAIN) {
46        return (media_status_t) AMEDIACODEC_INFO_TRY_AGAIN_LATER;
47    }
48    ALOGE("sf error code: %d", err);
49    return AMEDIA_ERROR_UNKNOWN;
50}
51
52enum {
53    kWhatActivityNotify,
54    kWhatRequestActivityNotifications,
55    kWhatStopActivityNotifications,
56};
57
58
59class CodecHandler: public AHandler {
60private:
61    AMediaCodec* mCodec;
62public:
63    explicit CodecHandler(AMediaCodec *codec);
64    virtual void onMessageReceived(const sp<AMessage> &msg);
65};
66
67typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
68
69struct AMediaCodec {
70    sp<android::MediaCodec> mCodec;
71    sp<ALooper> mLooper;
72    sp<CodecHandler> mHandler;
73    sp<AMessage> mActivityNotification;
74    int32_t mGeneration;
75    bool mRequestedActivityNotification;
76    OnCodecEvent mCallback;
77    void *mCallbackUserData;
78};
79
80CodecHandler::CodecHandler(AMediaCodec *codec) {
81    mCodec = codec;
82}
83
84void CodecHandler::onMessageReceived(const sp<AMessage> &msg) {
85
86    switch (msg->what()) {
87        case kWhatRequestActivityNotifications:
88        {
89            if (mCodec->mRequestedActivityNotification) {
90                break;
91            }
92
93            mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification);
94            mCodec->mRequestedActivityNotification = true;
95            break;
96        }
97
98        case kWhatActivityNotify:
99        {
100            {
101                int32_t generation;
102                msg->findInt32("generation", &generation);
103
104                if (generation != mCodec->mGeneration) {
105                    // stale
106                    break;
107                }
108
109                mCodec->mRequestedActivityNotification = false;
110            }
111
112            if (mCodec->mCallback) {
113                mCodec->mCallback(mCodec, mCodec->mCallbackUserData);
114            }
115            break;
116        }
117
118        case kWhatStopActivityNotifications:
119        {
120            sp<AReplyToken> replyID;
121            msg->senderAwaitsResponse(&replyID);
122
123            mCodec->mGeneration++;
124            mCodec->mRequestedActivityNotification = false;
125
126            sp<AMessage> response = new AMessage;
127            response->postReply(replyID);
128            break;
129        }
130
131        default:
132            ALOGE("shouldn't be here");
133            break;
134    }
135
136}
137
138
139static void requestActivityNotification(AMediaCodec *codec) {
140    (new AMessage(kWhatRequestActivityNotifications, codec->mHandler))->post();
141}
142
143extern "C" {
144
145static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool encoder) {
146    AMediaCodec *mData = new AMediaCodec();
147    mData->mLooper = new ALooper;
148    mData->mLooper->setName("NDK MediaCodec_looper");
149    size_t res = mData->mLooper->start(
150            false,      // runOnCallingThread
151            true,       // canCallJava XXX
152            PRIORITY_FOREGROUND);
153    if (res != OK) {
154        ALOGE("Failed to start the looper");
155        AMediaCodec_delete(mData);
156        return NULL;
157    }
158    if (name_is_type) {
159        mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder);
160    } else {
161        mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name);
162    }
163    if (mData->mCodec == NULL) {  // failed to create codec
164        AMediaCodec_delete(mData);
165        return NULL;
166    }
167    mData->mHandler = new CodecHandler(mData);
168    mData->mLooper->registerHandler(mData->mHandler);
169    mData->mGeneration = 1;
170    mData->mRequestedActivityNotification = false;
171    mData->mCallback = NULL;
172
173    return mData;
174}
175
176EXPORT
177AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
178    return createAMediaCodec(name, false, false);
179}
180
181EXPORT
182AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
183    return createAMediaCodec(mime_type, true, false);
184}
185
186EXPORT
187AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
188    return createAMediaCodec(name, true, true);
189}
190
191EXPORT
192media_status_t AMediaCodec_delete(AMediaCodec *mData) {
193    if (mData != NULL) {
194        if (mData->mCodec != NULL) {
195            mData->mCodec->release();
196            mData->mCodec.clear();
197        }
198
199        if (mData->mLooper != NULL) {
200            if (mData->mHandler != NULL) {
201                mData->mLooper->unregisterHandler(mData->mHandler->id());
202            }
203            mData->mLooper->stop();
204            mData->mLooper.clear();
205        }
206        delete mData;
207    }
208    return AMEDIA_OK;
209}
210
211EXPORT
212media_status_t AMediaCodec_configure(
213        AMediaCodec *mData,
214        const AMediaFormat* format,
215        ANativeWindow* window,
216        AMediaCrypto *crypto,
217        uint32_t flags) {
218    sp<AMessage> nativeFormat;
219    AMediaFormat_getFormat(format, &nativeFormat);
220    ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str());
221    sp<Surface> surface = NULL;
222    if (window != NULL) {
223        surface = (Surface*) window;
224    }
225
226    return translate_error(mData->mCodec->configure(nativeFormat, surface,
227            crypto ? crypto->mCrypto : NULL, flags));
228}
229
230EXPORT
231media_status_t AMediaCodec_start(AMediaCodec *mData) {
232    status_t ret =  mData->mCodec->start();
233    if (ret != OK) {
234        return translate_error(ret);
235    }
236    mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler);
237    mData->mActivityNotification->setInt32("generation", mData->mGeneration);
238    requestActivityNotification(mData);
239    return AMEDIA_OK;
240}
241
242EXPORT
243media_status_t AMediaCodec_stop(AMediaCodec *mData) {
244    media_status_t ret = translate_error(mData->mCodec->stop());
245
246    sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler);
247    sp<AMessage> response;
248    msg->postAndAwaitResponse(&response);
249    mData->mActivityNotification.clear();
250
251    return ret;
252}
253
254EXPORT
255media_status_t AMediaCodec_flush(AMediaCodec *mData) {
256    return translate_error(mData->mCodec->flush());
257}
258
259EXPORT
260ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
261    size_t idx;
262    status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
263    requestActivityNotification(mData);
264    if (ret == OK) {
265        return idx;
266    }
267    return translate_error(ret);
268}
269
270EXPORT
271uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
272    android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
273    if (mData->mCodec->getInputBuffers(&abufs) == 0) {
274        size_t n = abufs.size();
275        if (idx >= n) {
276            ALOGE("buffer index %zu out of range", idx);
277            return NULL;
278        }
279        if (abufs[idx] == NULL) {
280            ALOGE("buffer index %zu is NULL", idx);
281            return NULL;
282        }
283        if (out_size != NULL) {
284            *out_size = abufs[idx]->capacity();
285        }
286        return abufs[idx]->data();
287    }
288    ALOGE("couldn't get input buffers");
289    return NULL;
290}
291
292EXPORT
293uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
294    android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
295    if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
296        size_t n = abufs.size();
297        if (idx >= n) {
298            ALOGE("buffer index %zu out of range", idx);
299            return NULL;
300        }
301        if (out_size != NULL) {
302            *out_size = abufs[idx]->capacity();
303        }
304        return abufs[idx]->data();
305    }
306    ALOGE("couldn't get output buffers");
307    return NULL;
308}
309
310EXPORT
311media_status_t AMediaCodec_queueInputBuffer(AMediaCodec *mData,
312        size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) {
313
314    AString errorMsg;
315    status_t ret = mData->mCodec->queueInputBuffer(idx, offset, size, time, flags, &errorMsg);
316    return translate_error(ret);
317}
318
319EXPORT
320ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
321        AMediaCodecBufferInfo *info, int64_t timeoutUs) {
322    size_t idx;
323    size_t offset;
324    size_t size;
325    uint32_t flags;
326    int64_t presentationTimeUs;
327    status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs,
328            &flags, timeoutUs);
329    requestActivityNotification(mData);
330    switch (ret) {
331        case OK:
332            info->offset = offset;
333            info->size = size;
334            info->flags = flags;
335            info->presentationTimeUs = presentationTimeUs;
336            return idx;
337        case -EAGAIN:
338            return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
339        case android::INFO_FORMAT_CHANGED:
340            return AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED;
341        case INFO_OUTPUT_BUFFERS_CHANGED:
342            return AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED;
343        default:
344            break;
345    }
346    return translate_error(ret);
347}
348
349EXPORT
350AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
351    sp<AMessage> format;
352    mData->mCodec->getOutputFormat(&format);
353    return AMediaFormat_fromMsg(&format);
354}
355
356EXPORT
357media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
358    if (render) {
359        return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
360    } else {
361        return translate_error(mData->mCodec->releaseOutputBuffer(idx));
362    }
363}
364
365EXPORT
366media_status_t AMediaCodec_releaseOutputBufferAtTime(
367        AMediaCodec *mData, size_t idx, int64_t timestampNs) {
368    ALOGV("render @ %" PRId64, timestampNs);
369    return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
370}
371
372EXPORT
373media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) {
374    sp<Surface> surface = NULL;
375    if (window != NULL) {
376        surface = (Surface*) window;
377    }
378    return translate_error(mData->mCodec->setSurface(surface));
379}
380
381EXPORT
382media_status_t AMediaCodec_createInputSurface(AMediaCodec *mData, ANativeWindow **surface) {
383    if (surface == NULL || mData == NULL) {
384        return AMEDIA_ERROR_INVALID_PARAMETER;
385    }
386    *surface = NULL;
387
388    sp<IGraphicBufferProducer> igbp = NULL;
389    status_t err = mData->mCodec->createInputSurface(&igbp);
390    if (err != NO_ERROR) {
391        return translate_error(err);
392    }
393
394    *surface = new Surface(igbp);
395    ANativeWindow_acquire(*surface);
396    return AMEDIA_OK;
397}
398
399//EXPORT
400media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
401        void *userdata) {
402    mData->mCallback = callback;
403    mData->mCallbackUserData = userdata;
404    return AMEDIA_OK;
405}
406
407typedef struct AMediaCodecCryptoInfo {
408        int numsubsamples;
409        uint8_t key[16];
410        uint8_t iv[16];
411        cryptoinfo_mode_t mode;
412        cryptoinfo_pattern_t pattern;
413        size_t *clearbytes;
414        size_t *encryptedbytes;
415} AMediaCodecCryptoInfo;
416
417EXPORT
418media_status_t AMediaCodec_queueSecureInputBuffer(
419        AMediaCodec* codec,
420        size_t idx,
421        off_t offset,
422        AMediaCodecCryptoInfo* crypto,
423        uint64_t time,
424        uint32_t flags) {
425
426    CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples];
427    for (int i = 0; i < crypto->numsubsamples; i++) {
428        subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i];
429        subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
430    }
431
432    CryptoPlugin::Pattern pattern;
433    pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
434    pattern.mSkipBlocks = crypto->pattern.skipBlocks;
435
436    AString errormsg;
437    status_t err  = codec->mCodec->queueSecureInputBuffer(idx,
438            offset,
439            subSamples,
440            crypto->numsubsamples,
441            crypto->key,
442            crypto->iv,
443            (CryptoPlugin::Mode)crypto->mode,
444            pattern,
445            time,
446            flags,
447            &errormsg);
448    if (err != 0) {
449        ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
450    }
451    delete [] subSamples;
452    return translate_error(err);
453}
454
455
456EXPORT
457void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
458        cryptoinfo_pattern_t *pattern) {
459    info->pattern.encryptBlocks = pattern->encryptBlocks;
460    info->pattern.skipBlocks = pattern->skipBlocks;
461}
462
463EXPORT
464AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
465        int numsubsamples,
466        uint8_t key[16],
467        uint8_t iv[16],
468        cryptoinfo_mode_t mode,
469        size_t *clearbytes,
470        size_t *encryptedbytes) {
471
472    // size needed to store all the crypto data
473    size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
474    AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
475    if (!ret) {
476        ALOGE("couldn't allocate %zu bytes", cryptosize);
477        return NULL;
478    }
479    ret->numsubsamples = numsubsamples;
480    memcpy(ret->key, key, 16);
481    memcpy(ret->iv, iv, 16);
482    ret->mode = mode;
483    ret->pattern.encryptBlocks = 0;
484    ret->pattern.skipBlocks = 0;
485
486    // clearbytes and encryptedbytes point at the actual data, which follows
487    ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
488    ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes
489
490    memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
491    memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));
492
493    return ret;
494}
495
496
497EXPORT
498media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
499    free(info);
500    return AMEDIA_OK;
501}
502
503EXPORT
504size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
505    return ci->numsubsamples;
506}
507
508EXPORT
509media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
510    if (!ci) {
511        return AMEDIA_ERROR_INVALID_OBJECT;
512    }
513    if (!dst) {
514        return AMEDIA_ERROR_INVALID_PARAMETER;
515    }
516    memcpy(dst, ci->key, 16);
517    return AMEDIA_OK;
518}
519
520EXPORT
521media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
522    if (!ci) {
523        return AMEDIA_ERROR_INVALID_OBJECT;
524    }
525    if (!dst) {
526        return AMEDIA_ERROR_INVALID_PARAMETER;
527    }
528    memcpy(dst, ci->iv, 16);
529    return AMEDIA_OK;
530}
531
532EXPORT
533cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
534    if (!ci) {
535        return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT;
536    }
537    return ci->mode;
538}
539
540EXPORT
541media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
542    if (!ci) {
543        return AMEDIA_ERROR_INVALID_OBJECT;
544    }
545    if (!dst) {
546        return AMEDIA_ERROR_INVALID_PARAMETER;
547    }
548    memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
549    return AMEDIA_OK;
550}
551
552EXPORT
553media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
554    if (!ci) {
555        return AMEDIA_ERROR_INVALID_OBJECT;
556    }
557    if (!dst) {
558        return AMEDIA_ERROR_INVALID_PARAMETER;
559    }
560    memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
561    return AMEDIA_OK;
562}
563
564} // extern "C"
565
566