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; }
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; }