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