From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Jan Alexander Steffens (heftig)" <jan.steffens@gmail.com>
Date: Thu, 30 May 2024 00:54:43 +0200
Subject: [PATCH] libav: Fix compatibility with ffmpeg 7

Squash of the following commits:

  - avdemux: Remove typefinder implementation
  - libav: Fix signature of avprotocol write function for ffmpeg 7
  - libav: Update AVCodecContext lifetime to work properly with ffmpeg 7
  - avdemux: Fix leak of demuxer input context in error cases
  - avmux: Reset input context to NULL after closing in the muxer
  - avvidenc: Only use 2 ticks per frame if encoding interlaced video
  - avvidenc: Set the DTS to 0 if it is negative, not the PTS
  - avviddec: Only use 2 ticks per frame if decoding interlaced video
  - avvidenc: Make sure to pass always increasing PTS to the encoder
  - typefind: Add typefinders for formats that were previously available via ffmpeg

The latest commit was 39d2beac641315b8f53816d5f1fdcdfb5d14411c from
2024-05-01 18:05:35 +0300.

Source: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6505
---
 subprojects/gst-libav/ext/libav/gstav.c       |  12 --
 subprojects/gst-libav/ext/libav/gstav.h       |   1 -
 subprojects/gst-libav/ext/libav/gstavauddec.c |  92 +++-----
 subprojects/gst-libav/ext/libav/gstavauddec.h |   1 -
 subprojects/gst-libav/ext/libav/gstavaudenc.c |  65 ++----
 subprojects/gst-libav/ext/libav/gstavaudenc.h |   1 -
 subprojects/gst-libav/ext/libav/gstavcfg.c    |   6 +-
 .../gst-libav/ext/libav/gstavcodecmap.c       |  24 +++
 .../gst-libav/ext/libav/gstavdeinterlace.c    |   5 +-
 subprojects/gst-libav/ext/libav/gstavdemux.c  | 124 ++---------
 subprojects/gst-libav/ext/libav/gstavmux.c    |   1 +
 .../gst-libav/ext/libav/gstavprotocol.c       |   4 +
 subprojects/gst-libav/ext/libav/gstavviddec.c | 111 +++++-----
 subprojects/gst-libav/ext/libav/gstavviddec.h |   1 -
 subprojects/gst-libav/ext/libav/gstavvidenc.c | 127 ++++++-----
 subprojects/gst-libav/ext/libav/gstavvidenc.h |   2 +-
 .../gst/typefind/gsttypefindfunctions.c       | 203 ++++++++++++++++++
 .../gst/typefind/gsttypefindfunctionsplugin.c |  10 +
 .../gst/typefind/gsttypefindfunctionsplugin.h |  10 +
 .../gst/typefind/gsttypefindfunctionsriff.c   |   4 +
 .../typefind/gsttypefindfunctionsstartwith.c  |   2 +
 21 files changed, 457 insertions(+), 349 deletions(-)

diff --git a/subprojects/gst-libav/ext/libav/gstav.c b/subprojects/gst-libav/ext/libav/gstav.c
index 00fcc6388137..0c9353f0c157 100644
--- a/subprojects/gst-libav/ext/libav/gstav.c
+++ b/subprojects/gst-libav/ext/libav/gstav.c
@@ -72,18 +72,6 @@ gst_ffmpeg_avcodec_open (AVCodecContext * avctx, const AVCodec * codec)
   return ret;
 }
 
-int
-gst_ffmpeg_avcodec_close (AVCodecContext * avctx)
-{
-  int ret;
-
-  g_mutex_lock (&gst_avcodec_mutex);
-  ret = avcodec_close (avctx);
-  g_mutex_unlock (&gst_avcodec_mutex);
-
-  return ret;
-}
-
 int
 gst_ffmpeg_av_find_stream_info (AVFormatContext * ic)
 {
diff --git a/subprojects/gst-libav/ext/libav/gstav.h b/subprojects/gst-libav/ext/libav/gstav.h
index a7fbb019fd55..9cdb14503c3a 100644
--- a/subprojects/gst-libav/ext/libav/gstav.h
+++ b/subprojects/gst-libav/ext/libav/gstav.h
@@ -46,7 +46,6 @@ extern gboolean gst_ffmpegdeinterlace_register (GstPlugin * plugin);
 extern gboolean gst_ffmpegvidcmp_register (GstPlugin * plugin);
 
 int gst_ffmpeg_avcodec_open (AVCodecContext *avctx, const AVCodec *codec);
-int gst_ffmpeg_avcodec_close (AVCodecContext *avctx);
 int gst_ffmpeg_av_find_stream_info(AVFormatContext *ic);
 
 G_END_DECLS
diff --git a/subprojects/gst-libav/ext/libav/gstavauddec.c b/subprojects/gst-libav/ext/libav/gstavauddec.c
index 48c4be6b6a14..2279e690ee5e 100644
--- a/subprojects/gst-libav/ext/libav/gstavauddec.c
+++ b/subprojects/gst-libav/ext/libav/gstavauddec.c
@@ -145,136 +145,89 @@ gst_ffmpegauddec_class_init (GstFFMpegAudDecClass * klass)
 static void
 gst_ffmpegauddec_init (GstFFMpegAudDec * ffmpegdec)
 {
-  GstFFMpegAudDecClass *klass =
-      (GstFFMpegAudDecClass *) G_OBJECT_GET_CLASS (ffmpegdec);
-
-  /* some ffmpeg data */
-  ffmpegdec->context = avcodec_alloc_context3 (klass->in_plugin);
-  ffmpegdec->context->opaque = ffmpegdec;
-  ffmpegdec->opened = FALSE;
-
-  ffmpegdec->frame = av_frame_alloc ();
-
   GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (ffmpegdec));
   gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST
       (ffmpegdec), TRUE);
 
   gst_audio_decoder_set_drainable (GST_AUDIO_DECODER (ffmpegdec), TRUE);
   gst_audio_decoder_set_needs_format (GST_AUDIO_DECODER (ffmpegdec), TRUE);
 }
 
 static void
 gst_ffmpegauddec_finalize (GObject * object)
 {
   GstFFMpegAudDec *ffmpegdec = (GstFFMpegAudDec *) object;
 
   av_frame_free (&ffmpegdec->frame);
   avcodec_free_context (&ffmpegdec->context);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 /* With LOCK */
-static gboolean
-gst_ffmpegauddec_close (GstFFMpegAudDec * ffmpegdec, gboolean reset)
+static void
+gst_ffmpegauddec_close (GstFFMpegAudDec * ffmpegdec)
 {
-  GstFFMpegAudDecClass *oclass;
-
-  oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
-
   GST_LOG_OBJECT (ffmpegdec, "closing libav codec");
 
   gst_caps_replace (&ffmpegdec->last_caps, NULL);
-
-  gst_ffmpeg_avcodec_close (ffmpegdec->context);
-  ffmpegdec->opened = FALSE;
-
   av_freep (&ffmpegdec->context->extradata);
-
-  if (reset) {
-    avcodec_free_context (&ffmpegdec->context);
-    ffmpegdec->context = avcodec_alloc_context3 (oclass->in_plugin);
-    if (ffmpegdec->context == NULL) {
-      GST_DEBUG_OBJECT (ffmpegdec, "Failed to set context defaults");
-      return FALSE;
-    }
-    ffmpegdec->context->opaque = ffmpegdec;
-  }
-
-  return TRUE;
+  avcodec_free_context (&ffmpegdec->context);
 }
 
 static gboolean
 gst_ffmpegauddec_start (GstAudioDecoder * decoder)
 {
   GstFFMpegAudDec *ffmpegdec = (GstFFMpegAudDec *) decoder;
-  GstFFMpegAudDecClass *oclass;
-
-  oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
 
   GST_OBJECT_LOCK (ffmpegdec);
+  ffmpegdec->frame = av_frame_alloc ();
   avcodec_free_context (&ffmpegdec->context);
-  ffmpegdec->context = avcodec_alloc_context3 (oclass->in_plugin);
-  if (ffmpegdec->context == NULL) {
-    GST_DEBUG_OBJECT (ffmpegdec, "Failed to set context defaults");
-    GST_OBJECT_UNLOCK (ffmpegdec);
-    return FALSE;
-  }
-  ffmpegdec->context->opaque = ffmpegdec;
-
-  /* FIXME: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1474 */
-  if ((oclass->in_plugin->capabilities & AV_CODEC_CAP_DELAY) != 0
-      && (oclass->in_plugin->id == AV_CODEC_ID_WMAV1
-          || oclass->in_plugin->id == AV_CODEC_ID_WMAV2)) {
-    ffmpegdec->context->flags2 |= AV_CODEC_FLAG2_SKIP_MANUAL;
-  }
-
   GST_OBJECT_UNLOCK (ffmpegdec);
 
   return TRUE;
 }
 
 static gboolean
 gst_ffmpegauddec_stop (GstAudioDecoder * decoder)
 {
   GstFFMpegAudDec *ffmpegdec = (GstFFMpegAudDec *) decoder;
 
   GST_OBJECT_LOCK (ffmpegdec);
-  gst_ffmpegauddec_close (ffmpegdec, FALSE);
+  av_frame_free (&ffmpegdec->frame);
   g_free (ffmpegdec->padded);
+  gst_ffmpegauddec_close (ffmpegdec);
   ffmpegdec->padded = NULL;
   ffmpegdec->padded_size = 0;
   GST_OBJECT_UNLOCK (ffmpegdec);
   gst_audio_info_init (&ffmpegdec->info);
   gst_caps_replace (&ffmpegdec->last_caps, NULL);
 
   return TRUE;
 }
 
 /* with LOCK */
 static gboolean
 gst_ffmpegauddec_open (GstFFMpegAudDec * ffmpegdec)
 {
   GstFFMpegAudDecClass *oclass;
 
   oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
 
   if (gst_ffmpeg_avcodec_open (ffmpegdec->context, oclass->in_plugin) < 0)
     goto could_not_open;
 
-  ffmpegdec->opened = TRUE;
-
   GST_LOG_OBJECT (ffmpegdec, "Opened libav codec %s, id %d",
       oclass->in_plugin->name, oclass->in_plugin->id);
 
   gst_audio_info_init (&ffmpegdec->info);
 
   return TRUE;
 
   /* ERRORS */
 could_not_open:
   {
-    gst_ffmpegauddec_close (ffmpegdec, TRUE);
+    gst_ffmpegauddec_close (ffmpegdec);
     GST_DEBUG_OBJECT (ffmpegdec, "avdec_%s: Failed to open libav codec",
         oclass->in_plugin->name);
     return FALSE;
@@ -321,14 +274,26 @@ gst_ffmpegauddec_set_format (GstAudioDecoder * decoder, GstCaps * caps)
   gst_caps_replace (&ffmpegdec->last_caps, caps);
 
   /* close old session */
-  if (ffmpegdec->opened) {
+  if (ffmpegdec->context) {
     GST_OBJECT_UNLOCK (ffmpegdec);
     gst_ffmpegauddec_drain (ffmpegdec, FALSE);
     GST_OBJECT_LOCK (ffmpegdec);
-    if (!gst_ffmpegauddec_close (ffmpegdec, TRUE)) {
-      GST_OBJECT_UNLOCK (ffmpegdec);
-      return FALSE;
-    }
+    gst_ffmpegauddec_close (ffmpegdec);
+  }
+
+  ffmpegdec->context = avcodec_alloc_context3 (oclass->in_plugin);
+  if (ffmpegdec->context == NULL) {
+    GST_DEBUG_OBJECT (ffmpegdec, "Failed to allocate context");
+    GST_OBJECT_UNLOCK (ffmpegdec);
+    return FALSE;
+  }
+  ffmpegdec->context->opaque = ffmpegdec;
+
+  /* FIXME: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1474 */
+  if ((oclass->in_plugin->capabilities & AV_CODEC_CAP_DELAY) != 0
+      && (oclass->in_plugin->id == AV_CODEC_ID_WMAV1
+          || oclass->in_plugin->id == AV_CODEC_ID_WMAV2)) {
+    ffmpegdec->context->flags2 |= AV_CODEC_FLAG2_SKIP_MANUAL;
   }
 
   /* get size and so */
@@ -586,7 +551,7 @@ gst_ffmpegauddec_frame (GstFFMpegAudDec * ffmpegdec, GstFlowReturn * ret,
   GstBuffer *outbuf = NULL;
   gboolean got_frame = FALSE;
 
-  if (G_UNLIKELY (ffmpegdec->context->codec == NULL))
+  if (G_UNLIKELY (!ffmpegdec->context))
     goto no_codec;
 
   *ret = GST_FLOW_OK;
@@ -630,6 +595,9 @@ gst_ffmpegauddec_drain (GstFFMpegAudDec * ffmpegdec, gboolean force)
   gboolean need_more_data = FALSE;
   gboolean got_frame;
 
+  if (!ffmpegdec->context)
+    return GST_FLOW_OK;
+
   if (avcodec_send_packet (ffmpegdec->context, NULL))
     goto send_packet_failed;
 
@@ -672,32 +640,32 @@ gst_ffmpegauddec_flush (GstAudioDecoder * decoder, gboolean hard)
 {
   GstFFMpegAudDec *ffmpegdec = (GstFFMpegAudDec *) decoder;
 
-  if (ffmpegdec->opened) {
+  if (ffmpegdec->context) {
     avcodec_flush_buffers (ffmpegdec->context);
   }
 }
 
 static GstFlowReturn
 gst_ffmpegauddec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf)
 {
   GstFFMpegAudDec *ffmpegdec;
   GstFFMpegAudDecClass *oclass;
   guint8 *data;
   GstMapInfo map;
   gint size;
   gboolean got_any_frames = FALSE;
   gboolean got_frame;
   GstFlowReturn ret = GST_FLOW_OK;
   gboolean is_header;
   AVPacket packet;
   GstAudioClippingMeta *clipping_meta = NULL;
   guint32 num_clipped_samples = 0;
   gboolean fully_clipped = FALSE;
   gboolean need_more_data = FALSE;
 
   ffmpegdec = (GstFFMpegAudDec *) decoder;
 
-  if (G_UNLIKELY (!ffmpegdec->opened))
+  if (G_UNLIKELY (!ffmpegdec->context))
     goto not_negotiated;
 
   if (inbuf == NULL) {
diff --git a/subprojects/gst-libav/ext/libav/gstavauddec.h b/subprojects/gst-libav/ext/libav/gstavauddec.h
index d91de0d2b29e..93466ad99fb4 100644
--- a/subprojects/gst-libav/ext/libav/gstavauddec.h
+++ b/subprojects/gst-libav/ext/libav/gstavauddec.h
@@ -34,7 +34,6 @@ struct _GstFFMpegAudDec
 
   /* decoding */
   AVCodecContext *context;
-  gboolean opened;
 
   AVFrame *frame;
 
diff --git a/subprojects/gst-libav/ext/libav/gstavaudenc.c b/subprojects/gst-libav/ext/libav/gstavaudenc.c
index 57f41fe617d0..6ff966d32cee 100644
--- a/subprojects/gst-libav/ext/libav/gstavaudenc.c
+++ b/subprojects/gst-libav/ext/libav/gstavaudenc.c
@@ -161,92 +161,80 @@ gst_ffmpegaudenc_init (GstFFMpegAudEnc * ffmpegaudenc)
   GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (ffmpegaudenc));
 
   /* ffmpeg objects */
-  ffmpegaudenc->context = avcodec_alloc_context3 (klass->in_plugin);
   ffmpegaudenc->refcontext = avcodec_alloc_context3 (klass->in_plugin);
-  ffmpegaudenc->opened = FALSE;
-  ffmpegaudenc->frame = av_frame_alloc ();
 
   gst_audio_encoder_set_drainable (GST_AUDIO_ENCODER (ffmpegaudenc), TRUE);
 }
 
 static void
 gst_ffmpegaudenc_finalize (GObject * object)
 {
   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) object;
 
   /* clean up remaining allocated data */
   av_frame_free (&ffmpegaudenc->frame);
   avcodec_free_context (&ffmpegaudenc->context);
   avcodec_free_context (&ffmpegaudenc->refcontext);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 static gboolean
 gst_ffmpegaudenc_start (GstAudioEncoder * encoder)
 {
   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
-  GstFFMpegAudEncClass *oclass =
-      (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);
-
-  ffmpegaudenc->opened = FALSE;
-  ffmpegaudenc->need_reopen = FALSE;
 
   avcodec_free_context (&ffmpegaudenc->context);
-  ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
-  if (ffmpegaudenc->context == NULL) {
-    GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
-    return FALSE;
-  }
+  av_frame_free (&ffmpegaudenc->frame);
+  ffmpegaudenc->need_reopen = FALSE;
+
+  ffmpegaudenc->frame = av_frame_alloc ();
 
   return TRUE;
 }
 
 static gboolean
 gst_ffmpegaudenc_stop (GstAudioEncoder * encoder)
 {
   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
 
   /* close old session */
-  gst_ffmpeg_avcodec_close (ffmpegaudenc->context);
-  ffmpegaudenc->opened = FALSE;
+  avcodec_free_context (&ffmpegaudenc->context);
+  av_frame_free (&ffmpegaudenc->frame);
   ffmpegaudenc->need_reopen = FALSE;
 
   return TRUE;
 }
 
 static void
 gst_ffmpegaudenc_flush (GstAudioEncoder * encoder)
 {
   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
 
-  if (ffmpegaudenc->opened) {
+  if (ffmpegaudenc->context) {
     avcodec_flush_buffers (ffmpegaudenc->context);
   }
 }
 
 static gboolean
 gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info)
 {
   GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
   GstCaps *other_caps;
   GstCaps *allowed_caps;
   GstCaps *icaps;
   gsize frame_size;
   GstFFMpegAudEncClass *oclass =
       (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc);
 
   ffmpegaudenc->need_reopen = FALSE;
 
   /* close old session */
-  if (ffmpegaudenc->opened) {
-    avcodec_free_context (&ffmpegaudenc->context);
-    ffmpegaudenc->opened = FALSE;
-    ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
-    if (ffmpegaudenc->context == NULL) {
-      GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
-      return FALSE;
-    }
+  avcodec_free_context (&ffmpegaudenc->context);
+  ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
+  if (ffmpegaudenc->context == NULL) {
+    GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
+    return FALSE;
   }
 
   gst_ffmpeg_cfg_fill_context (G_OBJECT (ffmpegaudenc), ffmpegaudenc->context);
@@ -298,56 +286,48 @@ gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info)
   /* open codec */
   if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) {
     gst_caps_unref (allowed_caps);
-    avcodec_free_context (&ffmpegaudenc->context);
     GST_DEBUG_OBJECT (ffmpegaudenc, "avenc_%s: Failed to open FFMPEG codec",
         oclass->in_plugin->name);
-    ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
-    if (ffmpegaudenc->context == NULL)
-      GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
 
     if ((oclass->in_plugin->capabilities & AV_CODEC_CAP_EXPERIMENTAL) &&
         ffmpegaudenc->context->strict_std_compliance !=
         FF_COMPLIANCE_EXPERIMENTAL) {
       GST_ELEMENT_ERROR (ffmpegaudenc, LIBRARY, SETTINGS,
           ("Codec is experimental, but settings don't allow encoders to "
               "produce output of experimental quality"),
           ("This codec may not create output that is conformant to the specs "
               "or of good quality. If you must use it anyway, set the "
               "compliance property to experimental"));
     }
+    avcodec_free_context (&ffmpegaudenc->context);
     return FALSE;
   }
 
   /* try to set this caps on the other side */
   other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
       ffmpegaudenc->context, TRUE);
 
   if (!other_caps) {
     gst_caps_unref (allowed_caps);
     avcodec_free_context (&ffmpegaudenc->context);
     GST_DEBUG ("Unsupported codec - no caps found");
-    ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
-    if (ffmpegaudenc->context == NULL)
-      GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
     return FALSE;
   }
 
   icaps = gst_caps_intersect (allowed_caps, other_caps);
   gst_caps_unref (allowed_caps);
   gst_caps_unref (other_caps);
   if (gst_caps_is_empty (icaps)) {
     gst_caps_unref (icaps);
+    avcodec_free_context (&ffmpegaudenc->context);
     return FALSE;
   }
   icaps = gst_caps_fixate (icaps);
 
   if (!gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (ffmpegaudenc),
           icaps)) {
     avcodec_free_context (&ffmpegaudenc->context);
     gst_caps_unref (icaps);
-    ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin);
-    if (ffmpegaudenc->context == NULL)
-      GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults");
     return FALSE;
   }
   gst_caps_unref (icaps);
@@ -385,17 +365,14 @@ gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info)
   }
 
   /* success! */
-  ffmpegaudenc->opened = TRUE;
-  ffmpegaudenc->need_reopen = FALSE;
 
   return TRUE;
 }
 
 static void
 gst_ffmpegaudenc_free_avpacket (gpointer pkt)
 {
-  av_packet_unref ((AVPacket *) pkt);
-  g_free (pkt);
+  av_packet_free ((AVPacket **) & pkt);
 }
 
 typedef struct
@@ -596,8 +573,7 @@ gst_ffmpegaudenc_receive_packet (GstFFMpegAudEnc * ffmpegaudenc,
 
   ctx = ffmpegaudenc->context;
 
-  pkt = g_new0 (AVPacket, 1);
-
+  pkt = av_packet_alloc ();
   res = avcodec_receive_packet (ctx, pkt);
 
   if (res == 0) {
@@ -636,20 +612,23 @@ gst_ffmpegaudenc_receive_packet (GstFFMpegAudEnc * ffmpegaudenc,
     *got_packet = TRUE;
   } else {
     GST_LOG_OBJECT (ffmpegaudenc, "no output produced");
-    g_free (pkt);
+    av_packet_free (&pkt);
     ret = GST_FLOW_OK;
     *got_packet = FALSE;
   }
 
   return ret;
 }
 
 static GstFlowReturn
 gst_ffmpegaudenc_drain (GstFFMpegAudEnc * ffmpegaudenc)
 {
   GstFlowReturn ret = GST_FLOW_OK;
   gboolean got_packet;
 
+  if (!ffmpegaudenc->context)
+    return GST_FLOW_OK;
+
   ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, NULL);
 
   if (ret == GST_FLOW_OK) {
@@ -683,7 +662,7 @@ gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder, GstBuffer * inbuf)
 
   ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
 
-  if (G_UNLIKELY (!ffmpegaudenc->opened))
+  if (G_UNLIKELY (!ffmpegaudenc->context))
     goto not_negotiated;
 
   if (!inbuf)
@@ -752,7 +731,7 @@ gst_ffmpegaudenc_set_property (GObject * object,
 
   ffmpegaudenc = (GstFFMpegAudEnc *) (object);
 
-  if (ffmpegaudenc->opened) {
+  if (ffmpegaudenc->context) {
     GST_WARNING_OBJECT (ffmpegaudenc,
         "Can't change properties once encoder is setup !");
     return;
diff --git a/subprojects/gst-libav/ext/libav/gstavaudenc.h b/subprojects/gst-libav/ext/libav/gstavaudenc.h
index 3c94aef4e061..e21de8337d6b 100644
--- a/subprojects/gst-libav/ext/libav/gstavaudenc.h
+++ b/subprojects/gst-libav/ext/libav/gstavaudenc.h
@@ -38,7 +38,6 @@ struct _GstFFMpegAudEnc
 
   AVCodecContext *context;
   AVCodecContext *refcontext;
-  gboolean opened;
   gboolean need_reopen;
 
   AVFrame *frame;
diff --git a/subprojects/gst-libav/ext/libav/gstavcfg.c b/subprojects/gst-libav/ext/libav/gstavcfg.c
index bcc501c39cc8..6092b086c474 100644
--- a/subprojects/gst-libav/ext/libav/gstavcfg.c
+++ b/subprojects/gst-libav/ext/libav/gstavcfg.c
@@ -488,10 +488,8 @@ gst_ffmpeg_cfg_install_properties (GObjectClass * klass, AVCodec * in_plugin,
       install_opts ((GObjectClass *) klass, &ctx->av_class, prop_id, flags,
       " (Generic codec option, might have no effect)", generic_overrides);
 
-  if (ctx) {
-    gst_ffmpeg_avcodec_close (ctx);
-    av_free (ctx);
-  }
+  if (ctx)
+    avcodec_free_context (&ctx);
 }
 
 static gint
diff --git a/subprojects/gst-libav/ext/libav/gstavcodecmap.c b/subprojects/gst-libav/ext/libav/gstavcodecmap.c
index c9c0a0fa7730..3d5c19d67d64 100644
--- a/subprojects/gst-libav/ext/libav/gstavcodecmap.c
+++ b/subprojects/gst-libav/ext/libav/gstavcodecmap.c
@@ -3833,6 +3833,18 @@ gst_ffmpeg_formatid_to_caps (const gchar * format_name)
     caps = gst_caps_from_string ("audio/x-brstm");
   } else if (!strcmp (format_name, "bfstm")) {
     caps = gst_caps_from_string ("audio/x-bfstm");
+  } else if (!strcmp (format_name, "avs")) {
+    caps = gst_caps_from_string ("video/x-avs");
+  } else if (!strcmp (format_name, "dsf")) {
+    caps = gst_caps_from_string ("audio/x-dsf");
+  } else if (!strcmp (format_name, "ea")) {
+    caps = gst_caps_from_string ("video/x-ea");
+  } else if (!strcmp (format_name, "film_cpk")) {
+    caps = gst_caps_from_string ("video/x-film-cpk");
+  } else if (!strcmp (format_name, "xwma")) {
+    caps = gst_caps_from_string ("audio/x-xwma");
+  } else if (!strcmp (format_name, "iff")) {
+    caps = gst_caps_from_string ("application/x-iff");
   } else {
     gchar *name;
 
@@ -4029,6 +4041,18 @@ gst_ffmpeg_formatid_get_codecids (const gchar * format_name,
 
     *video_codec_list = ivf_video_list;
     *audio_codec_list = ivf_audio_list;
+  } else if ((!strcmp (format_name, "film_cpk"))) {
+    static enum AVCodecID cpk_video_list[] = {
+      AV_CODEC_ID_CINEPAK,
+      AV_CODEC_ID_NONE
+    };
+    static enum AVCodecID cpk_audio_list[] = {
+      AV_CODEC_ID_PCM_S16BE,
+      AV_CODEC_ID_NONE
+    };
+
+    *video_codec_list = cpk_video_list;
+    *audio_codec_list = cpk_audio_list;
   } else if ((plugin->audio_codec != AV_CODEC_ID_NONE) ||
       (plugin->video_codec != AV_CODEC_ID_NONE)) {
     tmp_vlist[0] = plugin->video_codec;
diff --git a/subprojects/gst-libav/ext/libav/gstavdeinterlace.c b/subprojects/gst-libav/ext/libav/gstavdeinterlace.c
index 2d46c5090185..49dcdffb492f 100644
--- a/subprojects/gst-libav/ext/libav/gstavdeinterlace.c
+++ b/subprojects/gst-libav/ext/libav/gstavdeinterlace.c
@@ -225,14 +225,13 @@ gst_ffmpegdeinterlace_sink_setcaps (GstPad * pad, GstObject * parent,
   ctx->pix_fmt = AV_PIX_FMT_NB;
   gst_ffmpeg_caps_with_codectype (AVMEDIA_TYPE_VIDEO, caps, ctx);
   if (ctx->pix_fmt == AV_PIX_FMT_NB) {
-    gst_ffmpeg_avcodec_close (ctx);
-    av_free (ctx);
+    avcodec_free_context (&ctx);
     return FALSE;
   }
 
   deinterlace->pixfmt = ctx->pix_fmt;
 
-  av_free (ctx);
+  avcodec_free_context (&ctx);
 
   deinterlace->to_size =
       av_image_get_buffer_size (deinterlace->pixfmt, deinterlace->width,
diff --git a/subprojects/gst-libav/ext/libav/gstavdemux.c b/subprojects/gst-libav/ext/libav/gstavdemux.c
index ab6ac1b5c944..2c68d622f1a8 100644
--- a/subprojects/gst-libav/ext/libav/gstavdemux.c
+++ b/subprojects/gst-libav/ext/libav/gstavdemux.c
@@ -67,7 +67,6 @@ struct _GstFFMpegDemux
   guint group_id;
 
   AVFormatContext *context;
-  gboolean opened;
 
   GstFFStream *streams[MAX_STREAMS];
 
@@ -273,7 +272,6 @@ gst_ffmpegdemux_init (GstFFMpegDemux * demux)
   demux->have_group_id = FALSE;
   demux->group_id = G_MAXUINT;
 
-  demux->opened = FALSE;
   demux->context = NULL;
 
   for (n = 0; n < MAX_STREAMS; n++) {
@@ -324,7 +322,7 @@ gst_ffmpegdemux_close (GstFFMpegDemux * demux)
   gint n;
   GstEvent **event_p;
 
-  if (!demux->opened)
+  if (!demux->context)
     return;
 
   /* remove pads from ourselves */
@@ -353,12 +351,8 @@ gst_ffmpegdemux_close (GstFFMpegDemux * demux)
     gst_ffmpeg_pipe_close (demux->context->pb);
   demux->context->pb = NULL;
   avformat_close_input (&demux->context);
-  if (demux->context)
-    avformat_free_context (demux->context);
-  demux->context = NULL;
 
   GST_OBJECT_LOCK (demux);
-  demux->opened = FALSE;
   event_p = &demux->seek_event;
   gst_event_replace (event_p, NULL);
   GST_OBJECT_UNLOCK (demux);
@@ -700,7 +694,7 @@ gst_ffmpegdemux_send_event (GstElement * element, GstEvent * event)
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEEK:
       GST_OBJECT_LOCK (demux);
-      if (!demux->opened) {
+      if (!demux->context) {
         GstEvent **event_p;
 
         GST_DEBUG_OBJECT (demux, "caching seek event");
@@ -1309,7 +1303,6 @@ gst_ffmpegdemux_open (GstFFMpegDemux * demux)
   demux->segment.duration = demux->duration;
 
   GST_OBJECT_LOCK (demux);
-  demux->opened = TRUE;
   event = demux->seek_event;
   demux->seek_event = NULL;
   cached_events = demux->cached_events;
@@ -1366,88 +1359,40 @@ gst_ffmpegdemux_open (GstFFMpegDemux * demux)
   /* ERRORS */
 beach:
   {
+    if (demux->context->pb) {
+      if (demux->seekable)
+        gst_ffmpegdata_close (demux->context->pb);
+      else
+        gst_ffmpeg_pipe_close (demux->context->pb);
+      demux->context->pb = NULL;
+    }
+    avformat_close_input (&demux->context);
+
     GST_ELEMENT_ERROR (demux, LIBRARY, FAILED, (NULL),
         ("%s", gst_ffmpegdemux_averror (res)));
     return FALSE;
   }
 }
 
-#define GST_FFMPEG_TYPE_FIND_SIZE 4096
-#define GST_FFMPEG_TYPE_FIND_MIN_SIZE 256
-
-static void
-gst_ffmpegdemux_type_find (GstTypeFind * tf, gpointer priv)
-{
-  const guint8 *data;
-  AVInputFormat *in_plugin = (AVInputFormat *) priv;
-  gint res = 0;
-  guint64 length;
-  GstCaps *sinkcaps;
-
-  /* We want GST_FFMPEG_TYPE_FIND_SIZE bytes, but if the file is shorter than
-   * that we'll give it a try... */
-  length = gst_type_find_get_length (tf);
-  if (length == 0 || length > GST_FFMPEG_TYPE_FIND_SIZE)
-    length = GST_FFMPEG_TYPE_FIND_SIZE;
-
-  /* The ffmpeg typefinders assume there's a certain minimum amount of data
-   * and will happily do invalid memory access if there isn't, so let's just
-   * skip the ffmpeg typefinders if the data available is too short
-   * (in which case it's unlikely to be a media file anyway) */
-  if (length < GST_FFMPEG_TYPE_FIND_MIN_SIZE) {
-    GST_LOG ("not typefinding %" G_GUINT64_FORMAT " bytes, too short", length);
-    return;
-  }
-
-  GST_LOG ("typefinding %" G_GUINT64_FORMAT " bytes", length);
-  if (in_plugin->read_probe &&
-      (data = gst_type_find_peek (tf, 0, length)) != NULL) {
-    AVProbeData probe_data;
-
-    probe_data.filename = "";
-    probe_data.buf = (guint8 *) data;
-    probe_data.buf_size = length;
-
-    res = in_plugin->read_probe (&probe_data);
-    if (res > 0) {
-      res = MAX (1, res * GST_TYPE_FIND_MAXIMUM / AVPROBE_SCORE_MAX);
-      /* Restrict the probability for MPEG-TS streams, because there is
-       * probably a better version in plugins-base, if the user has a recent
-       * plugins-base (in fact we shouldn't even get here for ffmpeg mpegts or
-       * mpegtsraw typefinders, since we blacklist them) */
-      if (g_str_has_prefix (in_plugin->name, "mpegts"))
-        res = MIN (res, GST_TYPE_FIND_POSSIBLE);
-
-      sinkcaps = gst_ffmpeg_formatid_to_caps (in_plugin->name);
-
-      GST_LOG ("libav typefinder '%s' suggests %" GST_PTR_FORMAT ", p=%u%%",
-          in_plugin->name, sinkcaps, res);
-
-      gst_type_find_suggest (tf, res, sinkcaps);
-      gst_caps_unref (sinkcaps);
-    }
-  }
-}
-
 /* Task */
 static void
 gst_ffmpegdemux_loop (GstFFMpegDemux * demux)
 {
   GstFlowReturn ret;
   gint res = -1;
   AVPacket pkt;
   GstPad *srcpad;
   GstFFStream *stream;
   AVStream *avstream;
   GstBuffer *outbuf = NULL;
   GstClockTime timestamp, duration;
   gint outsize;
   gboolean rawvideo;
   GstFlowReturn stream_last_flow;
   gint64 pts;
 
   /* open file if we didn't so already */
-  if (!demux->opened)
+  if (!demux->context)
     if (!gst_ffmpegdemux_open (demux))
       goto open_failed;
 
@@ -1782,7 +1727,7 @@ gst_ffmpegdemux_sink_event (GstPad * sinkpad, GstObject * parent,
        * If the demuxer isn't opened, push straight away, since we'll
        * be waiting against a cond that will never be signalled. */
       if (GST_EVENT_IS_SERIALIZED (event)) {
-        if (demux->opened) {
+        if (demux->context) {
           GST_FFMPEG_PIPE_MUTEX_LOCK (ffpipe);
           while (!ffpipe->needed)
             GST_FFMPEG_PIPE_WAIT (ffpipe);
@@ -2055,7 +2000,6 @@ gst_ffmpegdemux_register (GstPlugin * plugin)
   while ((in_plugin = av_demuxer_iterate (&i))) {
     gchar *type_name, *typefind_name;
     gint rank;
-    gboolean register_typefind_func = TRUE;
 
     GST_LOG ("Attempting to handle libav demuxer plugin %s [%s]",
         in_plugin->name, in_plugin->long_name);
@@ -2102,42 +2046,6 @@ gst_ffmpegdemux_register (GstPlugin * plugin)
         !strcmp (in_plugin->name, "ffmetadata"))
       continue;
 
-    /* Don't use the typefind functions of formats for which we already have
-     * better typefind functions */
-    if (!strcmp (in_plugin->name, "mov,mp4,m4a,3gp,3g2,mj2") ||
-        !strcmp (in_plugin->name, "ass") ||
-        !strcmp (in_plugin->name, "avi") ||
-        !strcmp (in_plugin->name, "asf") ||
-        !strcmp (in_plugin->name, "mpegvideo") ||
-        !strcmp (in_plugin->name, "mp3") ||
-        !strcmp (in_plugin->name, "matroska") ||
-        !strcmp (in_plugin->name, "matroska_webm") ||
-        !strcmp (in_plugin->name, "matroska,webm") ||
-        !strcmp (in_plugin->name, "mpeg") ||
-        !strcmp (in_plugin->name, "wav") ||
-        !strcmp (in_plugin->name, "au") ||
-        !strcmp (in_plugin->name, "tta") ||
-        !strcmp (in_plugin->name, "rm") ||
-        !strcmp (in_plugin->name, "amr") ||
-        !strcmp (in_plugin->name, "ogg") ||
-        !strcmp (in_plugin->name, "aiff") ||
-        !strcmp (in_plugin->name, "ape") ||
-        !strcmp (in_plugin->name, "dv") ||
-        !strcmp (in_plugin->name, "flv") ||
-        !strcmp (in_plugin->name, "mpc") ||
-        !strcmp (in_plugin->name, "mpc8") ||
-        !strcmp (in_plugin->name, "mpegts") ||
-        !strcmp (in_plugin->name, "mpegtsraw") ||
-        !strcmp (in_plugin->name, "mxf") ||
-        !strcmp (in_plugin->name, "nuv") ||
-        !strcmp (in_plugin->name, "swf") ||
-        !strcmp (in_plugin->name, "voc") ||
-        !strcmp (in_plugin->name, "pva") ||
-        !strcmp (in_plugin->name, "gif") ||
-        !strcmp (in_plugin->name, "vc1test") ||
-        !strcmp (in_plugin->name, "ivf"))
-      register_typefind_func = FALSE;
-
     /* Set the rank of demuxers known to work to MARGINAL.
      * Set demuxers for which we already have another implementation to NONE
      * Set All others to NONE*/
@@ -2214,11 +2122,7 @@ gst_ffmpegdemux_register (GstPlugin * plugin)
     else
       extensions = NULL;
 
-    if (!gst_element_register (plugin, type_name, rank, type) ||
-        (register_typefind_func == TRUE &&
-            !gst_type_find_register (plugin, typefind_name, rank,
-                gst_ffmpegdemux_type_find, extensions, NULL,
-                (gpointer) in_plugin, NULL))) {
+    if (!gst_element_register (plugin, type_name, rank, type)) {
       g_warning ("Registration of type %s failed", type_name);
       g_free (type_name);
       g_free (typefind_name);
diff --git a/subprojects/gst-libav/ext/libav/gstavmux.c b/subprojects/gst-libav/ext/libav/gstavmux.c
index 60da7f0c29e1..389a873cf717 100644
--- a/subprojects/gst-libav/ext/libav/gstavmux.c
+++ b/subprojects/gst-libav/ext/libav/gstavmux.c
@@ -796,6 +796,7 @@ gst_ffmpegmux_change_state (GstElement * element, GstStateChange transition)
       if (ffmpegmux->opened) {
         ffmpegmux->opened = FALSE;
         gst_ffmpegdata_close (ffmpegmux->context->pb);
+        ffmpegmux->context->pb = NULL;
       }
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
diff --git a/subprojects/gst-libav/ext/libav/gstavprotocol.c b/subprojects/gst-libav/ext/libav/gstavprotocol.c
index 249b24064275..cb607d301299 100644
--- a/subprojects/gst-libav/ext/libav/gstavprotocol.c
+++ b/subprojects/gst-libav/ext/libav/gstavprotocol.c
@@ -102,7 +102,11 @@ gst_ffmpegdata_read (void *priv_data, unsigned char *buf, int size)
 }
 
 static int
+#if LIBAVUTIL_VERSION_MAJOR >= 59
+gst_ffmpegdata_write (void *priv_data, const uint8_t * buf, int size)
+#else
 gst_ffmpegdata_write (void *priv_data, uint8_t * buf, int size)
+#endif
 {
   GstProtocolInfo *info;
   GstBuffer *outbuf;
diff --git a/subprojects/gst-libav/ext/libav/gstavviddec.c b/subprojects/gst-libav/ext/libav/gstavviddec.c
index fe1ea51aa61b..f70da082b0fb 100644
--- a/subprojects/gst-libav/ext/libav/gstavviddec.c
+++ b/subprojects/gst-libav/ext/libav/gstavviddec.c
@@ -337,34 +337,29 @@ gst_ffmpegviddec_init (GstFFMpegVidDec * ffmpegdec)
 static void
 gst_ffmpegviddec_subinit (GstFFMpegVidDec * ffmpegdec)
 {
-  GstFFMpegVidDecClass *klass =
-      (GstFFMpegVidDecClass *) G_OBJECT_GET_CLASS (ffmpegdec);
-
   /* some ffmpeg data */
-  ffmpegdec->context = avcodec_alloc_context3 (klass->in_plugin);
-  ffmpegdec->context->opaque = ffmpegdec;
-  ffmpegdec->picture = av_frame_alloc ();
-  ffmpegdec->opened = FALSE;
   ffmpegdec->skip_frame = ffmpegdec->lowres = 0;
   ffmpegdec->direct_rendering = DEFAULT_DIRECT_RENDERING;
   ffmpegdec->max_threads = DEFAULT_MAX_THREADS;
   ffmpegdec->output_corrupt = DEFAULT_OUTPUT_CORRUPT;
   ffmpegdec->thread_type = DEFAULT_THREAD_TYPE;
   ffmpegdec->std_compliance = DEFAULT_STD_COMPLIANCE;
 
   GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_DECODER_SINK_PAD (ffmpegdec));
   gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST
       (ffmpegdec), TRUE);
 
   gst_video_decoder_set_needs_format (GST_VIDEO_DECODER (ffmpegdec), TRUE);
 }
 
 static void
 gst_ffmpegviddec_finalize (GObject * object)
 {
   GstFFMpegVidDec *ffmpegdec = GST_FFMPEGVIDDEC (object);
 
   av_frame_free (&ffmpegdec->picture);
+  if (ffmpegdec->context)
+    av_freep (&ffmpegdec->context->extradata);
   avcodec_free_context (&ffmpegdec->context);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -395,72 +390,56 @@ gst_ffmpegviddec_context_set_flags2 (AVCodecContext * context, guint flags,
 }
 
 /* with LOCK */
-static gboolean
-gst_ffmpegviddec_close (GstFFMpegVidDec * ffmpegdec, gboolean reset)
+static void
+gst_ffmpegviddec_close (GstFFMpegVidDec * ffmpegdec)
 {
-  GstFFMpegVidDecClass *oclass;
   guint i;
 
-  oclass = GST_FFMPEGVIDDEC_GET_CLASS (ffmpegdec);
-
   GST_LOG_OBJECT (ffmpegdec, "closing ffmpeg codec");
 
   gst_caps_replace (&ffmpegdec->last_caps, NULL);
 
-  gst_ffmpeg_avcodec_close (ffmpegdec->context);
-  ffmpegdec->opened = FALSE;
+  if (ffmpegdec->context)
+    av_freep (&ffmpegdec->context->extradata);
+  avcodec_free_context (&ffmpegdec->context);
 
   for (i = 0; i < G_N_ELEMENTS (ffmpegdec->stride); i++)
     ffmpegdec->stride[i] = -1;
 
   gst_buffer_replace (&ffmpegdec->palette, NULL);
-
-  av_freep (&ffmpegdec->context->extradata);
-  if (reset) {
-    avcodec_free_context (&ffmpegdec->context);
-    ffmpegdec->context = avcodec_alloc_context3 (oclass->in_plugin);
-    if (ffmpegdec->context == NULL) {
-      GST_DEBUG_OBJECT (ffmpegdec, "Failed to set context defaults");
-      return FALSE;
-    }
-    ffmpegdec->context->opaque = ffmpegdec;
-  }
-  return TRUE;
 }
 
 /* with LOCK */
 static gboolean
 gst_ffmpegviddec_open (GstFFMpegVidDec * ffmpegdec)
 {
   GstFFMpegVidDecClass *oclass;
   guint i;
 
   oclass = GST_FFMPEGVIDDEC_GET_CLASS (ffmpegdec);
 
   if (gst_ffmpeg_avcodec_open (ffmpegdec->context, oclass->in_plugin) < 0)
     goto could_not_open;
 
   for (i = 0; i < G_N_ELEMENTS (ffmpegdec->stride); i++)
     ffmpegdec->stride[i] = -1;
 
-  ffmpegdec->opened = TRUE;
-
   GST_LOG_OBJECT (ffmpegdec, "Opened libav codec %s, id %d",
       oclass->in_plugin->name, oclass->in_plugin->id);
 
   gst_ffmpegviddec_context_set_flags (ffmpegdec->context,
       AV_CODEC_FLAG_OUTPUT_CORRUPT, ffmpegdec->output_corrupt);
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT (60, 31, 100)
   gst_ffmpegviddec_context_set_flags (ffmpegdec->context,
       AV_CODEC_FLAG_COPY_OPAQUE, TRUE);
 #endif
 
   return TRUE;
 
   /* ERRORS */
 could_not_open:
   {
-    gst_ffmpegviddec_close (ffmpegdec, TRUE);
+    gst_ffmpegviddec_close (ffmpegdec);
     GST_DEBUG_OBJECT (ffmpegdec, "avdec_%s: Failed to open libav codec",
         oclass->in_plugin->name);
     return FALSE;
@@ -537,29 +516,34 @@ gst_ffmpegviddec_set_format (GstVideoDecoder * decoder,
   }
 
   /* close old session */
-  if (ffmpegdec->opened) {
+  if (ffmpegdec->context) {
     GST_OBJECT_UNLOCK (ffmpegdec);
     gst_ffmpegviddec_finish (decoder);
     GST_OBJECT_LOCK (ffmpegdec);
-    if (!gst_ffmpegviddec_close (ffmpegdec, TRUE)) {
-      GST_OBJECT_UNLOCK (ffmpegdec);
-      return FALSE;
-    }
+    gst_ffmpegviddec_close (ffmpegdec);
     ffmpegdec->pic_pix_fmt = 0;
     ffmpegdec->pic_width = 0;
     ffmpegdec->pic_height = 0;
     ffmpegdec->pic_par_n = 0;
     ffmpegdec->pic_par_d = 0;
     ffmpegdec->pic_interlaced = 0;
     ffmpegdec->pic_field_order = 0;
     ffmpegdec->pic_field_order_changed = FALSE;
     ffmpegdec->ctx_ticks = 0;
     ffmpegdec->ctx_time_n = 0;
     ffmpegdec->ctx_time_d = 0;
     ffmpegdec->cur_multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
     ffmpegdec->cur_multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
   }
 
+  ffmpegdec->context = avcodec_alloc_context3 (oclass->in_plugin);
+  if (ffmpegdec->context == NULL) {
+    GST_DEBUG_OBJECT (ffmpegdec, "Failed to allocate context");
+    GST_OBJECT_UNLOCK (ffmpegdec);
+    return FALSE;
+  }
+  ffmpegdec->context->opaque = ffmpegdec;
+
   gst_caps_replace (&ffmpegdec->last_caps, state->caps);
 
   /* set buffer functions */
@@ -686,7 +670,9 @@ update_state:
     const gint fps_n = ffmpegdec->context->time_base.den;
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(60, 31, 100)
     const gint ticks_per_frame =
-        (ffmpegdec->context->
+        (GST_VIDEO_INFO_IS_INTERLACED (&ffmpegdec->input_state->info)
+        && ffmpegdec->context->codec_descriptor
+        && ffmpegdec->context->
         codec_descriptor->props & AV_CODEC_PROP_FIELDS) ? 2 : 1;
 #else
     const gint ticks_per_frame = ffmpegdec->context->ticks_per_frame;
@@ -718,12 +704,18 @@ done:
 open_failed:
   {
     GST_DEBUG_OBJECT (ffmpegdec, "Failed to open");
+    if (ffmpegdec->context)
+      av_freep (&ffmpegdec->context->extradata);
+    avcodec_free_context (&ffmpegdec->context);
     goto done;
   }
 nal_only_slice:
   {
     GST_ERROR_OBJECT (ffmpegdec,
         "Can't do NAL aligned H.264 with frame threading.");
+    if (ffmpegdec->context)
+      av_freep (&ffmpegdec->context->extradata);
+    avcodec_free_context (&ffmpegdec->context);
     goto done;
   }
 }
@@ -1165,8 +1157,11 @@ static gboolean
 context_changed (GstFFMpegVidDec * ffmpegdec, AVCodecContext * context)
 {
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(60, 31, 100)
-  const gint ticks_per_frame = (context->codec_descriptor
-      && context->codec_descriptor->props & AV_CODEC_PROP_FIELDS) ? 2 : 1;
+  const gint ticks_per_frame =
+      (GST_VIDEO_INFO_IS_INTERLACED (&ffmpegdec->input_state->info)
+      && ffmpegdec->context->codec_descriptor
+      && ffmpegdec->context->
+      codec_descriptor->props & AV_CODEC_PROP_FIELDS) ? 2 : 1;
 #else
   const gint ticks_per_frame = context->ticks_per_frame;
 #endif
@@ -1238,8 +1233,11 @@ update_video_context (GstFFMpegVidDec * ffmpegdec, AVCodecContext * context,
     ffmpegdec->pic_field_order_changed = FALSE;
 
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(60, 31, 100)
-  const gint ticks_per_frame = (context->codec_descriptor
-      && context->codec_descriptor->props & AV_CODEC_PROP_FIELDS) ? 2 : 1;
+  const gint ticks_per_frame =
+      (GST_VIDEO_INFO_IS_INTERLACED (&ffmpegdec->input_state->info)
+      && ffmpegdec->context->codec_descriptor
+      && ffmpegdec->context->
+      codec_descriptor->props & AV_CODEC_PROP_FIELDS) ? 2 : 1;
 #else
   const gint ticks_per_frame = context->ticks_per_frame;
 #endif
@@ -2119,7 +2117,7 @@ gst_ffmpegviddec_frame (GstFFMpegVidDec * ffmpegdec, GstVideoCodecFrame * frame,
 {
   gboolean got_frame = FALSE;
 
-  if (G_UNLIKELY (ffmpegdec->context->codec == NULL))
+  if (G_UNLIKELY (!ffmpegdec->context))
     goto no_codec;
 
   *ret = GST_FLOW_OK;
@@ -2149,7 +2147,7 @@ gst_ffmpegviddec_drain (GstVideoDecoder * decoder)
   GstFlowReturn ret = GST_FLOW_OK;
   gboolean got_frame = FALSE;
 
-  if (!ffmpegdec->opened)
+  if (!ffmpegdec->context)
     return GST_FLOW_OK;
 
   GST_VIDEO_DECODER_STREAM_UNLOCK (ffmpegdec);
@@ -2195,15 +2193,22 @@ gst_ffmpegviddec_handle_frame (GstVideoDecoder * decoder,
   GstFlowReturn ret = GST_FLOW_OK;
   AVPacket *packet;
 
+  if (G_UNLIKELY (!ffmpegdec->context)) {
+    gst_video_codec_frame_unref (frame);
+    GST_ERROR_OBJECT (ffmpegdec, "no codec context");
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+
   GST_LOG_OBJECT (ffmpegdec,
       "Received new data of size %" G_GSIZE_FORMAT ", dts %" GST_TIME_FORMAT
       ", pts:%" GST_TIME_FORMAT ", dur:%" GST_TIME_FORMAT,
       gst_buffer_get_size (frame->input_buffer), GST_TIME_ARGS (frame->dts),
       GST_TIME_ARGS (frame->pts), GST_TIME_ARGS (frame->duration));
 
   if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) {
     GST_ELEMENT_ERROR (ffmpegdec, STREAM, DECODE, ("Decoding problem"),
         ("Failed to map buffer for reading"));
+    gst_video_codec_frame_unref (frame);
     return GST_FLOW_ERROR;
   }
 
@@ -2312,31 +2317,26 @@ static gboolean
 gst_ffmpegviddec_start (GstVideoDecoder * decoder)
 {
   GstFFMpegVidDec *ffmpegdec = GST_FFMPEGVIDDEC (decoder);
-  GstFFMpegVidDecClass *oclass;
-
-  oclass = GST_FFMPEGVIDDEC_GET_CLASS (ffmpegdec);
 
   GST_OBJECT_LOCK (ffmpegdec);
+  av_frame_free (&ffmpegdec->picture);
+  if (ffmpegdec->context)
+    av_freep (&ffmpegdec->context->extradata);
   avcodec_free_context (&ffmpegdec->context);
-  ffmpegdec->context = avcodec_alloc_context3 (oclass->in_plugin);
-  if (ffmpegdec->context == NULL) {
-    GST_DEBUG_OBJECT (ffmpegdec, "Failed to set context defaults");
-    GST_OBJECT_UNLOCK (ffmpegdec);
-    return FALSE;
-  }
-  ffmpegdec->context->opaque = ffmpegdec;
+  ffmpegdec->picture = av_frame_alloc ();
   GST_OBJECT_UNLOCK (ffmpegdec);
 
   return TRUE;
 }
 
 static gboolean
 gst_ffmpegviddec_stop (GstVideoDecoder * decoder)
 {
   GstFFMpegVidDec *ffmpegdec = GST_FFMPEGVIDDEC (decoder);
 
   GST_OBJECT_LOCK (ffmpegdec);
-  gst_ffmpegviddec_close (ffmpegdec, FALSE);
+  av_frame_free (&ffmpegdec->picture);
+  gst_ffmpegviddec_close (ffmpegdec);
   GST_OBJECT_UNLOCK (ffmpegdec);
   g_free (ffmpegdec->padded);
   ffmpegdec->padded = NULL;
@@ -2390,7 +2390,7 @@ gst_ffmpegviddec_flush (GstVideoDecoder * decoder)
 {
   GstFFMpegVidDec *ffmpegdec = GST_FFMPEGVIDDEC (decoder);
 
-  if (ffmpegdec->opened) {
+  if (ffmpegdec->context) {
     GST_LOG_OBJECT (decoder, "flushing buffers");
     GST_VIDEO_DECODER_STREAM_UNLOCK (ffmpegdec);
     avcodec_flush_buffers (ffmpegdec->context);
@@ -2579,11 +2579,10 @@ gst_ffmpegviddec_set_property (GObject * object,
 
   switch (prop_id) {
     case PROP_LOWRES:
-      ffmpegdec->lowres = ffmpegdec->context->lowres = g_value_get_enum (value);
+      ffmpegdec->lowres = g_value_get_enum (value);
       break;
     case PROP_SKIPFRAME:
-      ffmpegdec->skip_frame = ffmpegdec->context->skip_frame =
-          g_value_get_enum (value);
+      ffmpegdec->skip_frame = g_value_get_enum (value);
       break;
     case PROP_DIRECT_RENDERING:
       ffmpegdec->direct_rendering = g_value_get_boolean (value);
diff --git a/subprojects/gst-libav/ext/libav/gstavviddec.h b/subprojects/gst-libav/ext/libav/gstavviddec.h
index 0f713de5691c..14d5a9aff352 100644
--- a/subprojects/gst-libav/ext/libav/gstavviddec.h
+++ b/subprojects/gst-libav/ext/libav/gstavviddec.h
@@ -54,7 +54,6 @@ struct _GstFFMpegVidDec
   GstVideoMultiviewMode picture_multiview_mode;
   GstVideoMultiviewFlags picture_multiview_flags;
   gint stride[AV_NUM_DATA_POINTERS];
-  gboolean opened;
 
   /* current output pictures */
   enum AVPixelFormat pic_pix_fmt;
diff --git a/subprojects/gst-libav/ext/libav/gstavvidenc.c b/subprojects/gst-libav/ext/libav/gstavvidenc.c
index 461263b4f645..90c35d216dcf 100644
--- a/subprojects/gst-libav/ext/libav/gstavvidenc.c
+++ b/subprojects/gst-libav/ext/libav/gstavvidenc.c
@@ -208,54 +208,47 @@ gst_ffmpegvidenc_init (GstFFMpegVidEnc * ffmpegenc)
 
   GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (ffmpegenc));
 
-  ffmpegenc->context = avcodec_alloc_context3 (klass->in_plugin);
   ffmpegenc->refcontext = avcodec_alloc_context3 (klass->in_plugin);
-  ffmpegenc->picture = av_frame_alloc ();
-  ffmpegenc->opened = FALSE;
   ffmpegenc->file = NULL;
 }
 
 static void
 gst_ffmpegvidenc_finalize (GObject * object)
 {
   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) object;
 
   /* clean up remaining allocated data */
   av_frame_free (&ffmpegenc->picture);
-  gst_ffmpeg_avcodec_close (ffmpegenc->context);
-  gst_ffmpeg_avcodec_close (ffmpegenc->refcontext);
-  av_freep (&ffmpegenc->context);
-  av_freep (&ffmpegenc->refcontext);
+  avcodec_free_context (&ffmpegenc->context);
+  avcodec_free_context (&ffmpegenc->refcontext);
   g_free (ffmpegenc->filename);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 static gboolean
 gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
     GstVideoCodecState * state)
 {
   GstCaps *other_caps;
   GstCaps *allowed_caps;
   GstCaps *icaps;
   GstVideoCodecState *output_format;
   enum AVPixelFormat pix_fmt;
   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
   GstFFMpegVidEncClass *oclass =
       (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
 
   ffmpegenc->need_reopen = FALSE;
 
   /* close old session */
-  if (ffmpegenc->opened) {
-    avcodec_free_context (&ffmpegenc->context);
-    ffmpegenc->opened = FALSE;
-    ffmpegenc->context = avcodec_alloc_context3 (oclass->in_plugin);
-    if (ffmpegenc->context == NULL) {
-      GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
-      return FALSE;
-    }
+  avcodec_free_context (&ffmpegenc->context);
+  ffmpegenc->context = avcodec_alloc_context3 (oclass->in_plugin);
+  if (ffmpegenc->context == NULL) {
+    GST_DEBUG_OBJECT (ffmpegenc, "Failed to allocate context");
+    return FALSE;
   }
+  ffmpegenc->last_pts_ff = G_MININT64;
 
   /* additional avcodec settings */
   gst_ffmpeg_cfg_fill_context (G_OBJECT (ffmpegenc), ffmpegenc->context);
@@ -402,89 +395,87 @@ gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
 
   /* success! */
   ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
-  ffmpegenc->opened = TRUE;
 
   return TRUE;
 
   /* ERRORS */
 open_file_err:
   {
     GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, OPEN_WRITE,
         (("Could not open file \"%s\" for writing."), ffmpegenc->filename),
         GST_ERROR_SYSTEM);
+    avcodec_free_context (&ffmpegenc->context);
     return FALSE;
   }
 file_read_err:
   {
     GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, READ,
         (("Could not get contents of file \"%s\"."), ffmpegenc->filename),
         GST_ERROR_SYSTEM);
+    avcodec_free_context (&ffmpegenc->context);
     return FALSE;
   }
 
 insane_timebase:
   {
     GST_ERROR_OBJECT (ffmpegenc, "Rejecting time base %d/%d",
         ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num);
-    goto cleanup_stats_in;
+    goto close_codec;
   }
 unsupported_codec:
   {
     GST_DEBUG ("Unsupported codec - no caps found");
-    goto cleanup_stats_in;
+    goto close_codec;
   }
 open_codec_fail:
   {
     GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to open libav codec",
         oclass->in_plugin->name);
     goto close_codec;
   }
 
 pix_fmt_err:
   {
     GST_DEBUG_OBJECT (ffmpegenc,
         "avenc_%s: AV wants different colourspace (%d given, %d wanted)",
         oclass->in_plugin->name, pix_fmt, ffmpegenc->context->pix_fmt);
     goto close_codec;
   }
 
 bad_input_fmt:
   {
     GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to determine input format",
         oclass->in_plugin->name);
     goto close_codec;
   }
 close_codec:
   {
+    if (ffmpegenc->context)
+      g_free (ffmpegenc->context->stats_in);
+    if (ffmpegenc->file) {
+      fclose (ffmpegenc->file);
+      ffmpegenc->file = NULL;
+    }
     avcodec_free_context (&ffmpegenc->context);
-    ffmpegenc->context = avcodec_alloc_context3 (oclass->in_plugin);
-    if (ffmpegenc->context == NULL)
-      GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
-    goto cleanup_stats_in;
-  }
-cleanup_stats_in:
-  {
-    g_free (ffmpegenc->context->stats_in);
     return FALSE;
   }
 }
 
 
 static gboolean
 gst_ffmpegvidenc_propose_allocation (GstVideoEncoder * encoder,
     GstQuery * query)
 {
   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
 
   return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
       query);
 }
 
 static void
 gst_ffmpegvidenc_free_avpacket (gpointer pkt)
 {
-  av_packet_unref ((AVPacket *) pkt);
-  g_free (pkt);
+  av_packet_free ((AVPacket **) & pkt);
 }
 
 typedef struct
@@ -560,6 +551,7 @@ gst_ffmpegvidenc_send_frame (GstFFMpegVidEnc * ffmpegenc,
   gint res;
   GstFlowReturn ret = GST_FLOW_ERROR;
   AVFrame *picture = NULL;
+  GstClockTime pts, pts_running_time;
 
   if (!frame)
     goto send_frame;
@@ -629,26 +621,46 @@ gst_ffmpegvidenc_send_frame (GstFFMpegVidEnc * ffmpegenc,
   picture->width = GST_VIDEO_FRAME_WIDTH (&buffer_info->vframe);
   picture->height = GST_VIDEO_FRAME_HEIGHT (&buffer_info->vframe);
 
+  // Use the running time to calculate a PTS that is passed to the encoder.
+  // This ensures that it is increasing even if there are segment changes and
+  // makes it unnecessary to drain the encoder on every segment change.
+  pts = frame->pts;
+  pts_running_time =
+      gst_segment_to_running_time (&GST_VIDEO_ENCODER
+      (ffmpegenc)->input_segment, GST_FORMAT_TIME, pts);
+
   if (ffmpegenc->pts_offset == GST_CLOCK_TIME_NONE) {
-    ffmpegenc->pts_offset = frame->pts;
+    ffmpegenc->pts_offset = pts_running_time;
   }
 
-  if (frame->pts == GST_CLOCK_TIME_NONE) {
+  if (pts_running_time == GST_CLOCK_TIME_NONE) {
     picture->pts = AV_NOPTS_VALUE;
-  } else if (frame->pts < ffmpegenc->pts_offset) {
+  } else if (pts_running_time < ffmpegenc->pts_offset) {
     GST_ERROR_OBJECT (ffmpegenc, "PTS is going backwards");
     picture->pts = AV_NOPTS_VALUE;
   } else {
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(60, 31, 100)
-    const gint ticks_per_frame = (ffmpegenc->context->codec_descriptor
+    const gint ticks_per_frame =
+        (GST_VIDEO_INFO_IS_INTERLACED (&ffmpegenc->input_state->info)
+        && ffmpegenc->context->codec_descriptor
         && ffmpegenc->context->
         codec_descriptor->props & AV_CODEC_PROP_FIELDS) ? 2 : 1;
 #else
     const gint ticks_per_frame = ffmpegenc->context->ticks_per_frame;
 #endif
     picture->pts =
-        gst_ffmpeg_time_gst_to_ff ((frame->pts - ffmpegenc->pts_offset) /
+        gst_ffmpeg_time_gst_to_ff ((pts_running_time - ffmpegenc->pts_offset) /
         ticks_per_frame, ffmpegenc->context->time_base);
+
+    // Certain codecs require always increasing PTS to work correctly. This
+    // affects at least all MPEG1/2/4 based encoders.
+    if (ffmpegenc->last_pts_ff == G_MININT64
+        || picture->pts > ffmpegenc->last_pts_ff) {
+      ffmpegenc->last_pts_ff = picture->pts;
+    } else {
+      ffmpegenc->last_pts_ff += 1;
+      picture->pts = ffmpegenc->last_pts_ff;
+    }
   }
 
 send_frame:
@@ -692,18 +704,18 @@ gst_ffmpegvidenc_receive_packet (GstFFMpegVidEnc * ffmpegenc,
 
   *got_packet = FALSE;
 
-  pkt = g_new0 (AVPacket, 1);
-
+  pkt = av_packet_alloc ();
   res = avcodec_receive_packet (ffmpegenc->context, pkt);
 
   if (res == AVERROR (EAGAIN)) {
-    g_free (pkt);
+    av_packet_free (&pkt);
     goto done;
   } else if (res == AVERROR_EOF) {
-    g_free (pkt);
+    av_packet_free (&pkt);
     ret = GST_FLOW_EOS;
     goto done;
   } else if (res < 0) {
+    av_packet_free (&pkt);
     ret = GST_FLOW_ERROR;
     goto done;
   }
@@ -743,50 +755,52 @@ gst_ffmpegvidenc_receive_packet (GstFFMpegVidEnc * ffmpegenc,
           ffmpegenc->context->time_base);
 
       if (gst_pts_dts_diff > frame->pts)
-        frame->pts = 0;
+        frame->dts = 0;
       else
         frame->dts = frame->pts - gst_pts_dts_diff;
     } else {
       frame->dts = frame->pts +
           gst_ffmpeg_time_ff_to_gst (pts_dts_diff,
           ffmpegenc->context->time_base);
     }
   }
 
   ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame);
 
 done:
   return ret;
 }
 
 static GstFlowReturn
 gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder,
     GstVideoCodecFrame * frame)
 {
   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
   GstFlowReturn ret;
   gboolean got_packet;
 
-  /* endoder was drained or flushed, and ffmpeg encoder doesn't support
+  /* encoder was drained or flushed, and ffmpeg encoder doesn't support
    * flushing. We need to re-open encoder then */
   if (ffmpegenc->need_reopen) {
     gboolean reopen_ret;
     GstVideoCodecState *input_state;
 
     GST_DEBUG_OBJECT (ffmpegenc, "Open encoder again");
 
     if (!ffmpegenc->input_state) {
       GST_ERROR_OBJECT (ffmpegenc,
           "Cannot re-open encoder without input state");
+      gst_video_codec_frame_unref (frame);
       return GST_FLOW_NOT_NEGOTIATED;
     }
 
     input_state = gst_video_codec_state_ref (ffmpegenc->input_state);
     reopen_ret = gst_ffmpegvidenc_set_format (encoder, input_state);
     gst_video_codec_state_unref (input_state);
 
     if (!reopen_ret) {
       GST_ERROR_OBJECT (ffmpegenc, "Couldn't re-open encoder");
+      gst_video_codec_frame_unref (frame);
       return GST_FLOW_NOT_NEGOTIATED;
     }
   }
@@ -831,7 +845,7 @@ gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send)
   GST_DEBUG_OBJECT (ffmpegenc, "flushing buffers with sending %d", send);
 
   /* no need to empty codec if there is none */
-  if (!ffmpegenc->opened)
+  if (!ffmpegenc->context)
     goto done;
 
   ret = gst_ffmpegvidenc_send_frame (ffmpegenc, NULL);
@@ -867,7 +881,7 @@ gst_ffmpegvidenc_set_property (GObject * object,
 
   ffmpegenc = (GstFFMpegVidEnc *) (object);
 
-  if (ffmpegenc->opened) {
+  if (ffmpegenc->context) {
     GST_WARNING_OBJECT (ffmpegenc,
         "Can't change properties once decoder is setup !");
     return;
@@ -921,45 +935,50 @@ gst_ffmpegvidenc_flush (GstVideoEncoder * encoder)
 {
   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
 
-  if (ffmpegenc->opened) {
+  if (ffmpegenc->context) {
     avcodec_flush_buffers (ffmpegenc->context);
     ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
   }
 
   return TRUE;
 }
 
 static gboolean
 gst_ffmpegvidenc_start (GstVideoEncoder * encoder)
 {
   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
-  GstFFMpegVidEncClass *oclass =
-      (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
-
-  ffmpegenc->opened = FALSE;
-  ffmpegenc->need_reopen = FALSE;
 
   /* close old session */
-  avcodec_free_context (&ffmpegenc->context);
-  ffmpegenc->context = avcodec_alloc_context3 (oclass->in_plugin);
-  if (ffmpegenc->context == NULL) {
-    GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults");
-    return FALSE;
+  if (ffmpegenc->file) {
+    fclose (ffmpegenc->file);
+    ffmpegenc->file = NULL;
   }
+  if (ffmpegenc->context)
+    g_free (ffmpegenc->context->stats_in);
+  avcodec_free_context (&ffmpegenc->context);
+  av_frame_free (&ffmpegenc->picture);
+  ffmpegenc->need_reopen = FALSE;
 
+  ffmpegenc->picture = av_frame_alloc ();
   gst_video_encoder_set_min_pts (encoder, GST_SECOND * 60 * 60 * 1000);
 
   return TRUE;
 }
 
 static gboolean
 gst_ffmpegvidenc_stop (GstVideoEncoder * encoder)
 {
   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
 
   gst_ffmpegvidenc_flush_buffers (ffmpegenc, FALSE);
-  gst_ffmpeg_avcodec_close (ffmpegenc->context);
-  ffmpegenc->opened = FALSE;
+  if (ffmpegenc->context)
+    g_free (ffmpegenc->context->stats_in);
+  if (ffmpegenc->file) {
+    fclose (ffmpegenc->file);
+    ffmpegenc->file = NULL;
+  }
+  avcodec_free_context (&ffmpegenc->context);
+  av_frame_free (&ffmpegenc->picture);
   ffmpegenc->need_reopen = FALSE;
 
   if (ffmpegenc->input_state) {
diff --git a/subprojects/gst-libav/ext/libav/gstavvidenc.h b/subprojects/gst-libav/ext/libav/gstavvidenc.h
index 340fb2520421..3b1f2e848825 100644
--- a/subprojects/gst-libav/ext/libav/gstavvidenc.h
+++ b/subprojects/gst-libav/ext/libav/gstavvidenc.h
@@ -41,7 +41,7 @@ struct _GstFFMpegVidEnc
   AVCodecContext *context;
   AVFrame *picture;
   GstClockTime pts_offset;
-  gboolean opened;
+  gint64 last_pts_ff;
   gboolean need_reopen;
   gboolean discont;
   guint pass;

