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;
}
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;
}
static void func_destroy(IJKFF_Pipenode *node)
{
    if (!node || !node->opaque)
        return;

    IJKFF_Pipenode_Opaque *opaque = node->opaque;

    SDL_DestroyCondP(&opaque->acodec_cond);
    SDL_DestroyMutexP(&opaque->acodec_mutex);
    SDL_DestroyCondP(&opaque->acodec_first_dequeue_output_cond);
    SDL_DestroyMutexP(&opaque->acodec_first_dequeue_output_mutex);

    SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec);
    SDL_AMediaFormat_deleteP(&opaque->input_aformat);
    SDL_AMediaFormat_deleteP(&opaque->output_aformat);

#if AMC_USE_AVBITSTREAM_FILTER
    av_freep(&opaque->orig_extradata);
#endif

    ffp_packet_queue_destroy(&opaque->fake_pictq);

    if (opaque->bsfc) {
        av_bitstream_filter_close(opaque->bsfc);
        opaque->bsfc = NULL;
    }

    JNIEnv *env = NULL;
    if (JNI_OK == SDL_JNI_SetupThreadEnv(&env)) {
        SDL_JNI_DeleteGlobalRefP(env, &opaque->jsurface);
    }
}
예제 #4
0
int ffpipeline_set_surface(JNIEnv *env, IJKFF_Pipeline* pipeline, jobject surface)
{
    ALOGD("%s()\n", __func__);
    if (!check_ffpipeline(pipeline, __func__))
        return -1;

    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;
    if (!opaque->surface_mutex)
        return -1;

    SDL_LockMutex(opaque->surface_mutex);
    {
        jobject prev_surface = opaque->jsurface;

        if ((surface == prev_surface) ||
            (surface && prev_surface && (*env)->IsSameObject(env, surface, prev_surface))) {
            // same object, no need to reconfigure
        } else {
            SDL_VoutAndroid_setAMediaCodec(opaque->weak_vout, NULL);
            if (surface) {
                opaque->jsurface = (*env)->NewGlobalRef(env, surface);
            } else {
                opaque->jsurface = NULL;
            }
            opaque->is_surface_need_reconfigure = true;

            if (prev_surface != NULL) {
                SDL_JNI_DeleteGlobalRefP(env, &prev_surface);
            }
        }
    }
    SDL_UnlockMutex(opaque->surface_mutex);

    return 0;
}
static int reconfigure_codec_l(JNIEnv *env, IJKFF_Pipenode *node)
{
    IJKFF_Pipenode_Opaque *opaque   = node->opaque;
    IJKFF_Pipeline        *pipeline = opaque->pipeline;
    int                    ret      = 0;
    sdl_amedia_status_t    amc_ret  = 0;
    jobject                prev_jsurface = NULL;

    ffpipeline_set_surface_need_reconfigure_l(pipeline, false);

    prev_jsurface = opaque->jsurface;
    opaque->jsurface = ffpipeline_get_surface_as_global_ref_l(env, pipeline);
    SDL_JNI_DeleteGlobalRefP(env, &prev_jsurface);

    if (!opaque->acodec) {
        opaque->acodec = create_codec_l(env, node);
        if (!opaque->acodec) {
            ALOGE("%s:open_video_decoder: create_codec failed\n", __func__);
            ret = -1;
            goto fail;
        }
    }

    if (SDL_AMediaCodec_isConfigured(opaque->acodec)) {
        if (opaque->acodec) {
            if (SDL_AMediaCodec_isStarted(opaque->acodec)) {
                SDL_VoutAndroid_invalidateAllBuffers(opaque->weak_vout);
                SDL_AMediaCodec_stop(opaque->acodec);
            }
            if (opaque->quirk_reconfigure_with_new_codec) {
                ALOGI("quirk: reconfigure with new codec");
                SDL_AMediaCodec_decreaseReferenceP(&opaque->acodec);

                opaque->acodec = create_codec_l(env, node);
                if (!opaque->acodec) {
                    ALOGE("%s:open_video_decoder: create_codec failed\n", __func__);
                    ret = -1;
                    goto fail;
                }
            }
        }

        assert(opaque->weak_vout);
    }

    amc_ret = SDL_AMediaCodec_configure_surface(env, opaque->acodec, opaque->input_aformat, opaque->jsurface, NULL, 0);
    if (amc_ret != SDL_AMEDIA_OK) {
        ALOGE("%s:configure_surface: failed\n", __func__);
        ret = -1;
        goto fail;
    }

    SDL_AMediaCodec_start(opaque->acodec);
    opaque->acodec_first_dequeue_output_request = true;
    ALOGI("%s:new acodec: %p\n", __func__, opaque->acodec);
    SDL_VoutAndroid_setAMediaCodec(opaque->weak_vout, opaque->acodec);
fail:
    return ret;
}
static sdl_amedia_status_t SDL_AMediaFormatJava_delete(SDL_AMediaFormat* aformat)
{
    if (!aformat)
        return SDL_AMEDIA_OK;

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

    SDL_AMediaFormat_Opaque *opaque = (SDL_AMediaFormat_Opaque *)aformat->opaque;
    if (opaque) {
        SDL_JNI_DeleteGlobalRefP(env, &opaque->android_byte_buffer);
        SDL_JNI_DeleteGlobalRefP(env, &opaque->android_media_format);
    }

    SDL_AMediaFormat_FreeInternal(aformat);
    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;
}
예제 #8
0
static void func_destroy(IJKFF_Pipeline *pipeline)
{
    IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;
    JNIEnv *env = NULL;

    SDL_DestroyMutexP(&opaque->surface_mutex);

    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
        ALOGE("amediacodec-pipeline:destroy: SetupThreadEnv failed\n");
        goto fail;
    }

    SDL_JNI_DeleteGlobalRefP(env, &opaque->jsurface);
fail:
    return;
}
SDL_AMediaFormat *SDL_AMediaFormatJava_init(JNIEnv *env, jobject android_format)
{
    SDLTRACE("%s", __func__);
    jobject global_android_media_format = (*env)->NewGlobalRef(env, android_format);
    if (J4A_ExceptionCheck__catchAll(env) || !global_android_media_format) {
        return NULL;
    }

    SDL_AMediaFormat *aformat = SDL_AMediaFormat_CreateInternal(sizeof(SDL_AMediaFormat_Opaque));
    if (!aformat) {
        SDL_JNI_DeleteGlobalRefP(env, &global_android_media_format);
        return NULL;
    }

    setup_aformat(aformat, global_android_media_format);
    return aformat;
}
SDL_AMediaFormat *SDL_AMediaFormatJava_createVideoFormat(JNIEnv *env, const char *mime, int width, int height)
{
    SDLTRACE("%s", __func__);

    jobject android_media_format = J4AC_MediaFormat__createVideoFormat__withCString__asGlobalRef__catchAll(env, mime, width, height);
    if (J4A_ExceptionCheck__catchAll(env) || !android_media_format) {
        return NULL;
    }

    SDL_AMediaFormat *aformat = SDL_AMediaFormat_CreateInternal(sizeof(SDL_AMediaFormat_Opaque));
    if (!aformat) {
        SDL_JNI_DeleteGlobalRefP(env, &android_media_format);
        return NULL;
    }

    setup_aformat(aformat, android_media_format);
    SDL_AMediaFormat_setInt32(aformat, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, 0);
    return aformat;
}
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 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;
}