History

amfenc: Fix for full PA queue

Fixes AMF_INPUT_FULL errors with pre-analysis (PA) enabled. Added wait and poll encoder output to free up internal buffers before submitting new frames. Improves stability and performance by accounting for encoder and analysis stage queue limits (incl. lookahead buffering).

Araz Iusubov committed 1 year ago

Commit 5f24c501 parent cd332192 files · +61 −15Browse files

Unified · Split

2 files
  1. libavcodec/amfenc.c +60 −15
  2. libavcodec/amfenc.h +1 −0
libavcodec/amfenc.c+60−15
@@ -204,6 +204,16 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx) · 203 unmodified lines
204 av_buffer_unref(&ctx->device_ctx_ref);204 av_buffer_unref(&ctx->device_ctx_ref);
205 av_fifo_freep2(&ctx->timestamp_list);205 av_fifo_freep2(&ctx->timestamp_list);
206 206
207 if (ctx->output_list) {
208 // release remaining AMF output buffers
209 while(av_fifo_can_read(ctx->output_list)) {
210 AMFBuffer* buffer = NULL;
211 av_fifo_read(ctx->output_list, &buffer, 1);
212 if(buffer != NULL)
213 buffer->pVtbl->Release(buffer);
214 }
215 av_fifo_freep2(&ctx->output_list);
216 }
207 av_freep(&ctx->pts_property_name);217 av_freep(&ctx->pts_property_name);
208 av_freep(&ctx->av_frame_property_name);218 av_freep(&ctx->av_frame_property_name);
209 219
@@ -306,6 +316,10 @@ int ff_amf_encode_init(AVCodecContext *avctx) · 96 unmodified lines
306 if (!ctx->timestamp_list) {316 if (!ctx->timestamp_list) {
307 return AVERROR(ENOMEM);317 return AVERROR(ENOMEM);
308 }318 }
319 ctx->output_list = av_fifo_alloc2(2, sizeof(AMFBuffer*), AV_FIFO_FLAG_AUTO_GROW);
320 if (!ctx->output_list)
321 return AVERROR(ENOMEM);
322
309 ctx->dts_delay = 0;323 ctx->dts_delay = 0;
310 324
311 ctx->hwsurfaces_in_queue = 0;325 ctx->hwsurfaces_in_queue = 0;
@@ -639,6 +653,22 @@ static int amf_submit_frame_locked(AVCodecContext *avctx, AVFrame *frame, AMFSur · 327 unmodified lines
639 amf_unlock_context(avctx);653 amf_unlock_context(avctx);
640 return ret;654 return ret;
641}655}
656static AMF_RESULT amf_query_output(AVCodecContext *avctx, AMFBuffer **buffer)
657{
658 AMFEncoderContext *ctx = avctx->priv_data;
659 AMFData *data = NULL;
660 AMF_RESULT ret = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data);
661 *buffer = NULL;
662 if (data) {
663 AMFGuid guid = IID_AMFBuffer();
664 data->pVtbl->QueryInterface(data, &guid, (void**)buffer); // query for buffer interface
665 data->pVtbl->Release(data);
666 if (amf_release_attached_frame_ref(ctx, *buffer) == AMF_OK)
667 ctx->hwsurfaces_in_queue--;
668 ctx->encoded_frame++;
669 }
670 return ret;
671}
642 672
643int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)673int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
644{674{
@@ -649,7 +679,7 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) · 4 unmodified lines
649 AMF_RESULT res;679 AMF_RESULT res;
650 int ret;680 int ret;
651 AMF_RESULT res_query;681 AMF_RESULT res_query;
652 AMFData *data = NULL;682 AMFBuffer* buffer = NULL;
653 AVFrame *frame = av_frame_alloc();683 AVFrame *frame = av_frame_alloc();
654 int block_and_wait;684 int block_and_wait;
655 int64_t pts = 0;685 int64_t pts = 0;
@@ -659,6 +689,14 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) · 3 unmodified lines
659 av_frame_free(&frame);689 av_frame_free(&frame);
660 return AVERROR(EINVAL);690 return AVERROR(EINVAL);
661 }691 }
692 // check if some outputs are available
693 av_fifo_read(ctx->output_list, &buffer, 1);
694 if (buffer != NULL) { // return already retrieved output
695 ret = amf_copy_buffer(avctx, avpkt, buffer);
696 buffer->pVtbl->Release(buffer);
697 return ret;
698 }
699
662 ret = ff_encode_get_frame(avctx, frame);700 ret = ff_encode_get_frame(avctx, frame);
663 if(ret < 0){701 if(ret < 0){
664 if(ret != AVERROR_EOF){702 if(ret != AVERROR_EOF){
@@ -698,20 +736,10 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) · 33 unmodified lines
698 do {736 do {
699 block_and_wait = 0;737 block_and_wait = 0;
700 // poll data738 // poll data
701 739 res_query = amf_query_output(avctx, &buffer);
702 res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data);740 if (buffer) {
703 if (data) {
704 // copy data to packet
705 AMFBuffer *buffer;
706 AMFGuid guid = IID_AMFBuffer();
707 data->pVtbl->QueryInterface(data, &guid, (void**)&buffer); // query for buffer interface
708 ret = amf_copy_buffer(avctx, avpkt, buffer);741 ret = amf_copy_buffer(avctx, avpkt, buffer);
709 if (amf_release_attached_frame_ref(ctx, buffer) == AMF_OK) {
710 ctx->hwsurfaces_in_queue--;
711 }
712 ctx->encoded_frame++;
713 buffer->pVtbl->Release(buffer);742 buffer->pVtbl->Release(buffer);
714 data->pVtbl->Release(data);
715 743
716 AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret);744 AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret);
717 745
@@ -737,12 +765,29 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) · 19 unmodified lines
737 765
738 if (res_query == AMF_EOF) {766 if (res_query == AMF_EOF) {
739 ret = AVERROR_EOF;767 ret = AVERROR_EOF;
740 } else if (data == NULL) {768 } else if (buffer == NULL) {
741 ret = AVERROR(EAGAIN);769 ret = AVERROR(EAGAIN);
742 } else {770 } else {
743 if(surface) {771 if(surface) {
744 // resubmit surface772 // resubmit surface
745 res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface);773 do {
774 res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface);
775 if (res != AMF_INPUT_FULL)
776 break;
777
778 if (!ctx->query_timeout_supported)
779 av_usleep(1000);
780
781 // Need to free up space in the encoder queue.
782 // The number of retrieved outputs is limited currently to 21
783 amf_query_output(avctx, &buffer);
784 if (buffer != NULL) {
785 ret = av_fifo_write(ctx->output_list, &buffer, 1);
786 if (ret < 0)
787 return ret;
788 }
789 } while(res == AMF_INPUT_FULL);
790
746 surface->pVtbl->Release(surface);791 surface->pVtbl->Release(surface);
747 if (res == AMF_INPUT_FULL) {792 if (res == AMF_INPUT_FULL) {
748 av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed SubmitInput returned AMF_INPUT_FULL- should not happen\n");793 av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed SubmitInput returned AMF_INPUT_FULL- should not happen\n");
libavcodec/amfenc.h+1−0
@@ -61,6 +61,7 @@ typedef struct AMFEncoderContext { · 60 unmodified lines
61 int64_t dts_delay;61 int64_t dts_delay;
62 int64_t submitted_frame;62 int64_t submitted_frame;
63 int64_t encoded_frame;63 int64_t encoded_frame;
64 AVFifo *output_list;
64 65
65 // common encoder options66 // common encoder options
66 67

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t