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
This commit is contained in:
Aurélien Zanelli 2014-05-30 15:29:15 +02:00 committed by Sebastian Dröge
parent 4c488d425d
commit ad969ffda3

View file

@ -1167,6 +1167,53 @@ done:
return err;
}
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)
{
@ -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) {