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
204204 av_buffer_unref(&ctx->device_ctx_ref);
205205 av_fifo_freep2(&ctx->timestamp_list);
206206
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+ }
207217 av_freep(&ctx->pts_property_name);
208218 av_freep(&ctx->av_frame_property_name);
209219
@@ -306,6 +316,10 @@ int ff_amf_encode_init(AVCodecContext *avctx) · 96 unmodified lines
306316 if (!ctx->timestamp_list) {
307317 return AVERROR(ENOMEM);
308318 }
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+
309323 ctx->dts_delay = 0;
310324
311325 ctx->hwsurfaces_in_queue = 0;
@@ -639,6 +653,22 @@ static int amf_submit_frame_locked(AVCodecContext *avctx, AVFrame *frame, AMFSur · 327 unmodified lines
639653 amf_unlock_context(avctx);
640654 return ret;
641655 }
656+static 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+}
642672
643673 int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
644674 {
@@ -649,7 +679,7 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) · 4 unmodified lines
649679 AMF_RESULT res;
650680 int ret;
651681 AMF_RESULT res_query;
652− AMFData *data = NULL;
682+ AMFBuffer* buffer = NULL;
653683 AVFrame *frame = av_frame_alloc();
654684 int block_and_wait;
655685 int64_t pts = 0;
@@ -659,6 +689,14 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) · 3 unmodified lines
659689 av_frame_free(&frame);
660690 return AVERROR(EINVAL);
661691 }
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+
662700 ret = ff_encode_get_frame(avctx, frame);
663701 if(ret < 0){
664702 if(ret != AVERROR_EOF){
@@ -698,20 +736,10 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) · 33 unmodified lines
698736 do {
699737 block_and_wait = 0;
700738 // poll data
701−
702− res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data);
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
739+ res_query = amf_query_output(avctx, &buffer);
740+ if (buffer) {
708741 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++;
713742 buffer->pVtbl->Release(buffer);
714− data->pVtbl->Release(data);
715743
716744 AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret);
717745
@@ -737,12 +765,29 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) · 19 unmodified lines
737765
738766 if (res_query == AMF_EOF) {
739767 ret = AVERROR_EOF;
740− } else if (data == NULL) {
768+ } else if (buffer == NULL) {
741769 ret = AVERROR(EAGAIN);
742770 } else {
743771 if(surface) {
744772 // 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+
746791 surface->pVtbl->Release(surface);
747792 if (res == AMF_INPUT_FULL) {
748793 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
6161 int64_t dts_delay;
6262 int64_t submitted_frame;
6363 int64_t encoded_frame;
64+ AVFifo *output_list;
6465
6566 // common encoder options
6667

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