+++ b/ext/libav/gstavviddec.c
@@ -79,6 +82,9 @@ struct _GstFFMpegVidDec
 
   gboolean is_realvideo;
 
+  // twc/mlr:
+  gboolean allocated_out;       /* Decode allocated a buffer, else drop input */
+
   GstCaps *last_caps;
 };
 
@@ -601,6 +607,9 @@ gst_ffmpegviddec_get_buffer (AVCodecContext * context, AVFrame * picture)
   if (G_UNLIKELY (frame == NULL))
     goto no_frame;
 
+  // twc/mlr: If we got here, we should not release the input frame after decode.
+  ffmpegdec->allocated_out = TRUE;
+
   if (G_UNLIKELY (frame->output_buffer != NULL))
     goto duplicate_frame;
 
@@ -1163,6 +1179,8 @@ gst_ffmpegviddec_video_frame (GstFFMpegVidDec * ffmpegdec,
     memcpy (pal, ffmpegdec->context->palctrl->palette, AVPALETTE_SIZE);
     GST_DEBUG_OBJECT (ffmpegdec, "copy pal %p %p", &packet, pal);
   }
+  // twc/mlr: Clear flag, if decode sets it then keep input frame.
+  ffmpegdec->allocated_out = FALSE;
 
   len = avcodec_decode_video2 (ffmpegdec->context,
       ffmpegdec->picture, &have_data, &packet);
@@ -1171,8 +1189,23 @@ gst_ffmpegviddec_video_frame (GstFFMpegVidDec * ffmpegdec,
   if (!decode)
     ffmpegdec->context->skip_frame = skip_frame;
 
-  GST_DEBUG_OBJECT (ffmpegdec, "after decode: len %d, have_data %d",
-      len, have_data);
+  GST_INFO_OBJECT (ffmpegdec, "after decode: len %d, have_data %d, FA=%d",
+      len, have_data, ffmpegdec->allocated_out);
+
+#ifdef CFG_H264_FIXES
+  // twc/mlr:  If decode failed, release input frame.
+  if (len < 0) {
+    if (frame && (!ffmpegdec->allocated_out)) {
+      GST_INFO ("err free frame=%d, ref=%d", frame->system_frame_number,
+          frame->ref_count);
+      ++frame->ref_count;
+      GST_VIDEO_CODEC_FRAME_FLAG_SET (frame,
+          GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
+      gst_video_decoder_finish_frame (GST_VIDEO_DECODER (ffmpegdec), frame);
+    }
+    goto beach;
+  }
+#endif
 
   /* when we are in skip_frame mode, don't complain when ffmpeg returned
    * no data because we told it to skip stuff. */
@@ -1233,9 +1269,26 @@ gst_ffmpegviddec_video_frame (GstFFMpegVidDec * ffmpegdec,
           GST_VIDEO_BUFFER_FLAG_INTERLACED);
   }
 
+  if (frame) {
+    GST_INFO ("fin frame=%d, out=%d, out_ref=%d", frame->system_frame_number,
+        out_frame->system_frame_number, out_frame->ref_count);
+  }
+
   *ret =
       gst_video_decoder_finish_frame (GST_VIDEO_DECODER (ffmpegdec), out_frame);
 
+#ifdef CFG_H264_FIXES
+  // twc/mlr:  Release input frame if not used for output
+  if (frame && (!ffmpegdec->allocated_out)) {
+    GST_INFO ("free frame=%d, ref=%d", frame->system_frame_number,
+        frame->ref_count);
+    ++frame->ref_count;
+    GST_VIDEO_CODEC_FRAME_FLAG_SET (frame,
+        GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
+    gst_video_decoder_finish_frame (GST_VIDEO_DECODER (ffmpegdec), frame);
+  }
+#endif
+
 beach:
   GST_DEBUG_OBJECT (ffmpegdec, "return flow %s, len %d",
       gst_flow_get_name (*ret), len);
@@ -1454,6 +1507,13 @@ gst_ffmpegviddec_handle_frame (GstVideoDecoder * decoder,
     GST_DEBUG_OBJECT (ffmpegdec, "Dropping %d bytes of data", bsize);
 
   gst_buffer_unmap (frame->input_buffer, &minfo);
+
+#ifdef CFG_H264_FIXES
+  // twc/mlr:  Release input early
+  gst_buffer_unref (frame->input_buffer);
+  frame->input_buffer = 0;
+#endif
+
   gst_video_codec_frame_unref (frame);
 
   return ret;
