vpxenc: discard frames that have been dropped by libvpx

This fixes a memory leak. When dropframe-threshold has been set,
libvpx may output less frames than the input ones, which causes
some GstVideoCodecFrames to queue up in GstVideoEncoder's internal
frame queue with no chance of ever being all released. And because
the frames keep references to the input buffers, the input buffer
pool keeps allocating new buffers and memory usage grows very fast.
For example the following pipeline's memory usage grows at a rate
of about 1GB per minute!

videotestsrc ! capsfilter caps=video/x-raw,width=1920,height=1080,framerate=30/1,format=I420 ! \
  vp8enc target-bitrate=1000000 end-usage=cbr dropframe-threshold=95 ! fakesink

https://bugzilla.gnome.org/show_bug.cgi?id=783086
This commit is contained in:
George Kiagiadakis 2017-07-27 17:21:48 +03:00
parent 5e48e85fb7
commit 36fc2a747a

View file

@ -1668,6 +1668,7 @@ gst_vpx_enc_process (GstVPXEnc * encoder)
GstVideoCodecFrame *frame;
GstFlowReturn ret = GST_FLOW_OK;
GstVPXEncClass *vpx_enc_class;
vpx_codec_pts_t pts;
video_encoder = GST_VIDEO_ENCODER (encoder);
vpx_enc_class = GST_VPX_ENC_GET_CLASS (encoder);
@ -1707,7 +1708,21 @@ gst_vpx_enc_process (GstVPXEnc * encoder)
}
invisible = (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) != 0;
/* discard older frames that were dropped by libvpx */
frame = NULL;
do {
if (frame)
gst_video_encoder_finish_frame (video_encoder, frame);
frame = gst_video_encoder_get_oldest_frame (video_encoder);
pts =
gst_util_uint64_scale (frame->pts,
encoder->cfg.g_timebase.den,
encoder->cfg.g_timebase.num * (GstClockTime) GST_SECOND);
GST_TRACE_OBJECT (encoder, "vpx pts: %" G_GINT64_FORMAT
", gst frame pts: %" G_GINT64_FORMAT, pkt->data.frame.pts, pts);
} while (pkt->data.frame.pts > pts);
g_assert (frame != NULL);
if ((pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0)
GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);