188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber/*
288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * Copyright 2012, The Android Open Source Project
388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber *
488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * you may not use this file except in compliance with the License.
688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * You may obtain a copy of the License at
788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber *
888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber *     http://www.apache.org/licenses/LICENSE-2.0
988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber *
1088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * Unless required by applicable law or agreed to in writing, software
1188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
1288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * See the License for the specific language governing permissions and
1488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber * limitations under the License.
1588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber */
1688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
1788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber//#define LOG_NDEBUG 0
1888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#define LOG_TAG "MediaCodec-JNI"
1988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include <utils/Log.h>
2088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
2188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include "android_media_MediaCodec.h"
2288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
2307ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber#include "android_media_MediaCrypto.h"
240e0fee1e3a04023c9ec122d3bd7da54e9565c3e7Ray Essick#include "android_media_MediaMetricsJNI.h"
2588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include "android_media_Utils.h"
2688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include "android_runtime/AndroidRuntime.h"
2788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include "android_runtime/android_view_Surface.h"
28d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang#include "android_util_Binder.h"
2988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include "jni.h"
3088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include "JNIHelp.h"
3188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
32d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang#include <android/media/IDescrambler.h>
33d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang
347ac4f560dfe754eb4fe0d279fa03c1d9b3a7a5afLajos Molnar#include <cutils/compiler.h>
357ac4f560dfe754eb4fe0d279fa03c1d9b3a7a5afLajos Molnar
368335f1ccccedb6655d96d9d5b697a7f0938235ddMathias Agopian#include <gui/Surface.h>
378335f1ccccedb6655d96d9d5b697a7f0938235ddMathias Agopian
380e97fc248eaea7b4c95053618ddedf0af638110eAndreas Huber#include <media/ICrypto.h>
394273dd03a83fd5f9ba25f3b7c3a4add7bce7206cWonsik Kim#include <media/MediaCodecBuffer.h>
4088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include <media/stagefright/MediaCodec.h>
4188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include <media/stagefright/foundation/ABuffer.h>
4288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include <media/stagefright/foundation/ADebug.h>
4388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include <media/stagefright/foundation/ALooper.h>
4488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include <media/stagefright/foundation/AMessage.h>
45bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber#include <media/stagefright/foundation/AString.h>
4688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber#include <media/stagefright/MediaErrors.h>
478034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhang#include <media/stagefright/PersistentSurface.h>
488d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber#include <nativehelper/ScopedLocalRef.h>
498d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber
50b12a5390694e8525ac61d7377e266e31d124c815Andreas Huber#include <system/window.h>
51b12a5390694e8525ac61d7377e266e31d124c815Andreas Huber
5288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Hubernamespace android {
5388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
5488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber// Keep these in sync with their equivalents in MediaCodec.java !!!
5588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberenum {
5688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    DEQUEUE_INFO_TRY_AGAIN_LATER            = -1,
5788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED      = -2,
5888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED     = -3,
5988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber};
6088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
61aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huberenum {
628d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    EVENT_CALLBACK = 1,
638d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    EVENT_SET_CALLBACK = 2,
64d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    EVENT_FRAME_RENDERED = 3,
65aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber};
66aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
675f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hungstatic struct CryptoErrorCodes {
683ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker    jint cryptoErrorNoKey;
693ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker    jint cryptoErrorKeyExpired;
703ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker    jint cryptoErrorResourceBusy;
71336d3eabc0d57fd2d1b8a9aa4ade7a0450cf183eJeff Tinker    jint cryptoErrorInsufficientOutputProtection;
7296a2a957e42e04be817b60bb27199f3846f00fc9Jeff Tinker    jint cryptoErrorSessionNotOpened;
73d393216f8a2186eebdb8615c61787ae599c1432fJeff Tinker    jint cryptoErrorUnsupportedOperation;
743ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker} gCryptoErrorCodes;
753ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker
765f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hungstatic struct CodecActionCodes {
775f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    jint codecActionTransient;
785f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    jint codecActionRecoverable;
795f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung} gCodecActionCodes;
805f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung
81c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wustatic struct CodecErrorCodes {
82c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu    jint errorInsufficientResource;
83c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu    jint errorReclaimed;
84c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu} gCodecErrorCodes;
859e9ec943ce7620bbfcadc2f8986a80ac58003e47Ronghua Wu
868034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhangstatic struct {
878034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhang    jclass clazz;
888034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhang    jfieldID mLock;
898034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhang    jfieldID mPersistentObject;
908034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhang    jmethodID ctor;
918034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhang    jmethodID setNativeObjectLocked;
928034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhang} gPersistentSurfaceClassInfo;
938034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhang
94d4ea5d3eb630476a43da2adb4ac518360bd64758Jeff Tinkerstatic struct {
95d4ea5d3eb630476a43da2adb4ac518360bd64758Jeff Tinker    jint Unencrypted;
96d4ea5d3eb630476a43da2adb4ac518360bd64758Jeff Tinker    jint AesCtr;
97d4ea5d3eb630476a43da2adb4ac518360bd64758Jeff Tinker    jint AesCbc;
98d4ea5d3eb630476a43da2adb4ac518360bd64758Jeff Tinker} gCryptoModes;
99d4ea5d3eb630476a43da2adb4ac518360bd64758Jeff Tinker
100d4ea5d3eb630476a43da2adb4ac518360bd64758Jeff Tinker
10188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstruct fields_t {
10288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    jfieldID context;
103aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber    jmethodID postEventFromNativeID;
10491befdc0c4710234840cdfd853e7d30e8f9de62cAndreas Huber    jfieldID cryptoInfoNumSubSamplesID;
10591befdc0c4710234840cdfd853e7d30e8f9de62cAndreas Huber    jfieldID cryptoInfoNumBytesOfClearDataID;
10691befdc0c4710234840cdfd853e7d30e8f9de62cAndreas Huber    jfieldID cryptoInfoNumBytesOfEncryptedDataID;
10791befdc0c4710234840cdfd853e7d30e8f9de62cAndreas Huber    jfieldID cryptoInfoKeyID;
10891befdc0c4710234840cdfd853e7d30e8f9de62cAndreas Huber    jfieldID cryptoInfoIVID;
10991befdc0c4710234840cdfd853e7d30e8f9de62cAndreas Huber    jfieldID cryptoInfoModeID;
110d4ea5d3eb630476a43da2adb4ac518360bd64758Jeff Tinker    jfieldID cryptoInfoPatternID;
111d4ea5d3eb630476a43da2adb4ac518360bd64758Jeff Tinker    jfieldID patternEncryptBlocksID;
112d4ea5d3eb630476a43da2adb4ac518360bd64758Jeff Tinker    jfieldID patternSkipBlocksID;
11388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber};
11488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
11588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatic fields_t gFields;
1168034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhangstatic const void *sRefBaseOwner;
11788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
11888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber////////////////////////////////////////////////////////////////////////////////
11988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
12088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas HuberJMediaCodec::JMediaCodec(
12188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        JNIEnv *env, jobject thiz,
12288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        const char *name, bool nameIsType, bool encoder)
12388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    : mClass(NULL),
1248d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang      mObject(NULL) {
12588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    jclass clazz = env->GetObjectClass(thiz);
12688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    CHECK(clazz != NULL);
12788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
12888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    mClass = (jclass)env->NewGlobalRef(clazz);
12988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    mObject = env->NewWeakGlobalRef(thiz);
13088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
1317de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    cacheJavaObjects(env);
1327de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
13388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    mLooper = new ALooper;
13488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    mLooper->setName("MediaCodec_looper");
13588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
13688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    mLooper->start(
13788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            false,      // runOnCallingThread
138aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber            true,       // canCallJava
1398d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber            PRIORITY_FOREGROUND);
14088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
14188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (nameIsType) {
1425f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
14388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    } else {
1445f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
14588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
1465f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    CHECK((mCodec != NULL) != (mInitStatus != OK));
14788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
14888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
1497de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnarvoid JMediaCodec::cacheJavaObjects(JNIEnv *env) {
1507de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer");
1517de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    mByteBufferClass = (jclass)env->NewGlobalRef(clazz);
1527de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    CHECK(mByteBufferClass != NULL);
1537de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
1547de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    ScopedLocalRef<jclass> byteOrderClass(
1557de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            env, env->FindClass("java/nio/ByteOrder"));
1567de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    CHECK(byteOrderClass.get() != NULL);
1577de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
1587de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    jmethodID nativeOrderID = env->GetStaticMethodID(
1597de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
1607de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    CHECK(nativeOrderID != NULL);
1617de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
1627de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    jobject nativeByteOrderObj =
1637de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
1647de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj);
1657de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    CHECK(mNativeByteOrderObj != NULL);
1667de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    env->DeleteLocalRef(nativeByteOrderObj);
1677de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    nativeByteOrderObj = NULL;
1687de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
1697de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    mByteBufferOrderMethodID = env->GetMethodID(
1707de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            mByteBufferClass,
1717de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            "order",
1727de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
1737de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    CHECK(mByteBufferOrderMethodID != NULL);
1747de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
1757de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID(
1767de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
1777de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL);
1787de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
1797de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    mByteBufferPositionMethodID = env->GetMethodID(
1807de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            mByteBufferClass, "position", "(I)Ljava/nio/Buffer;");
1817de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    CHECK(mByteBufferPositionMethodID != NULL);
1827de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
1837de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    mByteBufferLimitMethodID = env->GetMethodID(
1847de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;");
1857de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    CHECK(mByteBufferLimitMethodID != NULL);
1867de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar}
1877de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
18888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatus_t JMediaCodec::initCheck() const {
1895f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    return mInitStatus;
19088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
19188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
192aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Hubervoid JMediaCodec::registerSelf() {
193aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber    mLooper->registerHandler(this);
194aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber}
195aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
196128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhangvoid JMediaCodec::release() {
197d932de9aff49d1d9f752ad479b42854d2557c881Martin Storsjo    if (mCodec != NULL) {
198d932de9aff49d1d9f752ad479b42854d2557c881Martin Storsjo        mCodec->release();
199d932de9aff49d1d9f752ad479b42854d2557c881Martin Storsjo        mCodec.clear();
2005f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        mInitStatus = NO_INIT;
201d932de9aff49d1d9f752ad479b42854d2557c881Martin Storsjo    }
20288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
203128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang    if (mLooper != NULL) {
204128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang        mLooper->unregisterHandler(id());
205128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang        mLooper->stop();
206128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang        mLooper.clear();
207128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang    }
208128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang}
209128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang
210128b012cc8c2369136bb8450bc91c81aebe18506Chong ZhangJMediaCodec::~JMediaCodec() {
211128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang    if (mCodec != NULL || mLooper != NULL) {
212128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang        /* MediaCodec and looper should have been released explicitly already
213128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang         * in setMediaCodec() (see comments in setMediaCodec()).
214128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang         *
215128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang         * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
216128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang         * message handler, doing release() there risks deadlock as MediaCodec::
217128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang         * release() post synchronous message to the same looper.
218128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang         *
219128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang         * Print a warning and try to proceed with releasing.
220128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang         */
221128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang        ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
222128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang        release();
223128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang        ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
224128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang    }
225128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang
22688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    JNIEnv *env = AndroidRuntime::getJNIEnv();
22788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
22888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    env->DeleteWeakGlobalRef(mObject);
22988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    mObject = NULL;
23088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    env->DeleteGlobalRef(mClass);
23188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    mClass = NULL;
2327de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    deleteJavaObjects(env);
2337de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar}
2347de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
2357de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnarvoid JMediaCodec::deleteJavaObjects(JNIEnv *env) {
2367de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    env->DeleteGlobalRef(mByteBufferClass);
2377de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    mByteBufferClass = NULL;
2387de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    env->DeleteGlobalRef(mNativeByteOrderObj);
2397de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    mNativeByteOrderObj = NULL;
2407de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
2417de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    mByteBufferOrderMethodID = NULL;
2427de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    mByteBufferAsReadOnlyBufferMethodID = NULL;
2437de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    mByteBufferPositionMethodID = NULL;
2447de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    mByteBufferLimitMethodID = NULL;
24588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
24688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
247d8578577b02cf6360402eb8726e964d18b46434dLajos Molnarstatus_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
248d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    if (enable) {
249d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        if (mOnFrameRenderedNotification == NULL) {
250d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar            mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
251d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        }
252d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    } else {
253d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        mOnFrameRenderedNotification.clear();
254d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    }
255d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar
256d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
257d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar}
258d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar
2598d5e556b2b76278000a506382fdf594c071e1fbdChong Zhangstatus_t JMediaCodec::setCallback(jobject cb) {
2608d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    if (cb != NULL) {
2618d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        if (mCallbackNotification == NULL) {
26263834f4d23a97b27d830a301328329c7ef682bd5Lajos Molnar            mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
2638d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        }
2648d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    } else {
2658d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        mCallbackNotification.clear();
2668d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    }
2678d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
2688d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    return mCodec->setCallback(mCallbackNotification);
2698d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang}
2708d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
27188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatus_t JMediaCodec::configure(
27288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        const sp<AMessage> &format,
273d47f7d8b5fe3a3861d7cbdc5f912235407823c8eAndy McFadden        const sp<IGraphicBufferProducer> &bufferProducer,
2748240d9239d9aabed75c49f9d4d69fd8a5fe4c899Andreas Huber        const sp<ICrypto> &crypto,
275d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang        const sp<IDescrambler> &descrambler,
27688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        int flags) {
27752800617946c456e78ed010c82d0ec4358368164Mathias Agopian    sp<Surface> client;
278d47f7d8b5fe3a3861d7cbdc5f912235407823c8eAndy McFadden    if (bufferProducer != NULL) {
279aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber        mSurfaceTextureClient =
280aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber            new Surface(bufferProducer, true /* controlledByApp */);
281b12a5390694e8525ac61d7377e266e31d124c815Andreas Huber    } else {
282b12a5390694e8525ac61d7377e266e31d124c815Andreas Huber        mSurfaceTextureClient.clear();
28388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
284b12a5390694e8525ac61d7377e266e31d124c815Andreas Huber
285d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang    return mCodec->configure(
286d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang            format, mSurfaceTextureClient, crypto, descrambler, flags);
28788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
28888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
2895e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnarstatus_t JMediaCodec::setSurface(
2905e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar        const sp<IGraphicBufferProducer> &bufferProducer) {
2915e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar    sp<Surface> client;
2925e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar    if (bufferProducer != NULL) {
2935e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar        client = new Surface(bufferProducer, true /* controlledByApp */);
2945e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar    }
2955e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar    status_t err = mCodec->setSurface(client);
2965e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar    if (err == OK) {
2975e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar        mSurfaceTextureClient = client;
2985e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar    }
2995e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar    return err;
3005e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar}
3015e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar
3022621e40d0e0a496a96575768b7e2b70e3b3be640Andy McFaddenstatus_t JMediaCodec::createInputSurface(
3032621e40d0e0a496a96575768b7e2b70e3b3be640Andy McFadden        sp<IGraphicBufferProducer>* bufferProducer) {
3042621e40d0e0a496a96575768b7e2b70e3b3be640Andy McFadden    return mCodec->createInputSurface(bufferProducer);
3052621e40d0e0a496a96575768b7e2b70e3b3be640Andy McFadden}
3062621e40d0e0a496a96575768b7e2b70e3b3be640Andy McFadden
3079560ddb48af0e2da7743452f8d9d6d9cd34d8438Chong Zhangstatus_t JMediaCodec::setInputSurface(
3088034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhang        const sp<PersistentSurface> &surface) {
3099560ddb48af0e2da7743452f8d9d6d9cd34d8438Chong Zhang    return mCodec->setInputSurface(surface);
3108034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhang}
3118034d60f6e044deafe48501dfbfe17c31284bc17Chong Zhang
31288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatus_t JMediaCodec::start() {
3138d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    return mCodec->start();
31488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
31588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
31688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatus_t JMediaCodec::stop() {
317b12a5390694e8525ac61d7377e266e31d124c815Andreas Huber    mSurfaceTextureClient.clear();
318b12a5390694e8525ac61d7377e266e31d124c815Andreas Huber
3198d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    return mCodec->stop();
32088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
32188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
32288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatus_t JMediaCodec::flush() {
32388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    return mCodec->flush();
32488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
32588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
3261e6e8018a4f914210b615bfca0f818fd13574228Lajos Molnarstatus_t JMediaCodec::reset() {
3271e6e8018a4f914210b615bfca0f818fd13574228Lajos Molnar    return mCodec->reset();
3281e6e8018a4f914210b615bfca0f818fd13574228Lajos Molnar}
3291e6e8018a4f914210b615bfca0f818fd13574228Lajos Molnar
33088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatus_t JMediaCodec::queueInputBuffer(
33188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        size_t index,
332bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber        size_t offset, size_t size, int64_t timeUs, uint32_t flags,
333bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber        AString *errorDetailMsg) {
334bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber    return mCodec->queueInputBuffer(
335bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber            index, offset, size, timeUs, flags, errorDetailMsg);
33688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
33788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
3389e6bcce17d13bd4f7bba5f8fbcc2e6a0d695274bAndreas Huberstatus_t JMediaCodec::queueSecureInputBuffer(
3399e6bcce17d13bd4f7bba5f8fbcc2e6a0d695274bAndreas Huber        size_t index,
3409e6bcce17d13bd4f7bba5f8fbcc2e6a0d695274bAndreas Huber        size_t offset,
3419e6bcce17d13bd4f7bba5f8fbcc2e6a0d695274bAndreas Huber        const CryptoPlugin::SubSample *subSamples,
3429e6bcce17d13bd4f7bba5f8fbcc2e6a0d695274bAndreas Huber        size_t numSubSamples,
3439e6bcce17d13bd4f7bba5f8fbcc2e6a0d695274bAndreas Huber        const uint8_t key[16],
3449e6bcce17d13bd4f7bba5f8fbcc2e6a0d695274bAndreas Huber        const uint8_t iv[16],
3459e6bcce17d13bd4f7bba5f8fbcc2e6a0d695274bAndreas Huber        CryptoPlugin::Mode mode,
346d4ea5d3eb630476a43da2adb4ac518360bd64758Jeff Tinker        const CryptoPlugin::Pattern &pattern,
3479e6bcce17d13bd4f7bba5f8fbcc2e6a0d695274bAndreas Huber        int64_t presentationTimeUs,
348bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber        uint32_t flags,
349bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber        AString *errorDetailMsg) {
3509e6bcce17d13bd4f7bba5f8fbcc2e6a0d695274bAndreas Huber    return mCodec->queueSecureInputBuffer(
351d4ea5d3eb630476a43da2adb4ac518360bd64758Jeff Tinker            index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
352bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber            presentationTimeUs, flags, errorDetailMsg);
3539e6bcce17d13bd4f7bba5f8fbcc2e6a0d695274bAndreas Huber}
3549e6bcce17d13bd4f7bba5f8fbcc2e6a0d695274bAndreas Huber
35588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatus_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
3568d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    return mCodec->dequeueInputBuffer(index, timeoutUs);
35788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
35888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
35988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatus_t JMediaCodec::dequeueOutputBuffer(
36088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
36188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    size_t size, offset;
36288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    int64_t timeUs;
36388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    uint32_t flags;
364aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber    status_t err = mCodec->dequeueOutputBuffer(
365aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber            index, &offset, &size, &timeUs, &flags, timeoutUs);
366aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
367aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber    if (err != OK) {
36888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        return err;
36988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
37088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
3718d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    ScopedLocalRef<jclass> clazz(
3728d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber            env, env->FindClass("android/media/MediaCodec$BufferInfo"));
37388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
3748d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
375fef85ef152ab176fd96dbe3047c8025136fa8560Ashok Bhat    env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
37688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
37788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    return OK;
37888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
37988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
3807c513b6bef8ed4dfc28e0af6c8594563fdb9f436Lajos Molnarstatus_t JMediaCodec::releaseOutputBuffer(
3817c513b6bef8ed4dfc28e0af6c8594563fdb9f436Lajos Molnar        size_t index, bool render, bool updatePTS, int64_t timestampNs) {
3827c513b6bef8ed4dfc28e0af6c8594563fdb9f436Lajos Molnar    if (updatePTS) {
3837c513b6bef8ed4dfc28e0af6c8594563fdb9f436Lajos Molnar        return mCodec->renderOutputBufferAndRelease(index, timestampNs);
3847c513b6bef8ed4dfc28e0af6c8594563fdb9f436Lajos Molnar    }
38588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    return render
38688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        ? mCodec->renderOutputBufferAndRelease(index)
38788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        : mCodec->releaseOutputBuffer(index);
38888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
38988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
3902621e40d0e0a496a96575768b7e2b70e3b3be640Andy McFaddenstatus_t JMediaCodec::signalEndOfInputStream() {
3912621e40d0e0a496a96575768b7e2b70e3b3be640Andy McFadden    return mCodec->signalEndOfInputStream();
3922621e40d0e0a496a96575768b7e2b70e3b3be640Andy McFadden}
3932621e40d0e0a496a96575768b7e2b70e3b3be640Andy McFadden
394d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnarstatus_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
39588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    sp<AMessage> msg;
39688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    status_t err;
397d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
398d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    if (err != OK) {
399d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar        return err;
400d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    }
401d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar
402d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    return ConvertMessageToMap(env, msg, format);
403d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar}
404d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar
405d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnarstatus_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
406d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    sp<AMessage> msg;
407d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    status_t err;
408d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
40988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        return err;
41088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
41188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
41288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    return ConvertMessageToMap(env, msg, format);
41388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
41488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
41588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatus_t JMediaCodec::getBuffers(
41688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        JNIEnv *env, bool input, jobjectArray *bufArray) const {
4174273dd03a83fd5f9ba25f3b7c3a4add7bce7206cWonsik Kim    Vector<sp<MediaCodecBuffer> > buffers;
41888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
41988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    status_t err =
42088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        input
42188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            ? mCodec->getInputBuffers(&buffers)
42288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            : mCodec->getOutputBuffers(&buffers);
42388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
42488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (err != OK) {
42588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        return err;
42688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
42788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
42888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    *bufArray = (jobjectArray)env->NewObjectArray(
4297de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            buffers.size(), mByteBufferClass, NULL);
430cbbea8e651feb580f439e28359d72589709fb120Marco Nelissen    if (*bufArray == NULL) {
431cbbea8e651feb580f439e28359d72589709fb120Marco Nelissen        return NO_MEMORY;
432cbbea8e651feb580f439e28359d72589709fb120Marco Nelissen    }
43388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
43488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    for (size_t i = 0; i < buffers.size(); ++i) {
4354273dd03a83fd5f9ba25f3b7c3a4add7bce7206cWonsik Kim        const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
43688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
4377de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        jobject byteBuffer = NULL;
4387de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        err = createByteBufferFromABuffer(
4397de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar                env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
4407de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        if (err != OK) {
4417de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            return err;
442cbbea8e651feb580f439e28359d72589709fb120Marco Nelissen        }
4437de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        if (byteBuffer != NULL) {
4447de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            env->SetObjectArrayElement(
4457de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar                    *bufArray, i, byteBuffer);
4467de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
447d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar            env->DeleteLocalRef(byteBuffer);
4487de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            byteBuffer = NULL;
449d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar        }
45088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
45188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
45288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    return OK;
45388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
45488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
4557de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar// static
4564273dd03a83fd5f9ba25f3b7c3a4add7bce7206cWonsik Kimtemplate <typename T>
4577de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnarstatus_t JMediaCodec::createByteBufferFromABuffer(
4584273dd03a83fd5f9ba25f3b7c3a4add7bce7206cWonsik Kim        JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
4597de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        jobject *buf) const {
460d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    // if this is an ABuffer that doesn't actually hold any accessible memory,
461d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    // use a null ByteBuffer
4627de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    *buf = NULL;
463e5b641e6effda54945577e9348df86213b38baebAaron Vaage
464e5b641e6effda54945577e9348df86213b38baebAaron Vaage    if (buffer == NULL) {
465e5b641e6effda54945577e9348df86213b38baebAaron Vaage        ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
466e5b641e6effda54945577e9348df86213b38baebAaron Vaage        return OK;
467e5b641e6effda54945577e9348df86213b38baebAaron Vaage    }
468e5b641e6effda54945577e9348df86213b38baebAaron Vaage
469d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    if (buffer->base() == NULL) {
470d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar        return OK;
471d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    }
472d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar
473d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    jobject byteBuffer =
4747de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        env->NewDirectByteBuffer(buffer->base(), buffer->capacity());
4757de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    if (readOnly && byteBuffer != NULL) {
476d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar        jobject readOnlyBuffer = env->CallObjectMethod(
4777de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar                byteBuffer, mByteBufferAsReadOnlyBufferMethodID);
478d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar        env->DeleteLocalRef(byteBuffer);
479d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar        byteBuffer = readOnlyBuffer;
480d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    }
481d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    if (byteBuffer == NULL) {
482d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar        return NO_MEMORY;
483d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    }
484d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    jobject me = env->CallObjectMethod(
4857de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj);
486d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    env->DeleteLocalRef(me);
487d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    me = env->CallObjectMethod(
4887de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            byteBuffer, mByteBufferLimitMethodID,
4897de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size()));
490d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    env->DeleteLocalRef(me);
4917be24522ce2e1821ad45e7ada7c3f91e6814889aLajos Molnar    me = env->CallObjectMethod(
4927de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            byteBuffer, mByteBufferPositionMethodID,
4937de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            clearBuffer ? 0 : buffer->offset());
4947be24522ce2e1821ad45e7ada7c3f91e6814889aLajos Molnar    env->DeleteLocalRef(me);
495d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    me = NULL;
496d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar
497d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    *buf = byteBuffer;
498d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    return OK;
499d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar}
500d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar
5017de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnarstatus_t JMediaCodec::getBuffer(
5027de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        JNIEnv *env, bool input, size_t index, jobject *buf) const {
5034273dd03a83fd5f9ba25f3b7c3a4add7bce7206cWonsik Kim    sp<MediaCodecBuffer> buffer;
5047de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5057de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    status_t err =
5067de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        input
5077de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            ? mCodec->getInputBuffer(index, &buffer)
5087de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            : mCodec->getOutputBuffer(index, &buffer);
5097de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5107de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    if (err != OK) {
5117de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        return err;
5127de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    }
5137de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5147de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    return createByteBufferFromABuffer(
5157de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
5167de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar}
5177de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
518d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnarstatus_t JMediaCodec::getImage(
519d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar        JNIEnv *env, bool input, size_t index, jobject *buf) const {
5204273dd03a83fd5f9ba25f3b7c3a4add7bce7206cWonsik Kim    sp<MediaCodecBuffer> buffer;
521d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar
522d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    status_t err =
523d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar        input
524d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar            ? mCodec->getInputBuffer(index, &buffer)
525d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar            : mCodec->getOutputBuffer(index, &buffer);
526d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar
527d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    if (err != OK) {
528d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar        return err;
529d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    }
530d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar
531d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    // if this is an ABuffer that doesn't actually hold any accessible memory,
532d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    // use a null ByteBuffer
533d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    *buf = NULL;
534d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    if (buffer->base() == NULL) {
535d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar        return OK;
536d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    }
537d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar
538d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    // check if buffer is an image
5397de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    sp<ABuffer> imageData;
5407de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    if (!buffer->meta()->findBuffer("image-data", &imageData)) {
5417de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        return OK;
5427de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    }
5437de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5447de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    int64_t timestamp = 0;
5457de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
5467de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        timestamp *= 1000; // adjust to ns
5477de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    }
5487de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5497de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    jobject byteBuffer = NULL;
5507de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    err = createByteBufferFromABuffer(
5517de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
5527de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    if (err != OK) {
5537de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        return OK;
5547de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    }
5557de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5567de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    jobject infoBuffer = NULL;
5577de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    err = createByteBufferFromABuffer(
5587de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
5597de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    if (err != OK) {
5607de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        env->DeleteLocalRef(byteBuffer);
5617de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        byteBuffer = NULL;
562d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar        return OK;
563d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    }
564d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar
5657de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    jobject cropRect = NULL;
5667de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    int32_t left, top, right, bottom;
5677de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
5687de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        ScopedLocalRef<jclass> rectClazz(
5697de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar                env, env->FindClass("android/graphics/Rect"));
5707de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        CHECK(rectClazz.get() != NULL);
5717de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5727de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        jmethodID rectConstructID = env->GetMethodID(
5737de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar                rectClazz.get(), "<init>", "(IIII)V");
5747de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5757de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        cropRect = env->NewObject(
5767de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar                rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
5777de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    }
5787de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5797de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    ScopedLocalRef<jclass> imageClazz(
5807de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            env, env->FindClass("android/media/MediaCodec$MediaImage"));
5817de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    CHECK(imageClazz.get() != NULL);
5827de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5837de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
5847de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
5857de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5867de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    *buf = env->NewObject(imageClazz.get(), imageConstructID,
5877de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            byteBuffer, infoBuffer,
5887de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            (jboolean)!input /* readOnly */,
5897de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            (jlong)timestamp,
5907de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar            (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
5917de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5927de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    // if MediaImage creation fails, return null
5937de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    if (env->ExceptionCheck()) {
5947de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        env->ExceptionDescribe();
5957de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        env->ExceptionClear();
5967de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        *buf = NULL;
5977de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    }
5987de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
5997de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    if (cropRect != NULL) {
6007de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        env->DeleteLocalRef(cropRect);
6017de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar        cropRect = NULL;
6027de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    }
6037de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
6047de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    env->DeleteLocalRef(byteBuffer);
6057de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    byteBuffer = NULL;
6067de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
6077de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    env->DeleteLocalRef(infoBuffer);
6087de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar    infoBuffer = NULL;
6097de28d34f1ca3a727a8325cf3304f2fe03d2ac59Lajos Molnar
610d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar    return OK;
611d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar}
612d4023114e8cf7ec7db4d07958a303699b658f2c0Lajos Molnar
613056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjostatus_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
614056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo    AString name;
615056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo
616056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo    status_t err = mCodec->getName(&name);
617056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo
618056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo    if (err != OK) {
619056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo        return err;
620056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo    }
621056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo
622056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo    *nameStr = env->NewStringUTF(name.c_str());
623056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo
624056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo    return OK;
625056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo}
626056ef2ed5ff92b742fe53f2498c596ec1f6bed3cMartin Storsjo
627f2d0e40bf01fa133dd6b36f3716005d53fa9776cRay Essickstatus_t JMediaCodec::getMetrics(JNIEnv *, MediaAnalyticsItem * &reply) const {
6280e0fee1e3a04023c9ec122d3bd7da54e9565c3e7Ray Essick
6290e0fee1e3a04023c9ec122d3bd7da54e9565c3e7Ray Essick    status_t status = mCodec->getMetrics(reply);
6300e0fee1e3a04023c9ec122d3bd7da54e9565c3e7Ray Essick    return status;
6310e0fee1e3a04023c9ec122d3bd7da54e9565c3e7Ray Essick}
6320e0fee1e3a04023c9ec122d3bd7da54e9565c3e7Ray Essick
633226065bbe60cf32b33a5f86d27e2db88138e4486Andreas Huberstatus_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
634226065bbe60cf32b33a5f86d27e2db88138e4486Andreas Huber    return mCodec->setParameters(msg);
635226065bbe60cf32b33a5f86d27e2db88138e4486Andreas Huber}
636226065bbe60cf32b33a5f86d27e2db88138e4486Andreas Huber
637b12a5390694e8525ac61d7377e266e31d124c815Andreas Hubervoid JMediaCodec::setVideoScalingMode(int mode) {
638b12a5390694e8525ac61d7377e266e31d124c815Andreas Huber    if (mSurfaceTextureClient != NULL) {
639b12a5390694e8525ac61d7377e266e31d124c815Andreas Huber        native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
640b12a5390694e8525ac61d7377e266e31d124c815Andreas Huber    }
641b12a5390694e8525ac61d7377e266e31d124c815Andreas Huber}
642b12a5390694e8525ac61d7377e266e31d124c815Andreas Huber
6435f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hungstatic jthrowable createCodecException(
6445f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
6455f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    ScopedLocalRef<jclass> clazz(
6465f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung            env, env->FindClass("android/media/MediaCodec$CodecException"));
6475f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    CHECK(clazz.get() != NULL);
6485f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung
649c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu    const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
6505f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    CHECK(ctor != NULL);
6515f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung
6525f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    ScopedLocalRef<jstring> msgObj(
6535f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung            env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
6545f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung
6555f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    // translate action code to Java equivalent
6565f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    switch (actionCode) {
6575f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    case ACTION_CODE_TRANSIENT:
6585f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        actionCode = gCodecActionCodes.codecActionTransient;
6595f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        break;
6605f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    case ACTION_CODE_RECOVERABLE:
6615f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        actionCode = gCodecActionCodes.codecActionRecoverable;
6625f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        break;
6635f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    default:
6645f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        actionCode = 0;  // everything else is fatal
6655f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        break;
6665f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    }
6675f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung
668c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu    /* translate OS errors to Java API CodecException errorCodes */
669c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu    switch (err) {
670c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu        case NO_MEMORY:
671c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu            err = gCodecErrorCodes.errorInsufficientResource;
672c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu            break;
673c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu        case DEAD_OBJECT:
674c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu            err = gCodecErrorCodes.errorReclaimed;
675c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu            break;
676c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu        default:  /* Other error codes go out as is. */
677c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu            break;
678c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu    }
679c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu
680c53ad69bcc920cdbdb15685ddad1d864631bb4f7Ronghua Wu    return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
6815f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung}
6825f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung
6838d5e556b2b76278000a506382fdf594c071e1fbdChong Zhangvoid JMediaCodec::handleCallback(const sp<AMessage> &msg) {
6848d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    int32_t arg1, arg2 = 0;
6858d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    jobject obj = NULL;
6868d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    CHECK(msg->findInt32("callbackID", &arg1));
6878d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    JNIEnv *env = AndroidRuntime::getJNIEnv();
6888d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
6898d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    switch (arg1) {
6908d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        case MediaCodec::CB_INPUT_AVAILABLE:
691aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber        {
6928d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            CHECK(msg->findInt32("index", &arg2));
6938d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            break;
6948d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        }
6958d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
6968d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        case MediaCodec::CB_OUTPUT_AVAILABLE:
6978d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        {
6988d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            CHECK(msg->findInt32("index", &arg2));
6998d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
7008d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            size_t size, offset;
7018d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            int64_t timeUs;
7028d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            uint32_t flags;
7038d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            CHECK(msg->findSize("size", &size));
7048d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            CHECK(msg->findSize("offset", &offset));
7058d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            CHECK(msg->findInt64("timeUs", &timeUs));
7068d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            CHECK(msg->findInt32("flags", (int32_t *)&flags));
7078d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
7088d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            ScopedLocalRef<jclass> clazz(
7098d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                    env, env->FindClass("android/media/MediaCodec$BufferInfo"));
7108d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
7118d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
7128d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
7138d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            obj = env->NewObject(clazz.get(), ctor);
7148d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
7158d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            if (obj == NULL) {
7168d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                if (env->ExceptionCheck()) {
7178d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                    ALOGE("Could not create MediaCodec.BufferInfo.");
7188d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                    env->ExceptionClear();
7198d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                }
7208d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                jniThrowException(env, "java/lang/IllegalStateException", NULL);
7218d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                return;
722aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber            }
723aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
7248d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
725aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber            break;
726aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber        }
727aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
7288d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        case MediaCodec::CB_ERROR:
729aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber        {
73094686d13cacbec1ce7cf5fd0178fffb037d03cc1Chong Zhang            int32_t err, actionCode;
73194686d13cacbec1ce7cf5fd0178fffb037d03cc1Chong Zhang            CHECK(msg->findInt32("err", &err));
7328d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            CHECK(msg->findInt32("actionCode", &actionCode));
733aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
7345f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung            // note that DRM errors could conceivably alias into a CodecException
7355f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung            obj = (jobject)createCodecException(env, err, actionCode);
736aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
7378d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            if (obj == NULL) {
7388d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                if (env->ExceptionCheck()) {
73994686d13cacbec1ce7cf5fd0178fffb037d03cc1Chong Zhang                    ALOGE("Could not create CodecException object.");
7408d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                    env->ExceptionClear();
7418d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                }
7428d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                jniThrowException(env, "java/lang/IllegalStateException", NULL);
7438d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                return;
7448d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            }
745aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
746aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber            break;
747aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber        }
748aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
7498d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
750aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber        {
7518d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            sp<AMessage> format;
7528d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            CHECK(msg->findMessage("format", &format));
753aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
7548d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            if (OK != ConvertMessageToMap(env, format, &obj)) {
7558d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                jniThrowException(env, "java/lang/IllegalStateException", NULL);
7568d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang                return;
7578d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            }
758aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
759aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber            break;
760aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber        }
761aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
762aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber        default:
763aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber            TRESPASS();
764aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber    }
7658d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
7668d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    env->CallVoidMethod(
7678d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            mObject,
7688d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            gFields.postEventFromNativeID,
7698d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            EVENT_CALLBACK,
7708d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            arg1,
7718d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            arg2,
7728d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            obj);
7738d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
7748d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    env->DeleteLocalRef(obj);
775aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber}
776aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
777d8578577b02cf6360402eb8726e964d18b46434dLajos Molnarvoid JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
778d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    int32_t arg1 = 0, arg2 = 0;
779d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    jobject obj = NULL;
780d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    JNIEnv *env = AndroidRuntime::getJNIEnv();
781d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar
782d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    sp<AMessage> data;
783d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    CHECK(msg->findMessage("data", &data));
784d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar
785d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    status_t err = ConvertMessageToMap(env, data, &obj);
786d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    if (err != OK) {
787d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        jniThrowException(env, "java/lang/IllegalStateException", NULL);
788d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        return;
789d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    }
790d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar
791d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    env->CallVoidMethod(
792d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar            mObject, gFields.postEventFromNativeID,
793d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar            EVENT_FRAME_RENDERED, arg1, arg2, obj);
794d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar
795d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    env->DeleteLocalRef(obj);
796d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar}
797d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar
7988d5e556b2b76278000a506382fdf594c071e1fbdChong Zhangvoid JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
7998d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    switch (msg->what()) {
8008d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        case kWhatCallbackNotify:
8018d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        {
8028d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            handleCallback(msg);
8038d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            break;
8048d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        }
805d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        case kWhatFrameRendered:
806d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        {
807d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar            handleFrameRenderedNotification(msg);
808d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar            break;
809d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        }
8108d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        default:
8118d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang            TRESPASS();
8128d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    }
813aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber}
814aba671392d6606e35726c350a28d0c9b36ebfe16Andreas Huber
81588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}  // namespace android
81688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
81788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber////////////////////////////////////////////////////////////////////////////////
81888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
81988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberusing namespace android;
82088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
82188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatic sp<JMediaCodec> setMediaCodec(
82288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
823075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context);
82488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (codec != NULL) {
82588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        codec->incStrong(thiz);
82688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
82788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    if (old != NULL) {
828128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang        /* release MediaCodec and stop the looper now before decStrong.
829128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang         * otherwise JMediaCodec::~JMediaCodec() could be called from within
830128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang         * its message handler, doing release() from there will deadlock
831128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang         * (as MediaCodec::release() post synchronous message to the same looper)
832128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang         */
833128b012cc8c2369136bb8450bc91c81aebe18506Chong Zhang        old->release();
83488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        old->decStrong(thiz);
83588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
836075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    env->SetLongField(thiz, gFields.context, (jlong)codec.get());
83788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
83888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    return old;
83988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
84088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
84188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatic sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
842075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    return (JMediaCodec *)env->GetLongField(thiz, gFields.context);
84388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
84488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
84588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatic void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
84688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    setMediaCodec(env, thiz, NULL);
84788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
84888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
8495f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hungstatic void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
8505f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    jthrowable exception = createCodecException(env, err, actionCode, msg);
8515f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    env->Throw(exception);
8525f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung}
8535f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung
854bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huberstatic void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
8558d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    ScopedLocalRef<jclass> clazz(
8568d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber            env, env->FindClass("android/media/MediaCodec$CryptoException"));
8578d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber    CHECK(clazz.get() != NULL);
858bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber
859bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber    jmethodID constructID =
8608d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
861bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber    CHECK(constructID != NULL);
862bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber
8633ccb34d7070d73ba6c7842801b070b41de32b842Jeff Tinker    const char *defaultMsg = "Unknown Error";
864bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber
8655f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung    /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
8663ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker    switch (err) {
8673ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker        case ERROR_DRM_NO_LICENSE:
8683ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker            err = gCryptoErrorCodes.cryptoErrorNoKey;
8693ccb34d7070d73ba6c7842801b070b41de32b842Jeff Tinker            defaultMsg = "Crypto key not available";
8703ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker            break;
8713ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker        case ERROR_DRM_LICENSE_EXPIRED:
8723ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker            err = gCryptoErrorCodes.cryptoErrorKeyExpired;
8733ccb34d7070d73ba6c7842801b070b41de32b842Jeff Tinker            defaultMsg = "License expired";
8743ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker            break;
8753ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker        case ERROR_DRM_RESOURCE_BUSY:
8763ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker            err = gCryptoErrorCodes.cryptoErrorResourceBusy;
8773ccb34d7070d73ba6c7842801b070b41de32b842Jeff Tinker            defaultMsg = "Resource busy or unavailable";
8783ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker            break;
879336d3eabc0d57fd2d1b8a9aa4ade7a0450cf183eJeff Tinker        case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
880336d3eabc0d57fd2d1b8a9aa4ade7a0450cf183eJeff Tinker            err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
8813ccb34d7070d73ba6c7842801b070b41de32b842Jeff Tinker            defaultMsg = "Required output protections are not active";
882336d3eabc0d57fd2d1b8a9aa4ade7a0450cf183eJeff Tinker            break;
88396a2a957e42e04be817b60bb27199f3846f00fc9Jeff Tinker        case ERROR_DRM_SESSION_NOT_OPENED:
88496a2a957e42e04be817b60bb27199f3846f00fc9Jeff Tinker            err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
8853ccb34d7070d73ba6c7842801b070b41de32b842Jeff Tinker            defaultMsg = "Attempted to use a closed session";
88696a2a957e42e04be817b60bb27199f3846f00fc9Jeff Tinker            break;
887d393216f8a2186eebdb8615c61787ae599c1432fJeff Tinker        case ERROR_DRM_CANNOT_HANDLE:
888d393216f8a2186eebdb8615c61787ae599c1432fJeff Tinker            err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
889d393216f8a2186eebdb8615c61787ae599c1432fJeff Tinker            defaultMsg = "Operation not supported in this configuration";
890d393216f8a2186eebdb8615c61787ae599c1432fJeff Tinker            break;
8915f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        default:  /* Other negative DRM error codes go out as is. */
8923ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker            break;
8933ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker    }
8943ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker
8953ccb34d7070d73ba6c7842801b070b41de32b842Jeff Tinker    jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg);
8963ccb34d7070d73ba6c7842801b070b41de32b842Jeff Tinker
897bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber    jthrowable exception =
8988d5f3e31c914e29129f50fe9830d71adf52ab5cfAndreas Huber        (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
899bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber
900bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber    env->Throw(exception);
901bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber}
902bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huber
903bfc56f497de0d18125366a02a93e61cdc0891be4Andreas Huberstatic jint throwExceptionAsNecessary(
9045f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
9055f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        const char *msg = NULL) {
90688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    switch (err) {
90788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        case OK:
90888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            return 0;
90988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
91088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        case -EAGAIN:
91188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            return DEQUEUE_INFO_TRY_AGAIN_LATER;
91288572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
91388572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        case INFO_FORMAT_CHANGED:
91488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
91588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
91688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        case INFO_OUTPUT_BUFFERS_CHANGED:
91788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber            return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
91888572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
9195f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        case INVALID_OPERATION:
9205f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung            jniThrowException(env, "java/lang/IllegalStateException", msg);
9215f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung            return 0;
9223ed38266c1647c6219ae5ad89cb3f867cf66caaaJeff Tinker
9235e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar        case BAD_VALUE:
9245e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar            jniThrowException(env, "java/lang/IllegalArgumentException", msg);
9255e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar            return 0;
9265e02ba977ede1e38c9f206057ec3f0f1e89ba943Lajos Molnar
92788572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        default:
9285f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung            if (isCryptoError(err)) {
9295f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung                throwCryptoException(env, err, msg);
9305f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung                return 0;
9315f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung            }
9325f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung            throwCodecException(env, err, actionCode, msg);
9335f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung            return 0;
93488572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber    }
93588572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber}
93688572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber
937d8578577b02cf6360402eb8726e964d18b46434dLajos Molnarstatic void android_media_MediaCodec_native_enableOnFrameRenderedListener(
938d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        JNIEnv *env,
939d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        jobject thiz,
940d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        jboolean enabled) {
941d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
942d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar
943d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    if (codec == NULL) {
944d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        throwExceptionAsNecessary(env, INVALID_OPERATION);
945d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar        return;
946d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    }
947d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar
948d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    status_t err = codec->enableOnFrameRenderedListener(enabled);
949d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar
950d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar    throwExceptionAsNecessary(env, err);
951d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar}
952d8578577b02cf6360402eb8726e964d18b46434dLajos Molnar
9538d5e556b2b76278000a506382fdf594c071e1fbdChong Zhangstatic void android_media_MediaCodec_native_setCallback(
9548d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        JNIEnv *env,
9558d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        jobject thiz,
9568d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        jobject cb) {
9578d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
9588d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
9598d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    if (codec == NULL) {
9605f9aa0bcea8be860fdf5a35476435616cb5f44f3Andy Hung        throwExceptionAsNecessary(env, INVALID_OPERATION);
9618d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang        return;
9628d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    }
9638d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
9648d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    status_t err = codec->setCallback(cb);
9658d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
9668d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang    throwExceptionAsNecessary(env, err);
9678d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang}
9688d5e556b2b76278000a506382fdf594c071e1fbdChong Zhang
96988572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huberstatic void android_media_MediaCodec_native_configure(
97088572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        JNIEnv *env,
97188572f7a3e9d7ef85c26865a0150f3c2041561c2Andreas Huber        jobject thiz,
972