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:
parent
5aa3f7c16e
commit
4f5cda94f7
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user