Commit 1d24f411 for libheif

commit 1d24f41182760d6fadb4beecf451aeb58f7c87c0
Author: John Preston <johnprestonmail@gmail.com>
Date:   Fri Sep 25 18:36:32 2026 +0400

    FFmpeg decoder: send complete access units without the parser

    libheif pushes one complete access unit per push_data() call, so running
    av_parser_parse2() over it only parsed every NAL unit a second time before
    the decoder did. This also removes the partial-consumption path, which
    resized input_data by a byte count.

diff --git a/libheif/plugins/decoder_ffmpeg.cc b/libheif/plugins/decoder_ffmpeg.cc
index c253e84c..29c111c7 100644
--- a/libheif/plugins/decoder_ffmpeg.cc
+++ b/libheif/plugins/decoder_ffmpeg.cc
@@ -63,14 +63,12 @@ struct ffmpeg_decoder
   // --- decoder

   const AVCodec* av_codec = NULL;
-  AVCodecParserContext* av_codec_parser_context = NULL;
   AVCodecContext* av_codec_context = NULL;

   std::string error_message;

   ~ffmpeg_decoder()
   {
-    if (av_codec_parser_context) av_parser_close(av_codec_parser_context);
     if (av_codec_context) avcodec_free_context(&av_codec_context);
   }
 };
@@ -193,11 +191,6 @@ static heif_error ffmpeg_new_decoder2(void** dec, const heif_decoder_plugin_opti
     return { heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "avcodec_find_decoder() returned error" };
   }

-  decoder->av_codec_parser_context = av_parser_init(decoder->av_codec->id);
-  if (!decoder->av_codec_parser_context) {
-    return { heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "av_parser_init returned error" };
-  }
-
   decoder->av_codec_context = avcodec_alloc_context3(decoder->av_codec);
   if (!decoder->av_codec_context) {
     return { heif_error_Memory_allocation_error, heif_suberror_Unspecified, "avcodec_alloc_context3 returned error" };
@@ -768,9 +761,6 @@ static heif_error ffmpeg_decode_next_image2(void* decoder_raw,
   heif_error err = kSuccess;

   if (!decoder->input_data.empty()) {
-    uint8_t* parse_av_data = NULL;
-    int parse_av_data_size = 0;
-
     ffmpeg_decoder::Packet& first_pkt = decoder->input_data.front();

     if (first_pkt.data.empty()) {
@@ -790,49 +780,17 @@ static heif_error ffmpeg_decode_next_image2(void* decoder_raw,
         return { heif_error_Memory_allocation_error, heif_suberror_Unspecified, "av_packet_alloc returned error" };
       }

-      parse_av_data = first_pkt.data.data();
-      parse_av_data_size = (int) first_pkt.data.size();
-      size_t n_bytes_consumed = 0;
-
-      while (parse_av_data_size > 0) {
-        decoder->av_codec_parser_context->flags = PARSER_FLAG_COMPLETE_FRAMES;
-        ret = av_parser_parse2(decoder->av_codec_parser_context, decoder->av_codec_context, &av_pkt->data, &av_pkt->size,
-                               parse_av_data, parse_av_data_size,
-                               AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
-        if (ret < 0) {
-          return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "av_parser_parse2 returned error"};
-        }
-
-        // std::cout << "decode packet of size: " << ret << "\n";
+      // Every pushed chunk is a complete access unit, so it goes to the decoder
+      // as one packet. Running av_parser_parse2() over it first only parsed all
+      // NAL units a second time before the decoder parsed them again.
+      av_pkt->data = first_pkt.data.data();
+      av_pkt->size = (int) first_pkt.data.size();
+      av_pkt->pts = first_pkt.user_data;

-        parse_av_data += ret;
-        parse_av_data_size -= ret;
-        n_bytes_consumed += ret;
-
-        if (av_pkt->size) {
-          av_pkt->pts = first_pkt.user_data;
-
-          ret = avcodec_send_packet(decoder->av_codec_context, av_pkt);
-          if (ret < 0) {
-            char buf[100];
-            av_make_error_string(buf, 100, ret);
-            return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Error in avcodec_send_packet"};
-          }
-        }
-        else {
-          break;
-        }
-      }
-
-      if (n_bytes_consumed == first_pkt.data.size()) {
-        decoder->input_data.pop_front();
-      }
-      else {
-        if (n_bytes_consumed > 0) {
-          memmove(first_pkt.data.data(), first_pkt.data.data() + n_bytes_consumed,
-                  first_pkt.data.size() - n_bytes_consumed);
-          decoder->input_data.resize(decoder->input_data.size() - n_bytes_consumed);
-        }
+      ret = avcodec_send_packet(decoder->av_codec_context, av_pkt);
+      decoder->input_data.pop_front();
+      if (ret < 0) {
+        return {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "Error in avcodec_send_packet"};
       }
     }
   }