summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurélien Zanelli <aurelien.zanelli@parrot.com>2014-05-30 15:29:15 +0200
committerSebastian Dröge <sebastian@centricular.com>2014-06-04 16:36:02 +0200
commitad969ffda34f671252d115fbb3293fae43f1b0e6 (patch)
treeb6630a376d1e0fffbd0237aa44ec0374858b44b9
parent4c488d425d2dfb3dbb7225aa55b0425050f0531b (diff)
downloadgst-omx-ad969ffda34f671252d115fbb3293fae43f1b0e6.tar.gz
omxvideodec: release frames with old PTS to avoid memory issue
Interlaced stream could make the decoder use two input frames to produce one output frame causing the gstvideodecoder frame list to grow. Assuming the video decoder output frame in display order rather than in decoding order, this commit add a way to release frames with PTS less than current output frame. https://bugzilla.gnome.org/show_bug.cgi?id=730995
-rw-r--r--omx/gstomxvideodec.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c
index 207ba88..2fc7f19 100644
--- a/omx/gstomxvideodec.c
+++ b/omx/gstomxvideodec.c
@@ -1168,6 +1168,53 @@ done:
}
static void
+gst_omx_video_dec_clean_older_frames (GstOMXVideoDec * self,
+ GstOMXBuffer * buf, GList * frames)
+{
+ GList *l;
+ GstClockTime timestamp;
+
+ timestamp = gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND,
+ OMX_TICKS_PER_SECOND);
+
+ if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+ /* We could release all frames stored with pts < timestamp since the
+ * decoder will likely output frames in display order */
+ for (l = frames; l; l = l->next) {
+ GstVideoCodecFrame *tmp = l->data;
+
+ if (tmp->pts < timestamp) {
+ gst_video_decoder_release_frame (GST_VIDEO_DECODER (self), tmp);
+ GST_LOG_OBJECT (self,
+ "discarding ghost frame %p (#%d) PTS:%" GST_TIME_FORMAT " DTS:%"
+ GST_TIME_FORMAT, tmp, tmp->system_frame_number,
+ GST_TIME_ARGS (tmp->pts), GST_TIME_ARGS (tmp->dts));
+ } else {
+ gst_video_codec_frame_unref (tmp);
+ }
+ }
+ } else {
+ /* We will release all frames with invalid timestamp because we don't even
+ * know if they will be output some day. */
+ for (l = frames; l; l = l->next) {
+ GstVideoCodecFrame *tmp = l->data;
+
+ if (!GST_CLOCK_TIME_IS_VALID (tmp->pts)) {
+ gst_video_decoder_release_frame (GST_VIDEO_DECODER (self), tmp);
+ GST_LOG_OBJECT (self,
+ "discarding frame %p (#%d) with invalid PTS:%" GST_TIME_FORMAT
+ " DTS:%" GST_TIME_FORMAT, tmp, tmp->system_frame_number,
+ GST_TIME_ARGS (tmp->pts), GST_TIME_ARGS (tmp->dts));
+ } else {
+ gst_video_codec_frame_unref (tmp);
+ }
+ }
+ }
+
+ g_list_free (frames);
+}
+
+static void
gst_omx_video_dec_loop (GstOMXVideoDec * self)
{
GstOMXPort *port;
@@ -1297,6 +1344,15 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
frame = gst_omx_video_find_nearest_frame (buf,
gst_video_decoder_get_frames (GST_VIDEO_DECODER (self)));
+ /* So we have a timestamped OMX buffer and get, or not, corresponding frame.
+ * Assuming decoder output frames in display order, frames preceding this
+ * frame could be discarded as they seems useless due to e.g interlaced
+ * stream, corrupted input data...
+ * In any cases, not likely to be seen again. so drop it before they pile up
+ * and use all the memory. */
+ gst_omx_video_dec_clean_older_frames (self, buf,
+ gst_video_decoder_get_frames (GST_VIDEO_DECODER (self)));
+
if (frame
&& (deadline = gst_video_decoder_get_max_decode_time
(GST_VIDEO_DECODER (self), frame)) < 0) {