mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-29 05:01:23 +00:00
appsrc: extract buffering level calculations
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5321>
This commit is contained in:
parent
aa515b0276
commit
4c13ccec16
4 changed files with 323 additions and 195 deletions
|
@ -101,6 +101,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "gstappsrc.h"
|
||||
#include "gstapputils.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -178,11 +179,7 @@ struct _GstAppSrcPrivate
|
|||
gboolean flushing;
|
||||
gboolean started;
|
||||
gboolean is_eos;
|
||||
guint64 queued_bytes, queued_buffers;
|
||||
/* Used to calculate the current time level */
|
||||
GstClockTime last_in_running_time, last_out_running_time;
|
||||
/* Updated based on the above whenever they change */
|
||||
GstClockTime queued_time;
|
||||
GstQueueStatusInfo queue_status_info;
|
||||
guint64 offset;
|
||||
GstAppStreamType current_type;
|
||||
|
||||
|
@ -795,11 +792,7 @@ gst_app_src_flush_queued (GstAppSrc * src, gboolean retain_last_caps)
|
|||
gst_queue_array_clear (priv->delayed_events);
|
||||
priv->pushed_buffer = FALSE;
|
||||
|
||||
priv->queued_bytes = 0;
|
||||
priv->queued_buffers = 0;
|
||||
priv->queued_time = 0;
|
||||
priv->last_in_running_time = GST_CLOCK_TIME_NONE;
|
||||
priv->last_out_running_time = GST_CLOCK_TIME_NONE;
|
||||
gst_queue_status_info_reset (&priv->queue_status_info);
|
||||
priv->need_discont_upstream = FALSE;
|
||||
priv->need_discont_downstream = FALSE;
|
||||
}
|
||||
|
@ -1384,92 +1377,18 @@ gst_app_src_update_queued_pop (GstAppSrc * appsrc, GstMiniObject * item,
|
|||
gboolean update_offset)
|
||||
{
|
||||
GstAppSrcPrivate *priv = appsrc->priv;
|
||||
guint buf_size = 0;
|
||||
guint n_buffers = 0;
|
||||
GstClockTime end_buffer_ts = GST_CLOCK_TIME_NONE;
|
||||
guint64 old_queued_bytes = priv->queue_status_info.queued_bytes;
|
||||
guint64 bytes_dequeued;
|
||||
|
||||
if (GST_IS_BUFFER (item)) {
|
||||
GstBuffer *buf = GST_BUFFER_CAST (item);
|
||||
buf_size = gst_buffer_get_size (buf);
|
||||
n_buffers = 1;
|
||||
gst_queue_status_info_pop (&priv->queue_status_info, item,
|
||||
&priv->current_segment, &priv->last_segment, GST_OBJECT_CAST (appsrc));
|
||||
|
||||
end_buffer_ts = GST_BUFFER_DTS_OR_PTS (buf);
|
||||
if (end_buffer_ts != GST_CLOCK_TIME_NONE
|
||||
&& GST_BUFFER_DURATION_IS_VALID (buf))
|
||||
end_buffer_ts += GST_BUFFER_DURATION (buf);
|
||||
|
||||
GST_LOG_OBJECT (appsrc, "have buffer %p of size %u", buf, buf_size);
|
||||
} else if (GST_IS_BUFFER_LIST (item)) {
|
||||
GstBufferList *buffer_list = GST_BUFFER_LIST_CAST (item);
|
||||
guint i;
|
||||
|
||||
n_buffers = gst_buffer_list_length (buffer_list);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
GstBuffer *tmp = gst_buffer_list_get (buffer_list, i);
|
||||
GstClockTime ts = GST_BUFFER_DTS_OR_PTS (tmp);
|
||||
|
||||
buf_size += gst_buffer_get_size (tmp);
|
||||
/* Update to the last buffer's timestamp that is known */
|
||||
if (ts != GST_CLOCK_TIME_NONE) {
|
||||
end_buffer_ts = ts;
|
||||
if (GST_BUFFER_DURATION_IS_VALID (tmp))
|
||||
end_buffer_ts += GST_BUFFER_DURATION (tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
priv->queued_bytes -= buf_size;
|
||||
priv->queued_buffers -= n_buffers;
|
||||
|
||||
/* Update time level if working on a TIME segment */
|
||||
if ((priv->current_segment.format == GST_FORMAT_TIME
|
||||
|| (priv->current_segment.format == GST_FORMAT_UNDEFINED
|
||||
&& priv->last_segment.format == GST_FORMAT_TIME))
|
||||
&& end_buffer_ts != GST_CLOCK_TIME_NONE) {
|
||||
const GstSegment *segment =
|
||||
priv->current_segment.format ==
|
||||
GST_FORMAT_TIME ? &priv->current_segment : &priv->last_segment;
|
||||
|
||||
/* Clip to the current segment boundaries */
|
||||
if (segment->stop != -1 && end_buffer_ts > segment->stop)
|
||||
end_buffer_ts = segment->stop;
|
||||
else if (segment->start > end_buffer_ts)
|
||||
end_buffer_ts = segment->start;
|
||||
|
||||
priv->last_out_running_time =
|
||||
gst_segment_to_running_time (segment, GST_FORMAT_TIME, end_buffer_ts);
|
||||
|
||||
GST_TRACE_OBJECT (appsrc,
|
||||
"Last in running time %" GST_TIME_FORMAT ", last out running time %"
|
||||
GST_TIME_FORMAT, GST_TIME_ARGS (priv->last_in_running_time),
|
||||
GST_TIME_ARGS (priv->last_out_running_time));
|
||||
|
||||
/* If timestamps on both sides are known, calculate the current
|
||||
* fill level in time and consider the queue empty if the output
|
||||
* running time is lower than the input one (i.e. some kind of reset
|
||||
* has happened).
|
||||
*/
|
||||
if (priv->last_out_running_time != GST_CLOCK_TIME_NONE
|
||||
&& priv->last_in_running_time != GST_CLOCK_TIME_NONE) {
|
||||
if (priv->last_out_running_time > priv->last_in_running_time) {
|
||||
priv->queued_time = 0;
|
||||
} else {
|
||||
priv->queued_time =
|
||||
priv->last_in_running_time - priv->last_out_running_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (appsrc,
|
||||
"Currently queued: %" G_GUINT64_FORMAT " bytes, %" G_GUINT64_FORMAT
|
||||
" buffers, %" GST_TIME_FORMAT, priv->queued_bytes,
|
||||
priv->queued_buffers, GST_TIME_ARGS (priv->queued_time));
|
||||
bytes_dequeued = old_queued_bytes - priv->queue_status_info.queued_bytes;
|
||||
|
||||
/* only update the offset when in random_access mode and when requested by
|
||||
* the caller, i.e. not when just dropping the item */
|
||||
if (update_offset && priv->stream_type == GST_APP_STREAM_TYPE_RANDOM_ACCESS)
|
||||
priv->offset += buf_size;
|
||||
priv->offset += bytes_dequeued;
|
||||
}
|
||||
|
||||
/* Update the currently queued bytes/buffers/time information for the item
|
||||
|
@ -1479,99 +1398,11 @@ static void
|
|||
gst_app_src_update_queued_push (GstAppSrc * appsrc, GstMiniObject * item)
|
||||
{
|
||||
GstAppSrcPrivate *priv = appsrc->priv;
|
||||
GstClockTime start_buffer_ts = GST_CLOCK_TIME_NONE;
|
||||
GstClockTime end_buffer_ts = GST_CLOCK_TIME_NONE;
|
||||
guint buf_size = 0;
|
||||
guint n_buffers = 0;
|
||||
|
||||
if (GST_IS_BUFFER (item)) {
|
||||
GstBuffer *buf = GST_BUFFER_CAST (item);
|
||||
|
||||
buf_size = gst_buffer_get_size (buf);
|
||||
n_buffers = 1;
|
||||
|
||||
start_buffer_ts = end_buffer_ts = GST_BUFFER_DTS_OR_PTS (buf);
|
||||
if (end_buffer_ts != GST_CLOCK_TIME_NONE
|
||||
&& GST_BUFFER_DURATION_IS_VALID (buf))
|
||||
end_buffer_ts += GST_BUFFER_DURATION (buf);
|
||||
} else if (GST_IS_BUFFER_LIST (item)) {
|
||||
GstBufferList *buffer_list = GST_BUFFER_LIST_CAST (item);
|
||||
guint i;
|
||||
|
||||
n_buffers = gst_buffer_list_length (buffer_list);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
GstBuffer *tmp = gst_buffer_list_get (buffer_list, i);
|
||||
GstClockTime ts = GST_BUFFER_DTS_OR_PTS (tmp);
|
||||
|
||||
buf_size += gst_buffer_get_size (tmp);
|
||||
|
||||
if (ts != GST_CLOCK_TIME_NONE) {
|
||||
if (start_buffer_ts == GST_CLOCK_TIME_NONE)
|
||||
start_buffer_ts = ts;
|
||||
end_buffer_ts = ts;
|
||||
if (GST_BUFFER_DURATION_IS_VALID (tmp))
|
||||
end_buffer_ts += GST_BUFFER_DURATION (tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
priv->queued_bytes += buf_size;
|
||||
priv->queued_buffers += n_buffers;
|
||||
|
||||
/* Update time level if working on a TIME segment */
|
||||
if (priv->last_segment.format == GST_FORMAT_TIME
|
||||
&& end_buffer_ts != GST_CLOCK_TIME_NONE) {
|
||||
/* Clip to the last segment boundaries */
|
||||
if (priv->last_segment.stop != -1
|
||||
&& end_buffer_ts > priv->last_segment.stop)
|
||||
end_buffer_ts = priv->last_segment.stop;
|
||||
else if (priv->last_segment.start > end_buffer_ts)
|
||||
end_buffer_ts = priv->last_segment.start;
|
||||
|
||||
priv->last_in_running_time =
|
||||
gst_segment_to_running_time (&priv->last_segment, GST_FORMAT_TIME,
|
||||
end_buffer_ts);
|
||||
|
||||
/* If this is the only buffer then we can directly update the queued time
|
||||
* here. This is especially useful if this was the first buffer because
|
||||
* otherwise we would have to wait until it is actually unqueued to know
|
||||
* the queued duration */
|
||||
if (priv->queued_buffers == 1) {
|
||||
if (priv->last_segment.stop != -1
|
||||
&& start_buffer_ts > priv->last_segment.stop)
|
||||
start_buffer_ts = priv->last_segment.stop;
|
||||
else if (priv->last_segment.start > start_buffer_ts)
|
||||
start_buffer_ts = priv->last_segment.start;
|
||||
|
||||
priv->last_out_running_time =
|
||||
gst_segment_to_running_time (&priv->last_segment, GST_FORMAT_TIME,
|
||||
start_buffer_ts);
|
||||
}
|
||||
|
||||
GST_TRACE_OBJECT (appsrc,
|
||||
"Last in running time %" GST_TIME_FORMAT ", last out running time %"
|
||||
GST_TIME_FORMAT, GST_TIME_ARGS (priv->last_in_running_time),
|
||||
GST_TIME_ARGS (priv->last_out_running_time));
|
||||
|
||||
if (priv->last_out_running_time != GST_CLOCK_TIME_NONE
|
||||
&& priv->last_in_running_time != GST_CLOCK_TIME_NONE) {
|
||||
if (priv->last_out_running_time > priv->last_in_running_time) {
|
||||
priv->queued_time = 0;
|
||||
} else {
|
||||
priv->queued_time =
|
||||
priv->last_in_running_time - priv->last_out_running_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (appsrc,
|
||||
"Currently queued: %" G_GUINT64_FORMAT " bytes, %" G_GUINT64_FORMAT
|
||||
" buffers, %" GST_TIME_FORMAT, priv->queued_bytes, priv->queued_buffers,
|
||||
GST_TIME_ARGS (priv->queued_time));
|
||||
gst_queue_status_info_push (&priv->queue_status_info, item,
|
||||
&priv->last_segment, GST_OBJECT_CAST (appsrc));
|
||||
}
|
||||
|
||||
/* check if @obj should be send after the CAPS and SEGMENT events */
|
||||
/* check if @obj should be sent after the CAPS and SEGMENT events */
|
||||
static gboolean
|
||||
needs_segment (GstMiniObject * obj)
|
||||
{
|
||||
|
@ -1828,11 +1659,11 @@ gst_app_src_create (GstBaseSrc * bsrc, guint64 offset, guint size,
|
|||
/* see if we go lower than the min-percent */
|
||||
if (priv->min_percent) {
|
||||
if ((priv->max_bytes
|
||||
&& priv->queued_bytes * 100 / priv->max_bytes <=
|
||||
priv->min_percent) || (priv->max_buffers
|
||||
&& priv->queued_buffers * 100 / priv->max_buffers <=
|
||||
priv->min_percent) || (priv->max_time
|
||||
&& priv->queued_time * 100 / priv->max_time <=
|
||||
&& priv->queue_status_info.queued_bytes * 100 /
|
||||
priv->max_bytes <= priv->min_percent) || (priv->max_buffers
|
||||
&& priv->queue_status_info.queued_buffers * 100 /
|
||||
priv->max_buffers <= priv->min_percent) || (priv->max_time
|
||||
&& priv->queue_status_info.queued_time * 100 / priv->max_time <=
|
||||
priv->min_percent)) {
|
||||
/* ignore flushing state, we got a buffer and we will return it now.
|
||||
* Errors will be handled in the next round */
|
||||
|
@ -2211,7 +2042,7 @@ gst_app_src_get_current_level_bytes (GstAppSrc * appsrc)
|
|||
priv = appsrc->priv;
|
||||
|
||||
GST_OBJECT_LOCK (appsrc);
|
||||
queued = priv->queued_bytes;
|
||||
queued = priv->queue_status_info.queued_bytes;
|
||||
GST_DEBUG_OBJECT (appsrc, "current level bytes is %" G_GUINT64_FORMAT,
|
||||
queued);
|
||||
GST_OBJECT_UNLOCK (appsrc);
|
||||
|
@ -2299,7 +2130,7 @@ gst_app_src_get_current_level_buffers (GstAppSrc * appsrc)
|
|||
priv = appsrc->priv;
|
||||
|
||||
GST_OBJECT_LOCK (appsrc);
|
||||
queued = priv->queued_buffers;
|
||||
queued = priv->queue_status_info.queued_buffers;
|
||||
GST_DEBUG_OBJECT (appsrc, "current level buffers is %" G_GUINT64_FORMAT,
|
||||
queued);
|
||||
GST_OBJECT_UNLOCK (appsrc);
|
||||
|
@ -2388,7 +2219,7 @@ gst_app_src_get_current_level_time (GstAppSrc * appsrc)
|
|||
priv = appsrc->priv;
|
||||
|
||||
GST_OBJECT_LOCK (appsrc);
|
||||
queued = priv->queued_time;
|
||||
queued = priv->queue_status_info.queued_time;
|
||||
GST_DEBUG_OBJECT (appsrc, "current level time is %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (queued));
|
||||
GST_OBJECT_UNLOCK (appsrc);
|
||||
|
@ -2631,16 +2462,16 @@ gst_app_src_push_internal (GstAppSrc * appsrc, GstBuffer * buffer,
|
|||
if (priv->is_eos)
|
||||
goto eos;
|
||||
|
||||
if ((priv->max_bytes && priv->queued_bytes >= priv->max_bytes) ||
|
||||
(priv->max_buffers && priv->queued_buffers >= priv->max_buffers) ||
|
||||
(priv->max_time && priv->queued_time >= priv->max_time)) {
|
||||
if (gst_queue_status_info_is_full (&priv->queue_status_info,
|
||||
priv->max_buffers, priv->max_bytes, priv->max_time)) {
|
||||
GST_DEBUG_OBJECT (appsrc,
|
||||
"queue filled (queued %" G_GUINT64_FORMAT " bytes, max %"
|
||||
G_GUINT64_FORMAT " bytes, " "queued %" G_GUINT64_FORMAT
|
||||
" buffers, max %" G_GUINT64_FORMAT " buffers, " "queued %"
|
||||
GST_TIME_FORMAT " time, max %" GST_TIME_FORMAT " time)",
|
||||
priv->queued_bytes, priv->max_bytes, priv->queued_buffers,
|
||||
priv->max_buffers, GST_TIME_ARGS (priv->queued_time),
|
||||
priv->queue_status_info.queued_bytes, priv->max_bytes,
|
||||
priv->queue_status_info.queued_buffers, priv->max_buffers,
|
||||
GST_TIME_ARGS (priv->queue_status_info.queued_time),
|
||||
GST_TIME_ARGS (priv->max_time));
|
||||
|
||||
if (first) {
|
||||
|
|
250
subprojects/gst-plugins-base/gst-libs/gst/app/gstapputils.c
Normal file
250
subprojects/gst-plugins-base/gst-libs/gst/app/gstapputils.c
Normal file
|
@ -0,0 +1,250 @@
|
|||
/* GStreamer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "gstapputils.h"
|
||||
|
||||
void
|
||||
gst_queue_status_info_reset (GstQueueStatusInfo * info)
|
||||
{
|
||||
g_return_if_fail (info != NULL);
|
||||
|
||||
info->queued_bytes = 0;
|
||||
info->queued_buffers = 0;
|
||||
info->queued_time = 0;
|
||||
info->num_events = 0;
|
||||
info->last_in_running_time = GST_CLOCK_TIME_NONE;
|
||||
info->last_out_running_time = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_queue_status_info_is_full (const GstQueueStatusInfo * info,
|
||||
guint64 max_buffers, guint64 max_bytes, GstClockTime max_time)
|
||||
{
|
||||
g_return_val_if_fail (info != NULL, FALSE);
|
||||
|
||||
return (max_buffers > 0 && info->queued_buffers >= max_buffers)
|
||||
|| (max_bytes > 0 && info->queued_bytes >= max_bytes)
|
||||
|| (max_time > 0 && info->queued_time >= max_time);
|
||||
}
|
||||
|
||||
void
|
||||
gst_queue_status_info_push_event (GstQueueStatusInfo * info)
|
||||
{
|
||||
g_return_if_fail (info != NULL);
|
||||
|
||||
info->num_events++;
|
||||
}
|
||||
|
||||
/* Update the currently queued bytes/buffers/time information for the item
|
||||
* that was just added to the queue.
|
||||
*/
|
||||
void
|
||||
gst_queue_status_info_push (GstQueueStatusInfo * info, GstMiniObject * item,
|
||||
GstSegment * last_segment, GstObject * log_context)
|
||||
{
|
||||
GstClockTime start_buffer_ts = GST_CLOCK_TIME_NONE;
|
||||
GstClockTime end_buffer_ts = GST_CLOCK_TIME_NONE;
|
||||
guint buf_size = 0;
|
||||
guint n_buffers = 0;
|
||||
|
||||
g_return_if_fail (info != NULL);
|
||||
|
||||
if (GST_IS_EVENT (item)) {
|
||||
info->num_events++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (GST_IS_BUFFER (item)) {
|
||||
GstBuffer *buf = GST_BUFFER_CAST (item);
|
||||
|
||||
buf_size = gst_buffer_get_size (buf);
|
||||
n_buffers = 1;
|
||||
|
||||
start_buffer_ts = end_buffer_ts = GST_BUFFER_DTS_OR_PTS (buf);
|
||||
if (end_buffer_ts != GST_CLOCK_TIME_NONE
|
||||
&& GST_BUFFER_DURATION_IS_VALID (buf))
|
||||
end_buffer_ts += GST_BUFFER_DURATION (buf);
|
||||
} else if (GST_IS_BUFFER_LIST (item)) {
|
||||
GstBufferList *buffer_list = GST_BUFFER_LIST_CAST (item);
|
||||
guint i;
|
||||
|
||||
n_buffers = gst_buffer_list_length (buffer_list);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
GstBuffer *tmp = gst_buffer_list_get (buffer_list, i);
|
||||
GstClockTime ts = GST_BUFFER_DTS_OR_PTS (tmp);
|
||||
|
||||
buf_size += gst_buffer_get_size (tmp);
|
||||
|
||||
if (ts != GST_CLOCK_TIME_NONE) {
|
||||
if (start_buffer_ts == GST_CLOCK_TIME_NONE)
|
||||
start_buffer_ts = ts;
|
||||
end_buffer_ts = ts;
|
||||
if (GST_BUFFER_DURATION_IS_VALID (tmp))
|
||||
end_buffer_ts += GST_BUFFER_DURATION (tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info->queued_bytes += buf_size;
|
||||
info->queued_buffers += n_buffers;
|
||||
|
||||
/* Update time level if working on a TIME segment */
|
||||
if (last_segment->format == GST_FORMAT_TIME
|
||||
&& end_buffer_ts != GST_CLOCK_TIME_NONE) {
|
||||
/* Clip to the last segment boundaries */
|
||||
if (last_segment->stop != -1 && end_buffer_ts > last_segment->stop)
|
||||
end_buffer_ts = last_segment->stop;
|
||||
else if (last_segment->start > end_buffer_ts)
|
||||
end_buffer_ts = last_segment->start;
|
||||
|
||||
info->last_in_running_time =
|
||||
gst_segment_to_running_time (last_segment, GST_FORMAT_TIME,
|
||||
end_buffer_ts);
|
||||
|
||||
/* If this is the only buffer then we can directly update the queued time
|
||||
* here. This is especially useful if this was the first buffer because
|
||||
* otherwise we would have to wait until it is actually unqueued to know
|
||||
* the queued duration */
|
||||
if (info->queued_buffers == 1) {
|
||||
if (last_segment->stop != -1 && start_buffer_ts > last_segment->stop)
|
||||
start_buffer_ts = last_segment->stop;
|
||||
else if (last_segment->start > start_buffer_ts)
|
||||
start_buffer_ts = last_segment->start;
|
||||
|
||||
info->last_out_running_time =
|
||||
gst_segment_to_running_time (last_segment, GST_FORMAT_TIME,
|
||||
start_buffer_ts);
|
||||
}
|
||||
|
||||
GST_TRACE_OBJECT (log_context,
|
||||
"Last in running time %" GST_TIME_FORMAT ", last out running time %"
|
||||
GST_TIME_FORMAT, GST_TIME_ARGS (info->last_in_running_time),
|
||||
GST_TIME_ARGS (info->last_out_running_time));
|
||||
|
||||
if (info->last_out_running_time != GST_CLOCK_TIME_NONE
|
||||
&& info->last_in_running_time != GST_CLOCK_TIME_NONE) {
|
||||
if (info->last_out_running_time > info->last_in_running_time) {
|
||||
info->queued_time = 0;
|
||||
} else {
|
||||
info->queued_time =
|
||||
info->last_in_running_time - info->last_out_running_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (log_context,
|
||||
"Currently queued: %" G_GUINT64_FORMAT " bytes, %" G_GUINT64_FORMAT
|
||||
" buffers, %" GST_TIME_FORMAT, info->queued_bytes, info->queued_buffers,
|
||||
GST_TIME_ARGS (info->queued_time));
|
||||
}
|
||||
|
||||
void
|
||||
gst_queue_status_info_pop (GstQueueStatusInfo * info, GstMiniObject * item,
|
||||
GstSegment * current_segment, GstSegment * last_segment,
|
||||
GstObject * log_context)
|
||||
{
|
||||
guint buf_size = 0;
|
||||
guint n_buffers = 0;
|
||||
GstClockTime end_buffer_ts = GST_CLOCK_TIME_NONE;
|
||||
|
||||
g_return_if_fail (info != NULL);
|
||||
|
||||
if (GST_IS_EVENT (item)) {
|
||||
info->num_events--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (GST_IS_BUFFER (item)) {
|
||||
GstBuffer *buf = GST_BUFFER_CAST (item);
|
||||
buf_size = gst_buffer_get_size (buf);
|
||||
n_buffers = 1;
|
||||
|
||||
end_buffer_ts = GST_BUFFER_DTS_OR_PTS (buf);
|
||||
if (end_buffer_ts != GST_CLOCK_TIME_NONE
|
||||
&& GST_BUFFER_DURATION_IS_VALID (buf))
|
||||
end_buffer_ts += GST_BUFFER_DURATION (buf);
|
||||
|
||||
GST_LOG_OBJECT (log_context, "have buffer %p of size %u", buf, buf_size);
|
||||
} else if (GST_IS_BUFFER_LIST (item)) {
|
||||
GstBufferList *buffer_list = GST_BUFFER_LIST_CAST (item);
|
||||
guint i;
|
||||
|
||||
n_buffers = gst_buffer_list_length (buffer_list);
|
||||
|
||||
for (i = 0; i < n_buffers; i++) {
|
||||
GstBuffer *tmp = gst_buffer_list_get (buffer_list, i);
|
||||
GstClockTime ts = GST_BUFFER_DTS_OR_PTS (tmp);
|
||||
|
||||
buf_size += gst_buffer_get_size (tmp);
|
||||
/* Update to the last buffer's timestamp that is known */
|
||||
if (ts != GST_CLOCK_TIME_NONE) {
|
||||
end_buffer_ts = ts;
|
||||
if (GST_BUFFER_DURATION_IS_VALID (tmp))
|
||||
end_buffer_ts += GST_BUFFER_DURATION (tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info->queued_bytes -= buf_size;
|
||||
info->queued_buffers -= n_buffers;
|
||||
|
||||
/* Update time level if working on a TIME segment */
|
||||
if ((current_segment->format == GST_FORMAT_TIME
|
||||
|| (current_segment->format == GST_FORMAT_UNDEFINED
|
||||
&& last_segment->format == GST_FORMAT_TIME))
|
||||
&& end_buffer_ts != GST_CLOCK_TIME_NONE) {
|
||||
const GstSegment *segment =
|
||||
current_segment->format ==
|
||||
GST_FORMAT_TIME ? current_segment : last_segment;
|
||||
|
||||
/* Clip to the current segment boundaries */
|
||||
if (segment->stop != -1 && end_buffer_ts > segment->stop)
|
||||
end_buffer_ts = segment->stop;
|
||||
else if (segment->start > end_buffer_ts)
|
||||
end_buffer_ts = segment->start;
|
||||
|
||||
info->last_out_running_time =
|
||||
gst_segment_to_running_time (segment, GST_FORMAT_TIME, end_buffer_ts);
|
||||
|
||||
GST_TRACE_OBJECT (log_context,
|
||||
"Last in running time %" GST_TIME_FORMAT ", last out running time %"
|
||||
GST_TIME_FORMAT, GST_TIME_ARGS (info->last_in_running_time),
|
||||
GST_TIME_ARGS (info->last_out_running_time));
|
||||
|
||||
/* If timestamps on both sides are known, calculate the current
|
||||
* fill level in time and consider the queue empty if the output
|
||||
* running time is lower than the input one (i.e. some kind of reset
|
||||
* has happened).
|
||||
*/
|
||||
if (info->last_out_running_time != GST_CLOCK_TIME_NONE
|
||||
&& info->last_in_running_time != GST_CLOCK_TIME_NONE) {
|
||||
if (info->last_out_running_time > info->last_in_running_time) {
|
||||
info->queued_time = 0;
|
||||
} else {
|
||||
info->queued_time =
|
||||
info->last_in_running_time - info->last_out_running_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (log_context,
|
||||
"Currently queued: %" G_GUINT64_FORMAT " bytes, %" G_GUINT64_FORMAT
|
||||
" buffers, %" GST_TIME_FORMAT, info->queued_bytes,
|
||||
info->queued_buffers, GST_TIME_ARGS (info->queued_time));
|
||||
}
|
47
subprojects/gst-plugins-base/gst-libs/gst/app/gstapputils.h
Normal file
47
subprojects/gst-plugins-base/gst-libs/gst/app/gstapputils.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* GStreamer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef _GST_APP_UTILS_H_
|
||||
#define _GST_APP_UTILS_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
typedef struct _GstQueueStatusInfo
|
||||
{
|
||||
guint64 queued_bytes, queued_buffers;
|
||||
/* Used to calculate the current time level */
|
||||
GstClockTime last_in_running_time, last_out_running_time;
|
||||
/* Updated based on the above whenever they change */
|
||||
GstClockTime queued_time;
|
||||
guint num_events;
|
||||
} GstQueueStatusInfo;
|
||||
|
||||
void gst_queue_status_info_reset (GstQueueStatusInfo * info);
|
||||
|
||||
gboolean gst_queue_status_info_is_full (const GstQueueStatusInfo * info,
|
||||
guint64 max_buffers, guint64 max_bytes, GstClockTime max_time);
|
||||
|
||||
void gst_queue_status_info_push (GstQueueStatusInfo * info,
|
||||
GstMiniObject * item, GstSegment * last_segment, GstObject * log_context);
|
||||
|
||||
void gst_queue_status_info_push_event (GstQueueStatusInfo * info);
|
||||
|
||||
void gst_queue_status_info_pop (GstQueueStatusInfo * info, GstMiniObject * item,
|
||||
GstSegment * current_segment, GstSegment * last_segment,
|
||||
GstObject * log_context);
|
||||
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
app_sources = files(['gstappsrc.c', 'gstappsink.c'])
|
||||
app_sources = files(['gstappsrc.c', 'gstappsink.c', 'gstapputils.c'])
|
||||
|
||||
app_mkenum_headers = files([
|
||||
'gstappsrc.h',
|
||||
|
|
Loading…
Reference in a new issue