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;
}
IJKFF_Pipenode *ffpipenode_create_video_decoder_from_android_mediacodec(FFPlayer *ffp, IJKFF_Pipeline *pipeline, SDL_Vout *vout)
{
    ALOGD("ffpipenode_create_video_decoder_from_android_mediacodec()\n");
    if (SDL_Android_GetApiLevel() < IJK_API_16_JELLY_BEAN)
        return NULL;

    if (!ffp || !ffp->is)
        return NULL;

    IJKFF_Pipenode *node = ffpipenode_alloc(sizeof(IJKFF_Pipenode_Opaque));
    if (!node)
        return node;

    VideoState            *is     = ffp->is;
    IJKFF_Pipenode_Opaque *opaque = node->opaque;
    JNIEnv                *env    = NULL;

    node->func_destroy  = func_destroy;
    node->func_run_sync = func_run_sync;
    opaque->pipeline    = pipeline;
    opaque->ffp         = ffp;
    opaque->decoder     = &is->viddec;
    opaque->weak_vout   = vout;

    opaque->avctx = opaque->decoder->avctx;
    switch (opaque->avctx->codec_id) {
    case AV_CODEC_ID_H264:
        strcpy(opaque->mcc.mime_type, SDL_AMIME_VIDEO_AVC);
        opaque->mcc.profile = opaque->avctx->profile;
        opaque->mcc.level   = opaque->avctx->level;
        break;
    default:
        ALOGE("%s:create: not H264\n", __func__);
        goto fail;
    }

    if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) {
        ALOGE("%s:create: SetupThreadEnv failed\n", __func__);
        goto fail;
    }

    opaque->acodec_mutex                      = SDL_CreateMutex();
    opaque->acodec_cond                       = SDL_CreateCond();
    opaque->acodec_first_dequeue_output_mutex = SDL_CreateMutex();
    opaque->acodec_first_dequeue_output_cond  = SDL_CreateCond();

    ffp_packet_queue_init(&opaque->fake_pictq);
    ffp_packet_queue_start(&opaque->fake_pictq);

    if (!opaque->acodec_cond || !opaque->acodec_cond || !opaque->acodec_first_dequeue_output_mutex || !opaque->acodec_first_dequeue_output_cond) {
        ALOGE("%s:open_video_decoder: SDL_CreateCond() failed\n", __func__);
        goto fail;
    }

    opaque->acodec = create_codec_l(env, node);
    if (!opaque->acodec) {
        ALOGE("%s:open_video_decoder: SDL_AMediaCodecJava_createDecoderByType(%s) failed\n", __func__, opaque->mcc.mime_type);
        goto fail;
    }
    assert(opaque->weak_vout);
    SDL_VoutAndroid_setAMediaCodec(opaque->weak_vout, opaque->acodec);

    ALOGI("AMediaFormat: %s, %dx%d\n", opaque->mcc.mime_type, opaque->avctx->width, opaque->avctx->height);
    opaque->input_aformat = SDL_AMediaFormatJava_createVideoFormat(env, opaque->mcc.mime_type, opaque->avctx->width, opaque->avctx->height);
    if (opaque->avctx->extradata && opaque->avctx->extradata_size > 0) {
        if (opaque->avctx->codec_id == AV_CODEC_ID_H264 && opaque->avctx->extradata[0] == 1) {
#if AMC_USE_AVBITSTREAM_FILTER
            opaque->bsfc = av_bitstream_filter_init("h264_mp4toannexb");
            if (!opaque->bsfc) {
                ALOGE("Cannot open the h264_mp4toannexb BSF!\n");
                goto fail;
            }

            opaque->orig_extradata_size = opaque->avctx->extradata_size;
            opaque->orig_extradata = (uint8_t*) av_mallocz(opaque->avctx->extradata_size +
                                                      FF_INPUT_BUFFER_PADDING_SIZE);
            if (!opaque->orig_extradata) {
                goto fail;
            }
            memcpy(opaque->orig_extradata, opaque->avctx->extradata, opaque->avctx->extradata_size);
            for(int i = 0; i < opaque->avctx->extradata_size; i+=4) {
                ALOGE("csd-0[%d]: %02x%02x%02x%02x\n", opaque->avctx->extradata_size, (int)opaque->avctx->extradata[i+0], (int)opaque->avctx->extradata[i+1], (int)opaque->avctx->extradata[i+2], (int)opaque->avctx->extradata[i+3]);
            }
            SDL_AMediaFormat_setBuffer(opaque->input_aformat, "csd-0", opaque->avctx->extradata, opaque->avctx->extradata_size);
#else
            size_t   sps_pps_size   = 0;
            size_t   convert_size   = opaque->avctx->extradata_size + 20;
            uint8_t *convert_buffer = (uint8_t *)calloc(1, convert_size);
            if (!convert_buffer) {
                ALOGE("%s:sps_pps_buffer: alloc failed\n", __func__);
                goto fail;
            }
            if (0 != convert_sps_pps(opaque->avctx->extradata, opaque->avctx->extradata_size,
                                     convert_buffer, convert_size,
                                     &sps_pps_size, &opaque->nal_size)) {
                ALOGE("%s:convert_sps_pps: failed\n", __func__);
                goto fail;
            }
            SDL_AMediaFormat_setBuffer(opaque->input_aformat, "csd-0", convert_buffer, sps_pps_size);
            for(int i = 0; i < sps_pps_size; i+=4) {
                ALOGE("csd-0[%d]: %02x%02x%02x%02x\n", sps_pps_size, (int)convert_buffer[i+0], (int)convert_buffer[i+1], (int)convert_buffer[i+2], (int)convert_buffer[i+3]);
            }
            free(convert_buffer);
#endif
        } else {
            // Codec specific data
            // SDL_AMediaFormat_setBuffer(opaque->aformat, "csd-0", opaque->avctx->extradata, opaque->avctx->extradata_size);
            ALOGE("csd-0: naked\n");
        }
    } else {
        ALOGE("no buffer(%d)\n", opaque->avctx->extradata_size);
    }

    ffp_set_video_codec_info(ffp, MEDIACODEC_MODULE_NAME, opaque->mcc.codec_name);
    return node;
fail:
    ffpipenode_free_p(&node);
    return NULL;
}