gstmediasourcesamplemap: Re-worked sample iteration and removal

Both operations now work on coded frame groups (GOPs). This simplifies queueing
of video data. There is rarely any point of dealing with individual video frames
when iterating in DTS order, it's most meaningful to decode or delete whole
coded frame groups at a time, so the sample map will now do that when iterating
by DTS. When iterating in PTS order, the existing behavior is preserved since
that is used for informational purposes, not media processing.

A new private boxed type for coded frame groups was added to provide each data
item to the source buffer. Another possible solution would be creation of a new
GstSample representing the whole group by merging all the samples in a group
into a single sample containing a GstBufferList.

Also, start time filtering was removed from the API since gst_iterator_filter()
can be used by callers to achieve the same result.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8512>
This commit is contained in:
Jordan Yelloz 2025-02-18 13:08:37 -07:00 committed by GStreamer Marge Bot
parent 5aa3f7c16e
commit 4f5cda94f7
3 changed files with 419 additions and 259 deletions

View File

@ -23,7 +23,6 @@
#pragma once
#include <gst/gst.h>
#include <glib-object.h>
#include <gst/mse/mse-prelude.h>
G_BEGIN_DECLS
@ -31,6 +30,22 @@ G_BEGIN_DECLS
#define GST_TYPE_MEDIA_SOURCE_SAMPLE_MAP \
(gst_media_source_sample_map_get_type())
#define GST_TYPE_MEDIA_SOURCE_CODED_FRAME_GROUP \
(gst_media_source_coded_frame_group_get_type())
#define gst_value_get_media_source_coded_frame_group(v) \
(GstMediaSourceCodedFrameGroup *)(g_value_get_boxed (v))
#define gst_value_take_media_source_coded_frame_group(v, g) \
g_value_take_boxed ((v), (g))
typedef struct {
GstClockTime start;
GstClockTime end;
gsize size;
GList *samples;
} GstMediaSourceCodedFrameGroup;
GST_MSE_PRIVATE
G_DECLARE_FINAL_TYPE (GstMediaSourceSampleMap, gst_media_source_sample_map, GST,
MEDIA_SOURCE_SAMPLE_MAP, GstObject);
@ -50,16 +65,6 @@ GST_MSE_PRIVATE
gsize gst_media_source_sample_map_remove_range (GstMediaSourceSampleMap * self,
GstClockTime earliest, GstClockTime latest);
GST_MSE_PRIVATE
gsize
gst_media_source_sample_map_remove_range_from_start (GstMediaSourceSampleMap
* self, GstClockTime latest_dts);
GST_MSE_PRIVATE
gsize
gst_media_source_sample_map_remove_range_from_end (GstMediaSourceSampleMap
* self, GstClockTime earliest_dts);
GST_MSE_PRIVATE
gboolean gst_media_source_sample_map_contains (GstMediaSourceSampleMap * self,
GstSample * sample);
@ -81,14 +86,23 @@ gsize gst_media_source_sample_map_get_storage_size (
GST_MSE_PRIVATE
GstIterator *
gst_media_source_sample_map_iter_samples_by_dts (GstMediaSourceSampleMap * map,
GMutex * lock, guint32 * master_cookie, GstClockTime start_dts,
GstSample * start_sample);
gst_media_source_sample_map_iter_samples_by_dts (GstMediaSourceSampleMap * self,
GMutex * lock, guint32 * master_cookie);
GST_MSE_PRIVATE
GstIterator *
gst_media_source_sample_map_iter_samples_by_pts (GstMediaSourceSampleMap * map,
GMutex * lock, guint32 * master_cookie, GstClockTime start_pts,
GstSample *start_sample);
gst_media_source_sample_map_iter_samples_by_pts (GstMediaSourceSampleMap * self,
GMutex * lock, guint32 * master_cookie);
GST_MSE_PRIVATE
GType gst_media_source_coded_frame_group_get_type (void);
GST_MSE_PRIVATE
GstMediaSourceCodedFrameGroup *
gst_media_source_coded_frame_group_copy (GstMediaSourceCodedFrameGroup * group);
GST_MSE_PRIVATE
void
gst_media_source_coded_frame_group_free (GstMediaSourceCodedFrameGroup * group);
G_END_DECLS

View File

@ -27,6 +27,16 @@
#include "gstmediasourcesamplemap-private.h"
#include "gstmselogging-private.h"
G_DEFINE_BOXED_TYPE (GstMediaSourceCodedFrameGroup,
gst_media_source_coded_frame_group,
gst_media_source_coded_frame_group_copy,
gst_media_source_coded_frame_group_free);
#define TIME_RANGE_FORMAT \
"[%" GST_TIMEP_FORMAT "..%" GST_TIMEP_FORMAT ")"
#define TIME_RANGE_ARGS(a, b) &(a), &(b)
#define CODED_FRAME_GROUP_ARGS(g) TIME_RANGE_ARGS ((g)->start, (g)->end)
struct _GstMediaSourceSampleMap
{
GstObject parent_instance;
@ -41,12 +51,16 @@ struct _GstMediaSourceSampleMap
G_DEFINE_TYPE (GstMediaSourceSampleMap, gst_media_source_sample_map,
GST_TYPE_OBJECT);
static GstMediaSourceCodedFrameGroup *new_coded_frame_group_from_memory (const
GstMediaSourceCodedFrameGroup * src);
static gint compare_pts (GstSample * a, GstSample * b, gpointer user_data);
static GSequenceIter *find_sample_containing_dts (GstMediaSourceSampleMap *
self, GstClockTime dts);
static GSequenceIter *find_sample_containing_pts (GstMediaSourceSampleMap *
self, GstClockTime pts);
static GSequenceIter *find_sequentially (GSequence * sequence, gpointer item);
static GSequenceIter *next_coded_frame_group (GSequenceIter * it, GValue * val);
static inline GstClockTime
sample_duration (GstSample * sample)
{
return GST_BUFFER_DURATION (gst_sample_get_buffer (sample));
}
static inline GstClockTime
sample_dts (GstSample * sample)
@ -54,6 +68,12 @@ sample_dts (GstSample * sample)
return GST_BUFFER_DTS (gst_sample_get_buffer (sample));
}
static inline GstClockTime
sample_dts_end (GstSample * sample)
{
return sample_dts (sample) + sample_duration (sample);
}
static inline GstClockTime
sample_pts (GstSample * sample)
{
@ -66,15 +86,11 @@ sample_buffer_size (GstSample * sample)
return gst_buffer_get_size (gst_sample_get_buffer (sample));
}
static gboolean
iter_is_delta_unit (GSequenceIter * iter)
static inline gboolean
sample_is_key_unit (GstSample * sample)
{
if (g_sequence_iter_is_end (iter)) {
return TRUE;
}
GstSample *sample = g_sequence_get (iter);
GstBuffer *buffer = gst_sample_get_buffer (sample);
return GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
return !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
}
static gint
@ -198,6 +214,115 @@ gst_media_source_sample_map_contains (GstMediaSourceSampleMap * self,
return g_hash_table_contains (self->samples, sample);
}
static GSequenceIter *
next_key_unit (GSequenceIter * it)
{
for (; !g_sequence_iter_is_end (it); it = g_sequence_iter_next (it)) {
GstSample *sample = g_sequence_get (it);
if (sample_is_key_unit (sample)) {
break;
}
}
return it;
}
static GSequenceIter *
next_coded_frame_group (GSequenceIter * it, GValue * val)
{
it = next_key_unit (it);
if (g_sequence_iter_is_end (it)) {
return it;
}
GstSample *head = g_sequence_get (it);
g_return_val_if_fail (sample_is_key_unit (head), NULL);
GstMediaSourceCodedFrameGroup group = {
.start = sample_dts (head),
.end = sample_dts_end (head),
.samples = g_list_prepend (NULL, gst_sample_ref (head)),
.size = 1,
};
it = g_sequence_iter_next (it);
for (; !g_sequence_iter_is_end (it); it = g_sequence_iter_next (it)) {
GstSample *sample = g_sequence_get (it);
if (sample_is_key_unit (sample)) {
goto done;
}
group.end = sample_dts_end (sample), group.size++;
group.samples = g_list_prepend (group.samples, gst_sample_ref (sample));
}
done:
group.samples = g_list_reverse (group.samples);
GstMediaSourceCodedFrameGroup *box =
new_coded_frame_group_from_memory (&group);
gst_value_take_media_source_coded_frame_group (val, box);
return it;
}
static GSequenceIter *
find_start_point (GstMediaSourceSampleMap * self, GSequenceIter * it,
GList ** to_remove, GstClockTime earliest, GstClockTime latest)
{
while (TRUE) {
GValue value = G_VALUE_INIT;
g_value_init (&value, GST_TYPE_MEDIA_SOURCE_CODED_FRAME_GROUP);
it = next_coded_frame_group (it, &value);
GstMediaSourceCodedFrameGroup *group =
gst_value_get_media_source_coded_frame_group (&value);
if (group == NULL) {
GST_TRACE_OBJECT (self,
"reached end of coded frames before finding start point");
goto done;
}
if (group->start >= earliest && group->end <= latest) {
GST_TRACE_OBJECT (self, "found start point for %" GST_TIMEP_FORMAT ": "
TIME_RANGE_FORMAT, &earliest, CODED_FRAME_GROUP_ARGS (group));
*to_remove = g_list_prepend (*to_remove,
gst_media_source_coded_frame_group_copy (group));
goto done;
}
g_value_unset (&value);
continue;
done:
g_value_unset (&value);
return it;
}
return it;
}
static GSequenceIter *
find_end_point (GstMediaSourceSampleMap * self, GSequenceIter * it, GList **
to_remove, GstClockTime latest)
{
while (TRUE) {
GValue value = G_VALUE_INIT;
g_value_init (&value, GST_TYPE_MEDIA_SOURCE_CODED_FRAME_GROUP);
it = next_coded_frame_group (it, &value);
GstMediaSourceCodedFrameGroup *group =
gst_value_get_media_source_coded_frame_group (&value);
if (group == NULL) {
GST_TRACE_OBJECT (self,
"reached end of coded frames before finding end point");
goto done;
}
if (group->end >= latest) {
GST_TRACE_OBJECT (self, "found end point for %" GST_TIMEP_FORMAT ": "
TIME_RANGE_FORMAT, &latest, CODED_FRAME_GROUP_ARGS (group));
goto done;
}
*to_remove = g_list_prepend (*to_remove,
gst_media_source_coded_frame_group_copy (group));
g_value_unset (&value);
continue;
done:
g_value_unset (&value);
return it;
}
return it;
}
gsize
gst_media_source_sample_map_remove_range (GstMediaSourceSampleMap * self,
GstClockTime earliest, GstClockTime latest)
@ -205,54 +330,43 @@ gst_media_source_sample_map_remove_range (GstMediaSourceSampleMap * self,
g_return_val_if_fail (GST_IS_MEDIA_SOURCE_SAMPLE_MAP (self), 0);
g_return_val_if_fail (earliest <= latest, 0);
GSequenceIter *start_by_dts = find_sample_containing_dts (self, earliest);
GSequenceIter *end_by_dts = find_sample_containing_dts (self, latest);
GST_TRACE_OBJECT (self, "request remove range " TIME_RANGE_FORMAT,
TIME_RANGE_ARGS (earliest, latest));
GstSample *start = g_sequence_get (start_by_dts);
GstSample *end = g_sequence_get (end_by_dts);
GstClockTime start_time =
start == NULL ? GST_CLOCK_TIME_NONE : sample_dts (start);
GstClockTime end_time = end == NULL ? start_time : sample_dts (end);
GST_TRACE_OBJECT (self, "remove range [%" GST_TIMEP_FORMAT ",%"
GST_TIMEP_FORMAT ")", &start_time, &end_time);
GSequenceIter *it = g_sequence_get_begin_iter (self->samples_by_dts);
GList *to_remove = NULL;
while (g_sequence_iter_compare (start_by_dts, end_by_dts) < 1) {
GstSample *sample = g_sequence_get (start_by_dts);
to_remove = g_list_prepend (to_remove, sample);
start_by_dts = g_sequence_iter_next (start_by_dts);
}
gsize bytes_removed = 0;
for (GList * iter = to_remove; iter != NULL; iter = g_list_next (iter)) {
GstSample *sample = iter->data;
bytes_removed += sample_buffer_size (sample);
gst_media_source_sample_map_remove (self, sample);
it = find_start_point (self, it, &to_remove, earliest, latest);
if (to_remove == NULL) {
return 0;
}
g_list_free (to_remove);
it = find_end_point (self, it, &to_remove, latest);
to_remove = g_list_reverse (to_remove);
gsize bytes_removed = 0;
for (GList * group_iter = to_remove; group_iter != NULL;
group_iter = g_list_next (group_iter)) {
GstMediaSourceCodedFrameGroup *group = group_iter->data;
for (GList * sample_iter = group->samples; sample_iter != NULL;
sample_iter = g_list_next (sample_iter)) {
GstSample *sample = sample_iter->data;
bytes_removed += sample_buffer_size (sample);
gst_media_source_sample_map_remove (self, sample);
}
}
g_list_free_full (to_remove,
(GDestroyNotify) gst_media_source_coded_frame_group_free);
GST_TRACE_OBJECT (self, "removed=%" G_GSIZE_FORMAT "B, latest=%"
GST_TIMEP_FORMAT, bytes_removed, &latest);
return bytes_removed;
}
gsize
gst_media_source_sample_map_remove_range_from_start (GstMediaSourceSampleMap
* self, GstClockTime latest_dts)
{
return gst_media_source_sample_map_remove_range (self, 0, latest_dts);
}
gsize
gst_media_source_sample_map_remove_range_from_end (GstMediaSourceSampleMap
* self, GstClockTime earliest_dts)
{
return gst_media_source_sample_map_remove_range (self, earliest_dts,
GST_CLOCK_TIME_NONE);
}
GstClockTime
gst_media_source_sample_map_get_highest_end_time (GstMediaSourceSampleMap *
self)
@ -286,178 +400,40 @@ gst_media_source_sample_map_get_storage_size (GstMediaSourceSampleMap * self)
return self->storage_size;
}
static inline gboolean
sample_contains_dts (GstSample * sample, GstClockTime dts)
{
GstBuffer *buffer = gst_sample_get_buffer (sample);
g_return_val_if_fail (GST_BUFFER_DURATION_IS_VALID (buffer), FALSE);
g_return_val_if_fail (GST_BUFFER_DTS_IS_VALID (buffer), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (dts), FALSE);
GstClockTime end = GST_BUFFER_DTS (buffer) + GST_BUFFER_DURATION (buffer);
return dts <= end;
}
static inline gboolean
sample_contains_pts (GstSample * sample, GstClockTime pts)
{
GstBuffer *buffer = gst_sample_get_buffer (sample);
g_return_val_if_fail (GST_BUFFER_DURATION_IS_VALID (buffer), FALSE);
g_return_val_if_fail (GST_BUFFER_PTS_IS_VALID (buffer), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (pts), FALSE);
GstClockTime end = GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer);
return pts <= end;
}
static GSequenceIter *
find_sequentially (GSequence * sequence, gpointer item)
{
GSequenceIter *iter = g_sequence_get_begin_iter (sequence);
for (; !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter)) {
gpointer current = g_sequence_get (iter);
if (current == item) {
return iter;
}
}
return iter;
}
static GSequenceIter *
find_sample_containing_dts (GstMediaSourceSampleMap * self, GstClockTime dts)
{
if (dts == 0) {
return g_sequence_get_begin_iter (self->samples_by_dts);
}
if (dts == GST_CLOCK_TIME_NONE) {
return g_sequence_get_end_iter (self->samples_by_dts);
}
GSequenceIter *iter = g_sequence_get_begin_iter (self->samples_by_dts);
while (!g_sequence_iter_is_end (iter)) {
GstSample *sample = g_sequence_get (iter);
if (sample_contains_dts (sample, dts)) {
return iter;
}
iter = g_sequence_iter_next (iter);
}
return iter;
}
static GSequenceIter *
find_sample_containing_pts (GstMediaSourceSampleMap * self, GstClockTime pts)
{
if (pts == 0) {
return g_sequence_get_begin_iter (self->samples_by_pts);
}
if (pts == GST_CLOCK_TIME_NONE) {
return g_sequence_get_end_iter (self->samples_by_pts);
}
GSequenceIter *iter = g_sequence_get_begin_iter (self->samples_by_pts);
while (!g_sequence_iter_is_end (iter)) {
GstSample *sample = g_sequence_get (iter);
if (sample_contains_pts (sample, pts)) {
return iter;
}
iter = g_sequence_iter_next (iter);
}
return iter;
}
static GSequenceIter *
find_previous_non_delta_unit (GstMediaSourceSampleMap * self,
GSequenceIter * iter)
{
while (!g_sequence_iter_is_begin (iter)) {
if (!iter_is_delta_unit (iter)) {
GST_TRACE_OBJECT (self, "found valid sample");
return iter;
}
iter = g_sequence_iter_prev (iter);
}
GST_TRACE_OBJECT (self, "rolled back to the first sample");
return iter;
}
static GSequenceIter *
gst_media_source_sample_map_iter_starting_dts (GstMediaSourceSampleMap * self,
GstClockTime start_dts)
{
g_return_val_if_fail (GST_IS_MEDIA_SOURCE_SAMPLE_MAP (self), NULL);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start_dts), NULL);
GSequenceIter *iter = find_sample_containing_dts (self, start_dts);
return find_previous_non_delta_unit (self, iter);
}
static GSequenceIter *
gst_media_source_sample_map_iter_starting_pts (GstMediaSourceSampleMap
* self, GstClockTime start_pts)
{
g_return_val_if_fail (GST_IS_MEDIA_SOURCE_SAMPLE_MAP (self), NULL);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start_pts), NULL);
GSequenceIter *iter = find_sample_containing_pts (self, start_pts);
return find_previous_non_delta_unit (self, iter);
}
typedef struct _SampleMapIterator SampleMapIterator;
struct _SampleMapIterator
{
GstIterator iterator;
GstMediaSourceSampleMap *map;
/* *INDENT-OFF* */
GstClockTime (*timestamp_func) (GstSample *);
GSequenceIter *(*resync_locator_func) (SampleMapIterator *);
/* *INDENT-ON* */
GSequenceIter *(*reset_func) (SampleMapIterator *);
GstClockTime start_time;
GstClockTime current_time;
GSequenceIter *current_iter;
GstSample *current_sample;
};
static void
iter_copy (const SampleMapIterator * it, SampleMapIterator * copy)
{
copy->map = gst_object_ref (it->map);
copy->timestamp_func = it->timestamp_func;
copy->resync_locator_func = it->resync_locator_func;
copy->reset_func = it->reset_func;
copy->current_time = it->current_time;
copy->start_time = it->start_time;
copy->current_iter = it->current_iter;
copy->current_sample = gst_sample_ref (it->current_sample);
}
static GSequenceIter *
iter_find_resync_point_dts (SampleMapIterator * it)
iter_reset_by_dts (SampleMapIterator * it)
{
if (it->current_sample) {
GSequenceIter *iter =
find_sequentially (it->map->samples_by_dts, it->current_sample);
if (!g_sequence_iter_is_end (iter)) {
return g_sequence_iter_next (iter);
}
}
return gst_media_source_sample_map_iter_starting_dts (it->map,
it->current_time);
return g_sequence_get_begin_iter (it->map->samples_by_dts);
}
static GSequenceIter *
iter_find_resync_point_pts (SampleMapIterator * it)
iter_reset_by_pts (SampleMapIterator * it)
{
if (it->current_sample) {
GSequenceIter *iter =
find_sequentially (it->map->samples_by_pts, it->current_sample);
if (!g_sequence_iter_is_end (iter)) {
return g_sequence_iter_next (iter);
}
}
return gst_media_source_sample_map_iter_starting_pts (it->map,
it->current_time);
return g_sequence_get_begin_iter (it->map->samples_by_pts);
}
static GstIteratorResult
iter_next (SampleMapIterator * it, GValue * result)
iter_next_sample (SampleMapIterator * it, GValue * result)
{
if (g_sequence_iter_is_end (it->current_iter)) {
@ -465,10 +441,7 @@ iter_next (SampleMapIterator * it, GValue * result)
}
GstSample *sample = g_sequence_get (it->current_iter);
gst_clear_sample (&it->current_sample);
it->current_sample = gst_sample_ref (sample);
it->current_time = it->timestamp_func (sample);
it->current_iter = g_sequence_iter_next (it->current_iter);
gst_value_set_sample (result, sample);
@ -476,25 +449,59 @@ iter_next (SampleMapIterator * it, GValue * result)
return GST_ITERATOR_OK;
}
static GstIteratorResult
iter_next_group (SampleMapIterator * it, GValue * result)
{
if (g_sequence_iter_is_end (it->current_iter)) {
return GST_ITERATOR_DONE;
}
it->current_iter = next_coded_frame_group (it->current_iter, result);
return GST_ITERATOR_OK;
}
static void
iter_resync (SampleMapIterator * it)
{
GST_TRACE_OBJECT (it->map, "resync");
it->current_time = it->start_time;
it->current_iter = it->resync_locator_func (it);
it->current_iter = it->reset_func (it);
}
static void
iter_free (SampleMapIterator * it)
{
gst_clear_object (&it->map);
gst_clear_sample (&it->current_sample);
}
GstIterator *
gst_media_source_sample_map_iter_samples_by_dts (GstMediaSourceSampleMap * map,
GMutex * lock, guint32 * master_cookie, GstClockTime start_dts,
GstSample * start_sample)
gst_media_source_sample_map_iter_samples_by_dts (GstMediaSourceSampleMap * self,
GMutex * lock, guint32 * master_cookie)
{
/* *INDENT-OFF* */
SampleMapIterator *it = (SampleMapIterator *) gst_iterator_new (
sizeof (SampleMapIterator),
GST_TYPE_MEDIA_SOURCE_CODED_FRAME_GROUP,
lock,
master_cookie,
(GstIteratorCopyFunction) iter_copy,
(GstIteratorNextFunction) iter_next_group,
(GstIteratorItemFunction) NULL,
(GstIteratorResyncFunction) iter_resync,
(GstIteratorFreeFunction) iter_free
);
/* *INDENT-ON* */
it->map = gst_object_ref (self);
it->reset_func = iter_reset_by_dts;
it->current_iter = iter_reset_by_dts (it);
return GST_ITERATOR (it);
}
GstIterator *
gst_media_source_sample_map_iter_samples_by_pts (GstMediaSourceSampleMap * self,
GMutex * lock, guint32 * master_cookie)
{
/* *INDENT-OFF* */
SampleMapIterator *it = (SampleMapIterator *) gst_iterator_new (
@ -503,50 +510,43 @@ gst_media_source_sample_map_iter_samples_by_dts (GstMediaSourceSampleMap * map,
lock,
master_cookie,
(GstIteratorCopyFunction) iter_copy,
(GstIteratorNextFunction) iter_next,
(GstIteratorNextFunction) iter_next_sample,
(GstIteratorItemFunction) NULL,
(GstIteratorResyncFunction) iter_resync,
(GstIteratorFreeFunction) iter_free
);
/* *INDENT-ON* */
it->map = gst_object_ref (map);
it->timestamp_func = sample_dts;
it->resync_locator_func = iter_find_resync_point_dts;
it->start_time = start_dts;
it->current_time = start_dts;
it->current_sample = start_sample ? gst_sample_ref (start_sample) : NULL;
it->current_iter = iter_find_resync_point_dts (it);
it->map = gst_object_ref (self);
it->reset_func = iter_reset_by_pts;
it->current_iter = iter_reset_by_pts (it);
return GST_ITERATOR (it);
}
GstIterator *
gst_media_source_sample_map_iter_samples_by_pts (GstMediaSourceSampleMap * map,
GMutex * lock, guint32 * master_cookie, GstClockTime start_pts,
GstSample * start_sample)
static GstMediaSourceCodedFrameGroup *
new_coded_frame_group_from_memory (const GstMediaSourceCodedFrameGroup * src)
{
/* *INDENT-OFF* */
SampleMapIterator *it = (SampleMapIterator *) gst_iterator_new (
sizeof (SampleMapIterator),
GST_TYPE_SAMPLE,
lock,
master_cookie,
(GstIteratorCopyFunction) iter_copy,
(GstIteratorNextFunction) iter_next,
(GstIteratorItemFunction) NULL,
(GstIteratorResyncFunction) iter_resync,
(GstIteratorFreeFunction) iter_free
);
/* *INDENT-ON* */
it->map = gst_object_ref (map);
it->timestamp_func = sample_pts;
it->resync_locator_func = iter_find_resync_point_pts;
it->start_time = start_pts;
it->current_time = start_pts;
it->current_sample = start_sample ? gst_sample_ref (start_sample) : NULL;
it->current_iter = iter_find_resync_point_pts (it);
return GST_ITERATOR (it);
GstMediaSourceCodedFrameGroup *box =
g_atomic_rc_box_new0 (GstMediaSourceCodedFrameGroup);
memcpy (box, src, sizeof (GstMediaSourceCodedFrameGroup));
return box;
}
GstMediaSourceCodedFrameGroup *
gst_media_source_coded_frame_group_copy (GstMediaSourceCodedFrameGroup * self)
{
return g_atomic_rc_box_acquire (self);
}
static void
free_group_inner (GstMediaSourceCodedFrameGroup * self)
{
g_list_free_full (self->samples, (GDestroyNotify) gst_sample_unref);
}
void
gst_media_source_coded_frame_group_free (GstMediaSourceCodedFrameGroup * self)
{
g_atomic_rc_box_release_full (self, (GDestroyNotify) free_group_inner);
}

View File

@ -65,6 +65,13 @@ opened_media_source (void)
return media_source;
}
static GstClockTime
sample_dts (GstSample * sample)
{
GstBuffer *buffer = gst_sample_get_buffer (sample);
return GST_BUFFER_DTS (buffer);
}
static GstSample *
new_empty_sample_full (GstClockTime dts, GstClockTime pts,
GstClockTime duration, GstBufferFlags flags, GstCaps * caps,
@ -80,6 +87,13 @@ new_empty_sample_full (GstClockTime dts, GstClockTime pts,
return sample;
}
static GstSample *
new_empty_sample_with_timing_and_flags (GstClockTime dts, GstClockTime pts,
GstClockTime duration, GstBufferFlags flags)
{
return new_empty_sample_full (dts, pts, duration, flags, NULL, NULL, NULL);
}
static GstSample *
new_empty_sample_with_timing (GstClockTime dts, GstClockTime pts,
GstClockTime duration)
@ -933,6 +947,10 @@ GST_START_TEST (test_sample_map_remove_range_from_start)
for (guint i = 0; i < G_N_ELEMENTS (samples_to_remove); i++) {
GstClockTime time = i;
GstSample *sample = new_empty_sample_with_timing (time, time, 1);
if (i > 0) {
GstBuffer *head = gst_sample_get_buffer (sample);
GST_BUFFER_FLAGS (head) = GST_BUFFER_FLAG_DELTA_UNIT;
}
gst_media_source_sample_map_add (map, sample);
samples_to_remove[i] = sample;
}
@ -940,11 +958,15 @@ GST_START_TEST (test_sample_map_remove_range_from_start)
for (guint i = 0; i < G_N_ELEMENTS (samples_to_preserve); i++) {
GstClockTime time = i + G_N_ELEMENTS (samples_to_remove);
GstSample *sample = new_empty_sample_with_timing (time, time, 0);
if (i > 0) {
GstBuffer *head = gst_sample_get_buffer (sample);
GST_BUFFER_FLAGS (head) = GST_BUFFER_FLAG_DELTA_UNIT;
}
gst_media_source_sample_map_add (map, sample);
samples_to_preserve[i] = sample;
}
gst_media_source_sample_map_remove_range_from_start (map, 100);
gst_media_source_sample_map_remove_range (map, 0, 100);
for (guint i = 0; i < G_N_ELEMENTS (samples_to_remove); i++) {
GstSample *sample = samples_to_remove[i];
@ -975,20 +997,27 @@ GST_START_TEST (test_sample_map_remove_range_from_start_byte_count)
GBytes *bytes = g_bytes_new_static (chunk, buffer_size);
total_bytes_to_remove += buffer_size;
GstSample *sample = new_sample_with_bytes_and_timing (bytes, time, time, 1);
if (i > 0) {
GstBuffer *head = gst_sample_get_buffer (sample);
GST_BUFFER_FLAGS (head) = GST_BUFFER_FLAG_DELTA_UNIT;
}
gst_media_source_sample_map_add (map, sample);
samples_to_remove[i] = sample;
}
GstSample *samples_to_preserve[100] = { NULL };
for (guint i = 0; i < G_N_ELEMENTS (samples_to_preserve); i++) {
for (guint i = 0; i < G_N_ELEMENTS (samples_to_remove); i++) {
GstClockTime time = i + G_N_ELEMENTS (samples_to_remove);
GBytes *bytes = g_bytes_new_static (chunk, 1);
GstSample *sample = new_sample_with_bytes_and_timing (bytes, time, time, 0);
if (i > 0) {
GstBuffer *head = gst_sample_get_buffer (sample);
GST_BUFFER_FLAGS (head) = GST_BUFFER_FLAG_DELTA_UNIT;
}
gst_media_source_sample_map_add (map, sample);
samples_to_preserve[i] = sample;
}
gsize bytes_removed =
gst_media_source_sample_map_remove_range_from_start (map,
gsize bytes_removed = gst_media_source_sample_map_remove_range (map, 0,
G_N_ELEMENTS (samples_to_remove));
fail_unless_equals_uint64 (bytes_removed, total_bytes_to_remove);
@ -1004,6 +1033,119 @@ GST_START_TEST (test_sample_map_remove_range_from_start_byte_count)
GST_END_TEST;
GST_START_TEST (test_sample_map_remove_range_removes_coded_frame_group)
{
GstMediaSourceSampleMap *map = gst_media_source_sample_map_new ();
static const GstClockTime duration = 1;
GstSample *keyframe0 = new_empty_sample_with_timing_and_flags (0, 0,
duration, 0);
GstSample *delta0 = new_empty_sample_with_timing_and_flags (1, 1,
duration, GST_BUFFER_FLAG_DELTA_UNIT);
GstSample *keyframe1 = new_empty_sample_with_timing_and_flags (2, 2,
duration, 0);
GstSample *delta1 = new_empty_sample_with_timing_and_flags (3, 3,
duration, GST_BUFFER_FLAG_DELTA_UNIT);
GstSample *timeline[] = { keyframe0, delta0, keyframe1, delta1, NULL };
gst_media_source_sample_map_add (map, keyframe0);
gst_media_source_sample_map_add (map, delta0);
gst_media_source_sample_map_add (map, keyframe1);
gst_media_source_sample_map_add (map, delta1);
GstClockTime start = __i__ * 2;
GstClockTime end = start + duration * 2;
gst_media_source_sample_map_remove_range (map, start, end);
for (GstSample ** it = timeline; *it != NULL; it++) {
GstSample *sample = *it;
GstClockTime sample_start = sample_dts (sample);
GstClockTime sample_end = sample_start + duration;
if (sample_start >= start && sample_end <= end) {
fail_if (gst_media_source_sample_map_contains (map, sample));
} else {
fail_unless (gst_media_source_sample_map_contains (map, sample));
}
}
gst_object_unref (map);
gst_sample_unref (keyframe0);
gst_sample_unref (delta0);
gst_sample_unref (keyframe1);
gst_sample_unref (delta1);
}
GST_END_TEST;
static void
sample_map_iterate_size (const GValue * item, gpointer user_data)
{
guint *counter = (guint *) user_data;
*counter = *counter + 1;
}
GST_START_TEST (test_sample_map_empty_iterator_by_dts)
{
GstMediaSourceSampleMap *map = gst_media_source_sample_map_new ();
guint counter = 0;
GMutex mutex = { 0 };
guint32 cookie = 0;
GstIterator *it = gst_media_source_sample_map_iter_samples_by_dts (map,
&mutex, &cookie);
gst_iterator_foreach (it, sample_map_iterate_size, &counter);
gst_iterator_free (it);
assert_equals_int (counter, 0);
gst_object_unref (map);
}
GST_END_TEST;
GST_START_TEST (test_sample_map_grouped_iterator_by_dts)
{
GstMediaSourceSampleMap *map = gst_media_source_sample_map_new ();
guint counter = 0;
GMutex mutex = { 0 };
guint32 cookie = 0;
GstSample *key = new_empty_sample_full (0,
0,
GST_SECOND,
0,
NULL,
NULL,
NULL);
GstSample *delta = new_empty_sample_full (GST_SECOND,
GST_SECOND,
GST_SECOND,
GST_BUFFER_FLAG_DELTA_UNIT,
NULL,
NULL,
NULL);
gst_media_source_sample_map_add (map, key);
gst_media_source_sample_map_add (map, delta);
GstIterator *it = gst_media_source_sample_map_iter_samples_by_dts (map,
&mutex, &cookie);
gst_iterator_foreach (it, sample_map_iterate_size, &counter);
gst_iterator_free (it);
assert_equals_int (counter, 1);
gst_object_unref (map);
gst_clear_sample (&key);
gst_clear_sample (&delta);
}
GST_END_TEST;
#define DEFAULT_TCASE_TIMEOUT 15
#ifdef HAVE_VALGRIND
@ -1102,8 +1244,12 @@ mse_suite (void)
tcase_add_test (tc_sample_map, test_sample_map_add_invalid_sample);
tcase_add_test (tc_sample_map, test_sample_map_remove_sample);
tcase_add_test (tc_sample_map, test_sample_map_remove_range_from_start);
tcase_add_loop_test (tc_sample_map,
test_sample_map_remove_range_removes_coded_frame_group, 0, 2);
tcase_add_test (tc_sample_map,
test_sample_map_remove_range_from_start_byte_count);
tcase_add_test (tc_sample_map, test_sample_map_empty_iterator_by_dts);
tcase_add_test (tc_sample_map, test_sample_map_grouped_iterator_by_dts);
suite_add_tcase (s, tc_media_source);
suite_add_tcase (s, tc_source_buffer);