static int drain_output_buffer_l(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *dequeue_count) { IJKFF_Pipenode_Opaque *opaque = node->opaque; 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__); return -1; } output_buffer_index = SDL_AMediaCodec_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)" " slice-height: (%d)" " crop: (%d, %d, %d, %d)" , 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) { // enqueue packet as a fake picture PacketQueue *q = &opaque->fake_pictq; SDL_LockMutex(q->mutex); if (!q->abort_request && q->nb_packets <= 0) { SDL_CondWaitTimeout(q->cond, q->mutex, 1000); } SDL_UnlockMutex(q->mutex); if (q->abort_request) { ret = -1; goto fail; } else { AVPacket pkt; if (ffp_packet_queue_get(&opaque->fake_pictq, &pkt, 1, &opaque->fake_pictq_serial) < 0) { ret = -1; goto fail; } else { if (!ffp_is_flush_packet(&pkt)) { if (dequeue_count) ++*dequeue_count; ret = amc_queue_picture_fake(node, &pkt); av_free_packet(&pkt); } ret = 0; goto fail; } } } else if (output_buffer_index >= 0) { if (dequeue_count) ++*dequeue_count; ret = amc_queue_picture_buffer(node, output_buffer_index, &bufferInfo); } ret = 0; fail: return ret; }
static int drain_output_buffer_l(JNIEnv *env, IJKFF_Pipenode *node, int64_t timeUs, int *dequeue_count) { IJKFF_Pipenode_Opaque *opaque = node->opaque; 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__); return -1; } output_buffer_index = SDL_AMediaCodec_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) { // enqueue packet as a fake picture PacketQueue *fake_q = &opaque->fake_pictq; SDL_LockMutex(fake_q->mutex); if (!fake_q->abort_request && fake_q->nb_packets <= 0) { SDL_CondWaitTimeout(fake_q->cond, fake_q->mutex, 1000); } SDL_UnlockMutex(fake_q->mutex); if (fake_q->abort_request) { ret = -1; goto fail; } else { AVPacket pkt; if (ffp_packet_queue_get(&opaque->fake_pictq, &pkt, 1, &opaque->fake_pictq_serial) < 0) { ret = -1; goto fail; } else { if (!ffp_is_flush_packet(&pkt)) { if (dequeue_count) ++*dequeue_count; ret = amc_queue_picture_fake(node, &pkt); av_free_packet(&pkt); } ret = 0; goto fail; } } } else if (output_buffer_index >= 0) { if (dequeue_count) ++*dequeue_count; 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->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) { // 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_queue_picture_buffer(node, output_buffer_index, &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_queue_picture_buffer(node, buf_out->port, &buf_out->info); opaque->last_queued_pts = buf_out->pts; // ALOGD("pts = %f", buf_out->pts); /* replace for sort later */ 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!"); SDL_AMediaCodec_releaseOutputBuffer(opaque->acodec, output_buffer_index, false); goto done; } } } } else { ret = amc_queue_picture_buffer(node, output_buffer_index, &bufferInfo); } } done: ret = 0; fail: return ret; }
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; }