static int SDL_VoutAndroid_releaseBufferProxy_l(SDL_Vout *vout, SDL_AMediaCodecBufferProxy *proxy, bool render) { SDL_Vout_Opaque *opaque = vout->opaque; if (!proxy) return 0; AMCTRACE("%s: [%d] -------- proxy %d: vout: %d idx: %d render: %s fake: %s", __func__, proxy->buffer_id, proxy->acodec_serial, SDL_AMediaCodec_getSerial(opaque->acodec), proxy->buffer_index, render ? "true" : "false", (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) ? "YES" : "NO"); ISDL_Array__push_back(&opaque->overlay_pool, proxy); if (!SDL_AMediaCodec_isSameSerial(opaque->acodec, proxy->acodec_serial)) { ALOGW("%s: [%d] ???????? proxy %d: vout: %d idx: %d render: %s fake: %s", __func__, proxy->buffer_id, proxy->acodec_serial, SDL_AMediaCodec_getSerial(opaque->acodec), proxy->buffer_index, render ? "true" : "false", (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) ? "YES" : "NO"); return 0; } if (proxy->buffer_index < 0) { ALOGE("%s: [%d] invalid AMediaCodec buffer index %d\n", __func__, proxy->buffer_id, proxy->buffer_index); return 0; } else if (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) { proxy->buffer_index = -1; return 0; } sdl_amedia_status_t amc_ret = SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, proxy->buffer_index, render); if (amc_ret != SDL_AMEDIA_OK) { ALOGW("%s: [%d] !!!!!!!! proxy %d: vout: %d idx: %d render: %s, fake: %s", __func__, proxy->buffer_id, proxy->acodec_serial, SDL_AMediaCodec_getSerial(opaque->acodec), proxy->buffer_index, render ? "true" : "false", (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) ? "YES" : "NO"); proxy->buffer_index = -1; return -1; } proxy->buffer_index = -1; return 0; }
static SDL_AMediaCodecBufferProxy *SDL_VoutAndroid_obtainBufferProxy_l(SDL_Vout *vout, int acodec_serial, int buffer_index) { SDL_Vout_Opaque *opaque = vout->opaque; SDL_AMediaCodecBufferProxy *proxy = NULL; if (ISDL_Array__size(&opaque->overlay_pool) > 0) { proxy = ISDL_Array__pop_back(&opaque->overlay_pool); SDL_AMediaCodecBufferProxy_reset(proxy); } else { proxy = (SDL_AMediaCodecBufferProxy *)mallocz(sizeof(SDL_AMediaCodecBufferProxy)); if (!proxy) return NULL; SDL_AMediaCodecBufferProxy_init(proxy); ISDL_Array__push_back(&opaque->overlay_manager, proxy); } proxy->buffer_id = opaque->next_buffer_id++; proxy->acodec_serial = acodec_serial; proxy->buffer_index = buffer_index; AMCTRACE("%s: [%d] ++++++++ proxy %d: vout: %d idx: %d", __func__, proxy->buffer_id, proxy->acodec_serial, SDL_AMediaCodec_getSerial(opaque->acodec), proxy->buffer_index); return proxy; }
static SDL_AMediaCodecBufferProxy *SDL_VoutAndroid_obtainBufferProxy_l(SDL_Vout *vout, int acodec_serial, int buffer_index, SDL_AMediaCodecBufferInfo *buffer_info) { SDL_Vout_Opaque *opaque = vout->opaque; SDL_AMediaCodecBufferProxy *proxy = NULL; if (ISDL_Array__size(&opaque->overlay_pool) > 0) { proxy = ISDL_Array__pop_back(&opaque->overlay_pool); SDL_AMediaCodecBufferProxy_reset(proxy); } else { proxy = (SDL_AMediaCodecBufferProxy *)mallocz(sizeof(SDL_AMediaCodecBufferProxy)); if (!proxy) return NULL; SDL_AMediaCodecBufferProxy_init(proxy); ISDL_Array__push_back(&opaque->overlay_manager, proxy); } proxy->buffer_id = opaque->next_buffer_id++; proxy->acodec_serial = acodec_serial; proxy->buffer_index = buffer_index; proxy->buffer_info = *buffer_info; AMCTRACE("%s: [%d] ++++++++ proxy %d: vout: %d idx: %d fake: %s", __func__, proxy->buffer_id, proxy->acodec_serial, SDL_AMediaCodec_getSerial(opaque->acodec), proxy->buffer_index, (proxy->buffer_info.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME) ? "YES" : "NO"); return proxy; }
static int drain_output_buffer_l(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *dequeue_count, AVFrame *frame, int *got_frame) { IJKFF_Pipenode_Opaque *opaque = node->opaque; FFPlayer *ffp = opaque->ffp; int ret = 0; SDL_AMediaCodecBufferInfo bufferInfo; ssize_t output_buffer_index = 0; if (dequeue_count) *dequeue_count = 0; if (JNI_OK != SDL_JNI_SetupThreadEnv(&env)) { ALOGE("%s:create: SetupThreadEnv failed\n", __func__); goto fail; } output_buffer_index = SDL_AMediaCodecFake_dequeueOutputBuffer(opaque->acodec, &bufferInfo, timeUs); if (output_buffer_index == AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED) { ALOGI("AMEDIACODEC__INFO_OUTPUT_BUFFERS_CHANGED\n"); // continue; } else if (output_buffer_index == AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED) { ALOGI("AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED\n"); SDL_AMediaFormat_deleteP(&opaque->output_aformat); opaque->output_aformat = SDL_AMediaCodec_getOutputFormat(opaque->acodec); if (opaque->output_aformat) { int width = 0; int height = 0; int color_format = 0; int stride = 0; int slice_height = 0; int crop_left = 0; int crop_top = 0; int crop_right = 0; int crop_bottom = 0; SDL_AMediaFormat_getInt32(opaque->output_aformat, "width", &width); SDL_AMediaFormat_getInt32(opaque->output_aformat, "height", &height); SDL_AMediaFormat_getInt32(opaque->output_aformat, "color-format", &color_format); SDL_AMediaFormat_getInt32(opaque->output_aformat, "stride", &stride); SDL_AMediaFormat_getInt32(opaque->output_aformat, "slice-height", &slice_height); SDL_AMediaFormat_getInt32(opaque->output_aformat, "crop-left", &crop_left); SDL_AMediaFormat_getInt32(opaque->output_aformat, "crop-top", &crop_top); SDL_AMediaFormat_getInt32(opaque->output_aformat, "crop-right", &crop_right); SDL_AMediaFormat_getInt32(opaque->output_aformat, "crop-bottom", &crop_bottom); // TI decoder could crash after reconfigure // ffp_notify_msg3(ffp, FFP_MSG_VIDEO_SIZE_CHANGED, width, height); // opaque->frame_width = width; // opaque->frame_height = height; ALOGI( "AMEDIACODEC__INFO_OUTPUT_FORMAT_CHANGED\n" " width-height: (%d x %d)\n" " color-format: (%s: 0x%x)\n" " stride: (%d)\n" " slice-height: (%d)\n" " crop: (%d, %d, %d, %d)\n" , width, height, SDL_AMediaCodec_getColorFormatName(color_format), color_format, stride, slice_height, crop_left, crop_top, crop_right, crop_bottom); } // continue; } else if (output_buffer_index == AMEDIACODEC__INFO_TRY_AGAIN_LATER) { AMCTRACE("AMEDIACODEC__INFO_TRY_AGAIN_LATER\n"); // continue; } else if (output_buffer_index < 0) { SDL_LockMutex(opaque->any_input_mutex); SDL_CondWaitTimeout(opaque->any_input_cond, opaque->any_input_mutex, 1000); SDL_UnlockMutex(opaque->any_input_mutex); goto done; } else if (output_buffer_index >= 0) { ffp->stat.vdps = SDL_SpeedSamplerAdd(&opaque->sampler, FFP_SHOW_VDPS_MEDIACODEC, "vdps[MediaCodec]"); if (dequeue_count) ++*dequeue_count; #ifdef FFP_SHOW_AMC_VDPS { if (opaque->benchmark_start_time == 0) { opaque->benchmark_start_time = SDL_GetTickHR(); } opaque->benchmark_frame_count += 1; if (0 == (opaque->benchmark_frame_count % 240)) { Uint64 diff = SDL_GetTickHR() - opaque->benchmark_start_time; double per_frame_ms = ((double) diff) / opaque->benchmark_frame_count; double fps = ((double) opaque->benchmark_frame_count) * 1000 / diff; ALOGE("%lf fps, %lf ms/frame, %"PRIu64" frames\n", fps, per_frame_ms, opaque->benchmark_frame_count); } } #endif #ifdef FFP_AMC_DISABLE_OUTPUT if (!(bufferInfo.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME)) { SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false); } goto done; #endif if (opaque->n_buf_out) { AMC_Buf_Out *buf_out; if (opaque->off_buf_out < opaque->n_buf_out) { // ALOGD("filling buffer... %d", opaque->off_buf_out); buf_out = &opaque->amc_buf_out[opaque->off_buf_out++]; buf_out->acodec_serial = SDL_AMediaCodec_getSerial(opaque->acodec); buf_out->port = output_buffer_index; buf_out->info = bufferInfo; buf_out->pts = pts_from_buffer_info(node, &bufferInfo); sort_amc_buf_out(opaque->amc_buf_out, opaque->off_buf_out); } else { double pts; pts = pts_from_buffer_info(node, &bufferInfo); if (opaque->last_queued_pts != AV_NOPTS_VALUE && pts < opaque->last_queued_pts) { // FIXME: drop unordered picture to avoid dither // ALOGE("early picture, drop!"); // SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false); // goto done; } /* already sorted */ buf_out = &opaque->amc_buf_out[opaque->off_buf_out - 1]; /* new picture is the most aged, send now */ if (pts < buf_out->pts) { ret = amc_fill_frame(node, frame, got_frame, output_buffer_index, SDL_AMediaCodec_getSerial(opaque->acodec), &bufferInfo); opaque->last_queued_pts = pts; // ALOGD("pts = %f", pts); } else { int i; /* find one to send */ for (i = opaque->off_buf_out - 1; i >= 0; i--) { buf_out = &opaque->amc_buf_out[i]; if (pts > buf_out->pts) { ret = amc_fill_frame(node, frame, got_frame, buf_out->port, buf_out->acodec_serial, &buf_out->info); opaque->last_queued_pts = buf_out->pts; // ALOGD("pts = %f", buf_out->pts); /* replace for sort later */ buf_out->acodec_serial = SDL_AMediaCodec_getSerial(opaque->acodec); buf_out->port = output_buffer_index; buf_out->info = bufferInfo; buf_out->pts = pts_from_buffer_info(node, &bufferInfo); sort_amc_buf_out(opaque->amc_buf_out, opaque->n_buf_out); break; } } /* need to discard current buffer */ if (i < 0) { // ALOGE("buffer too small, drop picture!"); if (!(bufferInfo.flags & AMEDIACODEC__BUFFER_FLAG_FAKE_FRAME)) { SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false); goto done; } } } } } else { ret = amc_fill_frame(node, frame, got_frame, output_buffer_index, SDL_AMediaCodec_getSerial(opaque->acodec), &bufferInfo); } } done: if (opaque->decoder->queue->abort_request) ret = -1; else ret = 0; fail: return ret; }