mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-27 18:50:48 +00:00
multifilesink: Add a new max-duration file switching mode
This new mode ensures that files will never exceed a certain duration based on incoming buffer PTS (and duration if present) Note: * You need timestamped buffers (duh). If some of the incoming buffers don't have PTS, then it will just accept them in the current file
This commit is contained in:
parent
f1ceaab02f
commit
27c91bc881
2 changed files with 83 additions and 1 deletions
|
@ -136,6 +136,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_multi_file_sink_debug);
|
|||
#define DEFAULT_NEXT_FILE GST_MULTI_FILE_SINK_NEXT_BUFFER
|
||||
#define DEFAULT_MAX_FILES 0
|
||||
#define DEFAULT_MAX_FILE_SIZE G_GUINT64_CONSTANT(2*1024*1024*1024)
|
||||
#define DEFAULT_MAX_FILE_DURATION GST_CLOCK_TIME_NONE
|
||||
#define DEFAULT_AGGREGATE_GOPS FALSE
|
||||
|
||||
enum
|
||||
|
@ -147,6 +148,7 @@ enum
|
|||
PROP_NEXT_FILE,
|
||||
PROP_MAX_FILES,
|
||||
PROP_MAX_FILE_SIZE,
|
||||
PROP_MAX_FILE_DURATION,
|
||||
PROP_AGGREGATE_GOPS
|
||||
};
|
||||
|
||||
|
@ -190,6 +192,10 @@ gst_multi_file_sink_next_get_type (void)
|
|||
{GST_MULTI_FILE_SINK_NEXT_MAX_SIZE, "New file when the configured maximum "
|
||||
"file size would be exceeded with the next buffer or buffer list",
|
||||
"max-size"},
|
||||
{GST_MULTI_FILE_SINK_NEXT_MAX_DURATION,
|
||||
"New file when the configured maximum "
|
||||
"file duration would be exceeded with the next buffer or buffer list",
|
||||
"max-duration"},
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -270,6 +276,17 @@ gst_multi_file_sink_class_init (GstMultiFileSinkClass * klass)
|
|||
0, G_MAXUINT64, DEFAULT_MAX_FILE_SIZE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstMultiFileSink:max-file-duration:
|
||||
*
|
||||
* Maximum file size before starting a new file in max-size mode.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_MAX_FILE_DURATION,
|
||||
g_param_spec_uint64 ("max-file-duration", "Maximum File Duration",
|
||||
"Maximum file duration before starting a new file in max-size mode",
|
||||
0, G_MAXUINT64, DEFAULT_MAX_FILE_DURATION,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstMultiFileSink:aggregate-gops:
|
||||
*
|
||||
|
@ -317,6 +334,7 @@ gst_multi_file_sink_init (GstMultiFileSink * multifilesink)
|
|||
multifilesink->post_messages = DEFAULT_POST_MESSAGES;
|
||||
multifilesink->max_files = DEFAULT_MAX_FILES;
|
||||
multifilesink->max_file_size = DEFAULT_MAX_FILE_SIZE;
|
||||
multifilesink->max_file_duration = DEFAULT_MAX_FILE_DURATION;
|
||||
multifilesink->files = NULL;
|
||||
multifilesink->n_files = 0;
|
||||
|
||||
|
@ -377,6 +395,9 @@ gst_multi_file_sink_set_property (GObject * object, guint prop_id,
|
|||
case PROP_MAX_FILE_SIZE:
|
||||
sink->max_file_size = g_value_get_uint64 (value);
|
||||
break;
|
||||
case PROP_MAX_FILE_DURATION:
|
||||
sink->max_file_duration = g_value_get_uint64 (value);
|
||||
break;
|
||||
case PROP_AGGREGATE_GOPS:
|
||||
sink->aggregate_gops = g_value_get_boolean (value);
|
||||
break;
|
||||
|
@ -411,6 +432,9 @@ gst_multi_file_sink_get_property (GObject * object, guint prop_id,
|
|||
case PROP_MAX_FILE_SIZE:
|
||||
g_value_set_uint64 (value, sink->max_file_size);
|
||||
break;
|
||||
case PROP_MAX_FILE_DURATION:
|
||||
g_value_set_uint64 (value, sink->max_file_duration);
|
||||
break;
|
||||
case PROP_AGGREGATE_GOPS:
|
||||
g_value_set_boolean (value, sink->aggregate_gops);
|
||||
break;
|
||||
|
@ -428,6 +452,7 @@ gst_multi_file_sink_start (GstBaseSink * bsink)
|
|||
if (sink->aggregate_gops)
|
||||
sink->gop_adapter = gst_adapter_new ();
|
||||
sink->potential_next_gop = NULL;
|
||||
sink->file_pts = GST_CLOCK_TIME_NONE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -704,6 +729,46 @@ gst_multi_file_sink_write_buffer (GstMultiFileSink * multifilesink,
|
|||
multifilesink->cur_file_size += map.size;
|
||||
break;
|
||||
}
|
||||
case GST_MULTI_FILE_SINK_NEXT_MAX_DURATION:{
|
||||
GstClockTime new_duration = 0;
|
||||
|
||||
if (GST_BUFFER_PTS_IS_VALID (buffer)
|
||||
&& GST_CLOCK_TIME_IS_VALID (multifilesink->file_pts)) {
|
||||
/* The new duration will extend to this new buffer pts ... */
|
||||
new_duration = GST_BUFFER_PTS (buffer) - multifilesink->file_pts;
|
||||
/* ... and duration (if it has one) */
|
||||
if (GST_BUFFER_DURATION_IS_VALID (buffer))
|
||||
new_duration += GST_BUFFER_DURATION (buffer);
|
||||
}
|
||||
|
||||
if (new_duration > multifilesink->max_file_duration) {
|
||||
|
||||
GST_INFO_OBJECT (multifilesink,
|
||||
"new_duration: %" G_GUINT64_FORMAT ", max. duration %"
|
||||
G_GUINT64_FORMAT, new_duration, multifilesink->max_file_duration);
|
||||
|
||||
if (multifilesink->file != NULL) {
|
||||
first_file = FALSE;
|
||||
gst_multi_file_sink_close_file (multifilesink, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (multifilesink->file == NULL) {
|
||||
if (!gst_multi_file_sink_open_next_file (multifilesink))
|
||||
goto stdio_write_error;
|
||||
|
||||
multifilesink->file_pts = GST_BUFFER_PTS (buffer);
|
||||
if (!first_file)
|
||||
gst_multi_file_sink_write_stream_headers (multifilesink);
|
||||
}
|
||||
|
||||
ret = fwrite (map.data, map.size, 1, multifilesink->file);
|
||||
|
||||
if (ret != 1)
|
||||
goto stdio_write_error;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
@ -753,8 +818,13 @@ gst_multi_file_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
|
|||
g_list_append (sink->potential_next_gop, gst_buffer_ref (buffer));
|
||||
} else {
|
||||
if (key_unit && avail > 0) {
|
||||
GstClockTime pts, dts;
|
||||
GST_LOG_OBJECT (sink, "Grabbing pending completed GOP");
|
||||
pts = gst_adapter_prev_pts_at_offset (sink->gop_adapter, 0, NULL);
|
||||
dts = gst_adapter_prev_dts_at_offset (sink->gop_adapter, 0, NULL);
|
||||
gop_buffer = gst_adapter_take_buffer (sink->gop_adapter, avail);
|
||||
GST_BUFFER_PTS (gop_buffer) = pts;
|
||||
GST_BUFFER_DTS (gop_buffer) = dts;
|
||||
}
|
||||
|
||||
/* just accumulate the buffer */
|
||||
|
@ -775,6 +845,12 @@ gst_multi_file_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
|
|||
|
||||
if (gop_buffer != NULL) {
|
||||
GST_DEBUG_OBJECT (sink, "writing out pending GOP, %u bytes", avail);
|
||||
GST_DEBUG_OBJECT (sink,
|
||||
"gop buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
|
||||
" duration:%" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GST_BUFFER_PTS (gop_buffer)),
|
||||
GST_TIME_ARGS (GST_BUFFER_DTS (gop_buffer)),
|
||||
GST_TIME_ARGS (GST_BUFFER_DURATION (gop_buffer)));
|
||||
flow = gst_multi_file_sink_write_buffer (sink, gop_buffer);
|
||||
gst_buffer_unref (gop_buffer);
|
||||
}
|
||||
|
|
|
@ -62,6 +62,8 @@ typedef struct _GstMultiFileSinkClass GstMultiFileSinkClass;
|
|||
* event
|
||||
* @GST_MULTI_FILE_SINK_NEXT_MAX_SIZE: New file when the configured maximum file
|
||||
* size would be exceeded with the next buffer or buffer list
|
||||
* @GST_MULTI_FILE_SINK_NEXT_MAX_DURATION: New file when the configured maximum duration
|
||||
* would be exceeded with the next buffer or buffer list
|
||||
*
|
||||
* File splitting modes.
|
||||
*/
|
||||
|
@ -70,7 +72,8 @@ typedef enum {
|
|||
GST_MULTI_FILE_SINK_NEXT_DISCONT,
|
||||
GST_MULTI_FILE_SINK_NEXT_KEY_FRAME,
|
||||
GST_MULTI_FILE_SINK_NEXT_KEY_UNIT_EVENT,
|
||||
GST_MULTI_FILE_SINK_NEXT_MAX_SIZE
|
||||
GST_MULTI_FILE_SINK_NEXT_MAX_SIZE,
|
||||
GST_MULTI_FILE_SINK_NEXT_MAX_DURATION
|
||||
} GstMultiFileSinkNext;
|
||||
|
||||
struct _GstMultiFileSink
|
||||
|
@ -95,6 +98,9 @@ struct _GstMultiFileSink
|
|||
guint64 cur_file_size;
|
||||
guint64 max_file_size;
|
||||
|
||||
GstClockTime file_pts;
|
||||
GstClockTime max_file_duration;
|
||||
|
||||
gboolean aggregate_gops;
|
||||
GstAdapter *gop_adapter; /* to aggregate GOPs */
|
||||
GList *potential_next_gop; /* To detect false-positives */
|
||||
|
|
Loading…
Reference in a new issue