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
466EXPORT
467media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData) {
468
469    if (mData == NULL) {
470        return AMEDIA_ERROR_INVALID_PARAMETER;
471    }
472
473    status_t err = mData->mCodec->signalEndOfInputStream();
474    if (err == INVALID_OPERATION) {
475        return AMEDIA_ERROR_INVALID_OPERATION;
476    }
477
478    return translate_error(err);
479
480}
481
482//EXPORT
483media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
484        void *userdata) {
485    mData->mCallback = callback;
486    mData->mCallbackUserData = userdata;
487    return AMEDIA_OK;
488}
489
490typedef struct AMediaCodecCryptoInfo {
491        int numsubsamples;
492        uint8_t key[16];
493        uint8_t iv[16];
494        cryptoinfo_mode_t mode;
495        cryptoinfo_pattern_t pattern;
496        size_t *clearbytes;
497        size_t *encryptedbytes;
498} AMediaCodecCryptoInfo;
499
500EXPORT
501media_status_t AMediaCodec_queueSecureInputBuffer(
502        AMediaCodec* codec,
503        size_t idx,
504        off_t offset,
505        AMediaCodecCryptoInfo* crypto,
506        uint64_t time,
507        uint32_t flags) {
508
509    CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples];
510    for (int i = 0; i < crypto->numsubsamples; i++) {
511        subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i];
512        subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
513    }
514
515    CryptoPlugin::Pattern pattern;
516    pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
517    pattern.mSkipBlocks = crypto->pattern.skipBlocks;
518
519    AString errormsg;
520    status_t err  = codec->mCodec->queueSecureInputBuffer(idx,
521            offset,
522            subSamples,
523            crypto->numsubsamples,
524            crypto->key,
525            crypto->iv,
526            (CryptoPlugin::Mode)crypto->mode,
527            pattern,
528            time,
529            flags,
530            &errormsg);
531    if (err != 0) {
532        ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
533    }
534    delete [] subSamples;
535    return translate_error(err);
536}
537
538
539EXPORT
540void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
541        cryptoinfo_pattern_t *pattern) {
542    info->pattern.encryptBlocks = pattern->encryptBlocks;
543    info->pattern.skipBlocks = pattern->skipBlocks;
544}
545
546EXPORT
547AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
548        int numsubsamples,
549        uint8_t key[16],
550        uint8_t iv[16],
551        cryptoinfo_mode_t mode,
552        size_t *clearbytes,
553        size_t *encryptedbytes) {
554
555    // size needed to store all the crypto data
556    size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
557    AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
558    if (!ret) {
559        ALOGE("couldn't allocate %zu bytes", cryptosize);
560        return NULL;
561    }
562    ret->numsubsamples = numsubsamples;
563    memcpy(ret->key, key, 16);
564    memcpy(ret->iv, iv, 16);
565    ret->mode = mode;
566    ret->pattern.encryptBlocks = 0;
567    ret->pattern.skipBlocks = 0;
568
569    // clearbytes and encryptedbytes point at the actual data, which follows
570    ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
571    ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes
572
573    memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
574    memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));
575
576    return ret;
577}
578
579
580EXPORT
581media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
582    free(info);
583    return AMEDIA_OK;
584}
585
586EXPORT
587size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
588    return ci->numsubsamples;
589}
590
591EXPORT
592media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
593    if (!ci) {
594        return AMEDIA_ERROR_INVALID_OBJECT;
595    }
596    if (!dst) {
597        return AMEDIA_ERROR_INVALID_PARAMETER;
598    }
599    memcpy(dst, ci->key, 16);
600    return AMEDIA_OK;
601}
602
603EXPORT
604media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
605    if (!ci) {
606        return AMEDIA_ERROR_INVALID_OBJECT;
607    }
608    if (!dst) {
609        return AMEDIA_ERROR_INVALID_PARAMETER;
610    }
611    memcpy(dst, ci->iv, 16);
612    return AMEDIA_OK;
613}
614
615EXPORT
616cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
617    if (!ci) {
618        return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT;
619    }
620    return ci->mode;
621}
622
623EXPORT
624media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
625    if (!ci) {
626        return AMEDIA_ERROR_INVALID_OBJECT;
627    }
628    if (!dst) {
629        return AMEDIA_ERROR_INVALID_PARAMETER;
630    }
631    memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
632    return AMEDIA_OK;
633}
634
635EXPORT
636media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
637    if (!ci) {
638        return AMEDIA_ERROR_INVALID_OBJECT;
639    }
640    if (!dst) {
641        return AMEDIA_ERROR_INVALID_PARAMETER;
642    }
643    memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
644    return AMEDIA_OK;
645}
646
647} // extern "C"
648
649