Exemplo n.º 1
0
// NOTE: support to be called from read_thread
static int
inject_callback(void *opaque, int what, void *data, size_t data_size)
{
    JNIEnv     *env     = NULL;
    jobject     jbundle = NULL;
    int         ret     = -1;
    SDL_JNI_SetupThreadEnv(&env);

    jobject weak_thiz = (jobject) opaque;
    if (weak_thiz == NULL )
        goto fail;

    switch (what) {
    case IJKAVINJECT_CONCAT_RESOLVE_SEGMENT: {
        ret = _onNativeControlResolveSegment(env, weak_thiz, what, data, data_size);
        break;
    }
    case IJKAVINJECT_ON_TCP_OPEN:
    case IJKAVINJECT_ON_HTTP_OPEN:
    case IJKAVINJECT_ON_HTTP_RETRY:
    case IJKAVINJECT_ON_LIVE_RETRY: {
        IJKAVInject_OnUrlOpenData *real_data = (IJKAVInject_OnUrlOpenData *) data;
        jbundle = ASDK_Bundle__init(env);
        if (SDL_JNI_CatchException(env) || !jbundle) {
            ALOGE("%s: ASDK_Bundle__init failed\n", __func__);
            goto fail;
        }

        ASDK_Bundle__putString_c(env, jbundle,  "url",           real_data->url);
        ASDK_Bundle__putInt_c(env, jbundle,     "segment_index", real_data->segment_index);
        ASDK_Bundle__putInt_c(env, jbundle,     "retry_counter", real_data->retry_counter);

        if (!(*env)->CallStaticBooleanMethod(env, g_clazz.clazz, g_clazz.jmid_onNativeInvoke, weak_thiz, what, jbundle))
            goto fail;

        ASDK_Bundle__getString_cbuf(env, jbundle, "url", real_data->url, sizeof(real_data->url));
        ret = 0;
        break;
    }
    default: {
        goto fail;
    }
    }

fail:
    SDL_JNI_CatchException(env);
    SDL_JNI_DeleteLocalRefP(env, &jbundle);
    return ret;
}
ssize_t SDL_AMediaCodecJava_dequeueOutputBuffer(SDL_AMediaCodec* acodec, SDL_AMediaCodecBufferInfo *info, int64_t timeoutUs)
{
    AMCTRACE("%s(%d)", __func__, (int)timeoutUs);

    JNIEnv *env = NULL;
    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
        ALOGE("%s: SetupThreadEnv failed", __func__);
        return AMEDIACODEC__UNKNOWN_ERROR;
    }

    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
    jobject android_media_codec = opaque->android_media_codec;
    if (!opaque->output_buffer_info) {
        opaque->output_buffer_info = SDL_JNI_NewObjectAsGlobalRef(env, g_clazz_BufferInfo.clazz, g_clazz_BufferInfo.jmid__ctor);
        if (SDL_JNI_CatchException(env) || !opaque->output_buffer_info) {
            ALOGE("%s: SDL_JNI_NewObjectAsGlobalRef failed", __func__);
            return AMEDIACODEC__UNKNOWN_ERROR;
        }
    }

    jint idx = AMEDIACODEC__UNKNOWN_ERROR;
    while (1) {
        idx = (*env)->CallIntMethod(env, android_media_codec, g_clazz.jmid_dequeueOutputBuffer, opaque->output_buffer_info, (jlong)timeoutUs);
        if (SDL_JNI_CatchException(env)) {
            ALOGI("%s: Exception\n", __func__);
            return AMEDIACODEC__UNKNOWN_ERROR;
        }
        if (idx == AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED) {
            ALOGI("%s: INFO_OUTPUT_BUFFERS_CHANGED\n", __func__);
            SDL_JNI_DeleteGlobalRefP(env, &opaque->input_buffer_array);
            SDL_JNI_DeleteGlobalRefP(env, &opaque->output_buffer_array);
            continue;
        } else if (idx == AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED) {
            ALOGI("%s: INFO_OUTPUT_FORMAT_CHANGED\n", __func__);
        } else if (idx >= 0) {
            AMCTRACE("%s: buffer ready (%d) ====================\n", __func__, idx);
            if (info) {
                info->offset              = (*env)->GetIntField(env, opaque->output_buffer_info, g_clazz_BufferInfo.jfid_offset);
                info->size                = (*env)->GetIntField(env, opaque->output_buffer_info, g_clazz_BufferInfo.jfid_size);
                info->presentationTimeUs  = (*env)->GetLongField(env, opaque->output_buffer_info, g_clazz_BufferInfo.jfid_presentationTimeUs);
                info->flags               = (*env)->GetIntField(env, opaque->output_buffer_info, g_clazz_BufferInfo.jfid_flags);
            }
        }
        break;
    }

    return idx;
}
ssize_t SDL_AMediaCodecJava_dequeueInputBuffer(SDL_AMediaCodec* acodec, int64_t timeoutUs)
{
    AMCTRACE("%s(%d)", __func__, (int)timeoutUs);

    JNIEnv *env = NULL;
    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
        ALOGE("%s: SetupThreadEnv failed", __func__);
        return -1;
    }

    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
    // docs lie, getInputBuffers should be good after
    // m_codec->start() but the internal refs are not
    // setup until much later on some devices.
    //if (-1 == getInputBuffers(env, acodec)) {
    //    ALOGE("%s: getInputBuffers failed", __func__);
    //    return -1;
    //}

    jobject android_media_codec = opaque->android_media_codec;
    jint idx = (*env)->CallIntMethod(env, android_media_codec, g_clazz.jmid_dequeueInputBuffer, (jlong)timeoutUs);
    if (SDL_JNI_CatchException(env)) {
        ALOGE("%s: dequeueInputBuffer failed", __func__);
        opaque->is_input_buffer_valid = false;
        return -1;
    }

    return idx;
}
static sdl_amedia_status_t SDL_AMediaCodecJava_configure_surface(
    JNIEnv*env,
    SDL_AMediaCodec* acodec,
    const SDL_AMediaFormat* aformat,
    jobject android_surface,
    SDL_AMediaCrypto *crypto,
    uint32_t flags)
{
    SDLTRACE("SDL_AMediaCodecJava_configure_surface");

    // TODO: implement SDL_AMediaCrypto
    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
    jobject android_media_format = SDL_AMediaFormatJava_getObject(env, aformat);
    jobject android_media_codec  = SDL_AMediaCodecJava_getObject(env, acodec);
    ALOGE("configure acodec:%p format:%p: surface:%p", android_media_codec, android_media_format, android_surface);
    (*env)->CallVoidMethod(env, android_media_codec, g_clazz.jmid_configure, android_media_format, android_surface, crypto, flags);
    if (SDL_JNI_CatchException(env)) {
        return SDL_AMEDIA_ERROR_UNKNOWN;
    }

    opaque->is_input_buffer_valid = true;
    SDL_JNI_DeleteGlobalRefP(env, &opaque->input_buffer_array);
    SDL_JNI_DeleteGlobalRefP(env, &opaque->output_buffer_array);
    return SDL_AMEDIA_OK;
}
static sdl_amedia_status_t SDL_AMediaCodecJava_delete(SDL_AMediaCodec* acodec)
{
    ALOGI("%s\n", __func__);
    if (!acodec)
        return SDL_AMEDIA_OK;

    JNIEnv *env = NULL;
    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
        ALOGE("SDL_AMediaCodecJava_delete: SetupThreadEnv failed");
        return SDL_AMEDIA_ERROR_UNKNOWN;
    }

    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
    if (opaque) {
        if (opaque->android_media_codec) {
            (*env)->CallVoidMethod(env, opaque->android_media_codec, g_clazz.jmid_release);
            SDL_JNI_CatchException(env);
        }

        SDL_JNI_DeleteGlobalRefP(env, &opaque->output_buffer_info);
        SDL_JNI_DeleteGlobalRefP(env, &opaque->output_buffer);
        SDL_JNI_DeleteGlobalRefP(env, &opaque->output_buffer_array);
        SDL_JNI_DeleteGlobalRefP(env, &opaque->input_buffer);
        SDL_JNI_DeleteGlobalRefP(env, &opaque->input_buffer_array);
        SDL_JNI_DeleteGlobalRefP(env, &opaque->android_media_codec);
    }

    SDL_AMediaCodec_FreeInternal(acodec);
    return SDL_AMEDIA_OK;
}
Exemplo n.º 6
0
inline static void fillMetaInternal(JNIEnv *env, jobject jbundle, IjkMediaMeta *meta, const char *key, const char *default_value)
{
    const char *value = ijkmeta_get_string_l(meta, key);
    if (value == NULL )
        value = default_value;

    ASDK_Bundle__putString_c(env, jbundle, key, value);
    SDL_JNI_CatchException(env);
}
SDL_AMediaCodec* SDL_AMediaCodecJava_createDecoderByType(JNIEnv *env, const char *mime_type)
{
    SDLTRACE("%s", __func__);

    jstring jmime_type = (*env)->NewStringUTF(env, mime_type);
    if (SDL_JNI_CatchException(env) || !jmime_type) {
        return NULL;
    }

    jobject local_android_media_codec = (*env)->CallStaticObjectMethod(env, g_clazz.clazz, g_clazz.jmid_createDecoderByType, jmime_type);
    SDL_JNI_DeleteLocalRefP(env, &jmime_type);
    if (SDL_JNI_CatchException(env) || !local_android_media_codec) {
        return NULL;
    }

    SDL_AMediaCodec* acodec = SDL_AMediaCodecJava_init(env, local_android_media_codec);
    SDL_JNI_DeleteLocalRefP(env, &local_android_media_codec);
    return acodec;
}
Exemplo n.º 8
0
static bool mediacodec_select_callback(void *opaque, ijkmp_mediacodecinfo_context *mcc)
{
    JNIEnv *env = NULL;
    jobject jmime = NULL;
    jstring jcodec_name = NULL;
    jobject weak_this = (jobject) opaque;
    const char *codec_name = NULL;
    bool found_codec = false;

    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
        ALOGE("%s: SetupThreadEnv failed\n", __func__);
        return -1;
    }

    jmime = (*env)->NewStringUTF(env, mcc->mime_type);
    if (SDL_JNI_CatchException(env) || !jmime) {
        goto fail;
    }

    jcodec_name = (*env)->CallStaticObjectMethod(env, g_clazz.clazz, g_clazz.jmid_onSelectCodec, weak_this, jmime, mcc->profile, mcc->level);
    if (SDL_JNI_CatchException(env) || !jcodec_name) {
        goto fail;
    }

    codec_name = (*env)->GetStringUTFChars(env, jcodec_name, NULL );
    if (!codec_name || !*codec_name) {
        goto fail;
    }

    strncpy(mcc->codec_name, codec_name, sizeof(mcc->codec_name) / sizeof(*mcc->codec_name));
    mcc->codec_name[sizeof(mcc->codec_name) / sizeof(*mcc->codec_name) - 1] = 0;
    found_codec = true;
    fail:
    if (codec_name) {
        (*env)->ReleaseStringUTFChars(env, jcodec_name, codec_name);
        codec_name = NULL;
    }

    SDL_JNI_DeleteLocalRefP(env, &jcodec_name);
    SDL_JNI_DeleteLocalRefP(env, &jmime);
    return found_codec;
}
SDL_AMediaCodec* SDL_AMediaCodecJava_createByCodecName(JNIEnv *env, const char *codec_name)
{
    SDLTRACE("%s", __func__);

    jstring jcodec_name = (*env)->NewStringUTF(env, codec_name);
    if (SDL_JNI_CatchException(env) || !jcodec_name) {
        return NULL;
    }

    jobject local_android_media_codec = (*env)->CallStaticObjectMethod(env, g_clazz.clazz, g_clazz.jmid_createByCodecName, jcodec_name);
    SDL_JNI_DeleteLocalRefP(env, &jcodec_name);
    if (SDL_JNI_CatchException(env) || !local_android_media_codec) {
        return NULL;
    }

    SDL_AMediaCodec* acodec = SDL_AMediaCodecJava_init(env, local_android_media_codec);
    acodec->object_serial = SDL_AMediaCodec_create_object_serial();
    SDL_JNI_DeleteLocalRefP(env, &local_android_media_codec);
    return acodec;
}
static uint8_t* SDL_AMediaCodecJava_getInputBuffer(SDL_AMediaCodec* acodec, size_t idx, size_t *out_size)
{
    AMCTRACE("%s", __func__);

    JNIEnv *env = NULL;
    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
        ALOGE("%s: SetupThreadEnv failed", __func__);
        return NULL;
    }

    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
    if (0 != getInputBuffers(env, acodec))
        return NULL;

    assert(opaque->input_buffer_array);
    int buffer_count = (*env)->GetArrayLength(env, opaque->input_buffer_array);
    if (SDL_JNI_CatchException(env) || idx < 0 || idx >= buffer_count) {
        ALOGE("%s: idx(%d) < count(%d)\n", __func__, (int)idx, (int)buffer_count);
        return NULL;
    }

    SDL_JNI_DeleteGlobalRefP(env, &opaque->input_buffer);
    jobject local_input_buffer = (*env)->GetObjectArrayElement(env, opaque->input_buffer_array, idx);
    if (SDL_JNI_CatchException(env) || !local_input_buffer) {
        ALOGE("%s: GetObjectArrayElement failed\n", __func__);
        return NULL;
    }
    opaque->input_buffer = (*env)->NewGlobalRef(env, local_input_buffer);
    SDL_JNI_DeleteLocalRefP(env, &local_input_buffer);
    if (SDL_JNI_CatchException(env) || !opaque->input_buffer) {
        ALOGE("%s: GetObjectArrayElement.NewGlobalRef failed\n", __func__);
        return NULL;
    }

    jlong size = (*env)->GetDirectBufferCapacity(env, opaque->input_buffer);
    void *ptr  = (*env)->GetDirectBufferAddress(env, opaque->input_buffer);

    if (out_size)
        *out_size = size;
    return ptr;
}
inline static int getOutputBuffers(JNIEnv *env, SDL_AMediaCodec* acodec)
{
    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
    jobject android_media_codec = opaque->android_media_codec;
    SDL_JNI_DeleteGlobalRefP(env, &opaque->output_buffer_array);
    if (opaque->output_buffer_array)
        return 0;

    jobjectArray local_output_buffer_array = (*env)->CallObjectMethod(env, android_media_codec, g_clazz.jmid_getOutputBuffers);
    if (SDL_JNI_CatchException(env) || !local_output_buffer_array) {
        ALOGE("%s: getInputBuffers failed\n", __func__);
        return -1;
    }

    opaque->output_buffer_array = (*env)->NewGlobalRef(env, local_output_buffer_array);
    SDL_JNI_DeleteLocalRefP(env, &local_output_buffer_array);
    if (SDL_JNI_CatchException(env) || !opaque->output_buffer_array) {
        ALOGE("%s: getOutputBuffers.NewGlobalRef failed\n", __func__);
        return -1;
    }

    return 0;
}
sdl_amedia_status_t SDL_AMediaCodecJava_queueInputBuffer(SDL_AMediaCodec* acodec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags)
{
    AMCTRACE("%s: %d", __func__, (int)idx);

    JNIEnv *env = NULL;
    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
        ALOGE("SDL_AMediaCodecJava_queueInputBuffer: SetupThreadEnv failed");
        return SDL_AMEDIA_ERROR_UNKNOWN;
    }

    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
    jobject android_media_codec = opaque->android_media_codec;
    (*env)->CallVoidMethod(env, android_media_codec, g_clazz.jmid_queueInputBuffer, (jint)idx, (jint)offset, (jint)size, (jlong)time, (jint)flags);
    if (SDL_JNI_CatchException(env)) {
        return SDL_AMEDIA_ERROR_UNKNOWN;
    }

    return SDL_AMEDIA_OK;
}
static sdl_amedia_status_t SDL_AMediaCodecJava_flush(SDL_AMediaCodec* acodec)
{
    SDLTRACE("%s", __func__);

    JNIEnv *env = NULL;
    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
        ALOGE("%s: SetupThreadEnv failed", __func__);
        return SDL_AMEDIA_ERROR_UNKNOWN;
    }

    jobject android_media_codec = SDL_AMediaCodecJava_getObject(env, acodec);
    (*env)->CallVoidMethod(env, android_media_codec, g_clazz.jmid_flush, android_media_codec);
    if (SDL_JNI_CatchException(env)) {
        ALOGE("%s: flush", __func__);
        return SDL_AMEDIA_ERROR_UNKNOWN;
    }

    return SDL_AMEDIA_OK;
}
static SDL_AMediaCodec* SDL_AMediaCodecJava_init(JNIEnv *env, jobject android_media_codec)
{
    SDLTRACE("%s", __func__);

    jobject global_android_media_codec = (*env)->NewGlobalRef(env, android_media_codec);
    if (SDL_JNI_CatchException(env) || !global_android_media_codec) {
        return NULL;
    }

    SDL_AMediaCodec *acodec = SDL_AMediaCodec_CreateInternal(sizeof(SDL_AMediaCodec_Opaque));
    if (!acodec) {
        SDL_JNI_DeleteGlobalRefP(env, &global_android_media_codec);
        return NULL;
    }

    SDL_AMediaCodec_Opaque *opaque = acodec->opaque;
    opaque->android_media_codec         = global_android_media_codec;

    acodec->opaque_class                = &g_amediacodec_class;
    acodec->func_delete                 = SDL_AMediaCodecJava_delete;
    acodec->func_configure              = NULL;
    acodec->func_configure_surface      = SDL_AMediaCodecJava_configure_surface;

    acodec->func_start                  = SDL_AMediaCodecJava_start;
    acodec->func_stop                   = SDL_AMediaCodecJava_stop;
    acodec->func_flush                  = SDL_AMediaCodecJava_flush;

    acodec->func_getInputBuffer         = SDL_AMediaCodecJava_getInputBuffer;
    acodec->func_getOutputBuffer        = SDL_AMediaCodecJava_getOutputBuffer;

    acodec->func_dequeueInputBuffer     = SDL_AMediaCodecJava_dequeueInputBuffer;
    acodec->func_queueInputBuffer       = SDL_AMediaCodecJava_queueInputBuffer;

    acodec->func_dequeueOutputBuffer    = SDL_AMediaCodecJava_dequeueOutputBuffer;
    acodec->func_getOutputFormat        = SDL_AMediaCodecJava_getOutputFormat;
    acodec->func_releaseOutputBuffer    = SDL_AMediaCodecJava_releaseOutputBuffer;

    acodec->func_isInputBuffersValid    = SDL_AMediaCodecJava_isInputBuffersValid;

    SDL_AMediaCodec_increaseReference(acodec);
    return acodec;
}
static sdl_amedia_status_t SDL_AMediaCodecJava_start(SDL_AMediaCodec* acodec)
{
    SDLTRACE("%s", __func__);

    JNIEnv *env = NULL;
    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
        ALOGE("%s: SetupThreadEnv failed", __func__);
        return SDL_AMEDIA_ERROR_UNKNOWN;
    }

    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
    jobject android_media_codec    = opaque->android_media_codec;
    (*env)->CallVoidMethod(env, android_media_codec, g_clazz.jmid_start, android_media_codec);
    if (SDL_JNI_CatchException(env)) {
        ALOGE("%s: start failed", __func__);
        return SDL_AMEDIA_ERROR_UNKNOWN;
    }

    return SDL_AMEDIA_OK;
}
sdl_amedia_status_t SDL_AMediaCodecJava_releaseOutputBuffer(SDL_AMediaCodec* acodec, size_t idx, bool render)
{
    AMCTRACE("%s", __func__);

    JNIEnv *env = NULL;
    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
        ALOGE("%s(%d, %s): SetupThreadEnv failed", __func__, (int)idx, render ? "true" : "false");
        return SDL_AMEDIA_ERROR_UNKNOWN;
    }

    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)acodec->opaque;
    jobject android_media_codec = opaque->android_media_codec;
    (*env)->CallVoidMethod(env, android_media_codec, g_clazz.jmid_releaseOutputBuffer, (jint)idx, (jboolean)render);
    if (SDL_JNI_CatchException(env)) {
        ALOGE("%s: releaseOutputBuffer\n", __func__);
        return SDL_AMEDIA_ERROR_UNKNOWN;
    }

    return SDL_AMEDIA_OK;
}
SDL_AMediaFormat *SDL_AMediaCodecJava_getOutputFormat(SDL_AMediaCodec *thiz)
{
    if (!thiz || !thiz->opaque)
        return NULL;

    JNIEnv *env = NULL;
    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
        ALOGE("%s: SetupThreadEnv failed", __func__);
        return NULL;
    }

    SDL_AMediaCodec_Opaque *opaque = (SDL_AMediaCodec_Opaque *)thiz->opaque;
    jobject android_format = (*env)->CallObjectMethod(env, opaque->android_media_codec, g_clazz.jmid_getOutputFormat);
    if (SDL_JNI_CatchException(env) || !android_format) {
        return NULL;
    }

    SDL_AMediaFormat *aformat = SDL_AMediaFormatJava_init(env, android_format);
    SDL_JNI_DeleteLocalRefP(env, &android_format);
    return aformat;
}