diff options
author | George Kiagiadakis <george.kiagiadakis@collabora.com> | 2017-07-27 17:21:48 +0300 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2017-08-17 13:35:34 +0300 |
commit | 4abc746fcdf76a1ade14c30e06be778f3fff29a2 (patch) | |
tree | 746c47f2b14924064f49f7e8327fa1d2cd980988 /ext/vpx/gstvpxenc.c | |
parent | 3c3c1d3e205a397f744c46bd3a4f97acad71deb5 (diff) | |
download | gstreamer-plugins-good-4abc746fcdf76a1ade14c30e06be778f3fff29a2.tar.gz |
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
Diffstat (limited to 'ext/vpx/gstvpxenc.c')
-rw-r--r-- | ext/vpx/gstvpxenc.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/ext/vpx/gstvpxenc.c b/ext/vpx/gstvpxenc.c index 003d4640f..1fa2cccf3 100644 --- a/ext/vpx/gstvpxenc.c +++ b/ext/vpx/gstvpxenc.c @@ -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; - frame = gst_video_encoder_get_oldest_frame (video_encoder); + + /* 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); |