mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-26 17:18:15 +00:00
splitmux: Implement new elements for splitting files at mux level.
Implement 2 new elements - splitmuxsink and splitmuxsrc. splitmuxsink is a bin which wraps a muxer and takes 1 video stream, plus audio/subtitle streams, and starts a new file whenever necessary to avoid overrunning a threshold of either bytes or time. New files are started at a keyframe, and corresponding audio and subtitle streams are split at packet boundaries to match video GOP timestamps. splitmuxsrc is a corresponding source element which handles the splitmux:// URL and plays back all component files, reconstructing the original elementary streams as it goes.
This commit is contained in:
parent
59431f663a
commit
5e2214d309
23 changed files with 4633 additions and 88 deletions
|
@ -157,6 +157,8 @@ EXTRA_HFILES = \
|
|||
$(top_srcdir)/gst/multifile/gstmultifilesink.h \
|
||||
$(top_srcdir)/gst/multifile/gstmultifilesrc.h \
|
||||
$(top_srcdir)/gst/multifile/gstsplitfilesrc.h \
|
||||
$(top_srcdir)/gst/multifile/gstsplitmuxsrc.h \
|
||||
$(top_srcdir)/gst/multifile/gstsplitmuxsink.h \
|
||||
$(top_srcdir)/gst/multipart/multipartdemux.h \
|
||||
$(top_srcdir)/gst/multipart/multipartmux.h \
|
||||
$(top_srcdir)/gst/isomp4/qtdemux.h \
|
||||
|
|
|
@ -162,6 +162,8 @@
|
|||
<xi:include href="xml/element-speexenc.xml" />
|
||||
<xi:include href="xml/element-speexdec.xml" />
|
||||
<xi:include href="xml/element-splitfilesrc.xml" />
|
||||
<xi:include href="xml/element-splitmuxsrc.xml" />
|
||||
<xi:include href="xml/element-splitmuxsink.xml" />
|
||||
<xi:include href="xml/element-streaktv.xml" />
|
||||
<xi:include href="xml/element-taginject.xml" />
|
||||
<xi:include href="xml/element-udpsrc.xml" />
|
||||
|
|
|
@ -2013,6 +2013,34 @@ GST_TYPE_SPLIT_FILE_SRC
|
|||
gst_split_file_src_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>element-splitmuxsrc</FILE>
|
||||
<TITLE>splitmuxsrc</TITLE>
|
||||
GstSplitMuxSrc
|
||||
<SUBSECTION Standard>
|
||||
GstSplitMuxSrcClass
|
||||
GST_SPLITMUX_SRC
|
||||
GST_SPLITMUX_SRC_CLASS
|
||||
GST_IS_SPLITMUX_SRC
|
||||
GST_IS_SPLITMUX_SRC_CLASS
|
||||
GST_TYPE_SPLITMUX_SRC
|
||||
gst_split_mux_src_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>element-splitmuxsink</FILE>
|
||||
<TITLE>splitmuxsink</TITLE>
|
||||
GstSplitMuxSink
|
||||
<SUBSECTION Standard>
|
||||
GstSplitMuxSinkClass
|
||||
GST_SPLITMUX_SINK
|
||||
GST_SPLITMUX_SINK_CLASS
|
||||
GST_IS_SPLITMUX_SINK
|
||||
GST_IS_SPLITMUX_SINK_CLASS
|
||||
GST_TYPE_SPLITMUX_SINK
|
||||
gst_split_mux_sink_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>element-taginject</FILE>
|
||||
<TITLE>taginject</TITLE>
|
||||
|
|
|
@ -152,6 +152,8 @@ GObject
|
|||
GstRTSPSrc
|
||||
GstRgVolume
|
||||
GstRtpBin
|
||||
GstSplitMuxSink
|
||||
GstSplitMuxSrc
|
||||
GstCutter
|
||||
GstDVDec
|
||||
GstDVDemux
|
||||
|
|
|
@ -71,6 +71,8 @@ GstSoupHTTPSrc GstURIHandler
|
|||
GstSpeexEnc GstPreset GstTagSetter
|
||||
GstSpeexEnc GstTagSetter GstPreset
|
||||
GstSplitFileSrc GstURIHandler
|
||||
GstSplitMuxSink GstChildProxy
|
||||
GstSplitMuxSrc GstChildProxy GstURIHandler
|
||||
GstSwitchSink GstChildProxy
|
||||
GstSwitchSrc GstChildProxy
|
||||
GstTagLibMux GstTagSetter
|
||||
|
|
|
@ -6,14 +6,30 @@ libgstmultifile_la_SOURCES = \
|
|||
gstmultifilesrc.c \
|
||||
gstmultifile.c \
|
||||
gstsplitfilesrc.c \
|
||||
gstsplitmuxsink.c \
|
||||
gstsplitmuxpartreader.c \
|
||||
gstsplitmuxsrc.c \
|
||||
gstsplitutils.c \
|
||||
patternspec.c
|
||||
libgstmultifile_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS)
|
||||
libgstmultifile_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@ $(GST_BASE_LIBS) $(GST_LIBS) $(GIO_LIBS)
|
||||
libgstmultifile_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstmultifile_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
|
||||
|
||||
noinst_HEADERS = gstmultifilesrc.h gstmultifilesink.h gstsplitfilesrc.h patternspec.h
|
||||
noinst_HEADERS = gstmultifilesrc.h gstmultifilesink.h gstsplitfilesrc.h gstsplitmuxsink.h \
|
||||
gstsplitmuxsrc.h gstsplitmuxpartreader.h gstsplitutils.h patternspec.h
|
||||
|
||||
noinst_PROGRAMS = test-splitmux-part-reader
|
||||
|
||||
test_splitmux_part_reader_SOURCES = \
|
||||
test-splitmuxpartreader.c \
|
||||
gstsplitmuxpartreader.c \
|
||||
gstsplitmuxsrc.c \
|
||||
gstsplitutils.c \
|
||||
patternspec.c
|
||||
test_splitmux_part_reader_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS)
|
||||
test_splitmux_part_reader_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@ $(GST_BASE_LIBS) $(GST_LIBS) $(GIO_LIBS)
|
||||
test_splitmux_part_reader_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
Android.mk: Makefile.am $(BUILT_SOURCES)
|
||||
androgenizer \
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include "gstmultifilesink.h"
|
||||
#include "gstmultifilesrc.h"
|
||||
#include "gstsplitfilesrc.h"
|
||||
#include "gstsplitmuxsink.h"
|
||||
#include "gstsplitmuxsrc.h"
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
|
@ -42,6 +44,12 @@ plugin_init (GstPlugin * plugin)
|
|||
gst_element_register (plugin, "splitfilesrc", GST_RANK_NONE,
|
||||
gst_split_file_src_get_type ());
|
||||
|
||||
if (!register_splitmuxsink (plugin))
|
||||
return FALSE;
|
||||
|
||||
if (!register_splitmuxsrc (plugin))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,16 +45,10 @@
|
|||
#endif
|
||||
|
||||
#include "gstsplitfilesrc.h"
|
||||
#include "patternspec.h"
|
||||
#include "gstsplitutils.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#define DEFAULT_PATTERN_MATCH_MODE MATCH_MODE_UTF8
|
||||
#else
|
||||
#define DEFAULT_PATTERN_MATCH_MODE MATCH_MODE_AUTO
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_LOCATION = 1
|
||||
|
@ -237,84 +231,6 @@ gst_split_file_src_get_property (GObject * object, guint prop_id,
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
gst_split_file_src_array_sortfunc (gchar ** a, gchar ** b)
|
||||
{
|
||||
return strcmp (*a, *b);
|
||||
}
|
||||
|
||||
static gchar **
|
||||
gst_split_file_src_find_files (GstSplitFileSrc * src, const gchar * dirname,
|
||||
const gchar * basename, GError ** err)
|
||||
{
|
||||
PatternSpec *pspec;
|
||||
GPtrArray *files;
|
||||
const gchar *name;
|
||||
GDir *dir;
|
||||
|
||||
if (dirname == NULL || basename == NULL)
|
||||
goto invalid_location;
|
||||
|
||||
GST_INFO_OBJECT (src, "checking in directory '%s' for pattern '%s'",
|
||||
dirname, basename);
|
||||
|
||||
dir = g_dir_open (dirname, 0, err);
|
||||
if (dir == NULL)
|
||||
return NULL;
|
||||
|
||||
if (DEFAULT_PATTERN_MATCH_MODE == MATCH_MODE_UTF8 &&
|
||||
!g_utf8_validate (basename, -1, NULL)) {
|
||||
goto not_utf8;
|
||||
}
|
||||
|
||||
/* mode will be AUTO on linux/unix and UTF8 on win32 */
|
||||
pspec = pattern_spec_new (basename, DEFAULT_PATTERN_MATCH_MODE);
|
||||
|
||||
files = g_ptr_array_new ();
|
||||
|
||||
while ((name = g_dir_read_name (dir))) {
|
||||
GST_TRACE_OBJECT (src, "check: %s", name);
|
||||
if (pattern_match_string (pspec, name)) {
|
||||
GST_DEBUG_OBJECT (src, "match: %s", name);
|
||||
g_ptr_array_add (files, g_build_filename (dirname, name, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
if (files->len == 0)
|
||||
goto no_matches;
|
||||
|
||||
g_ptr_array_sort (files, (GCompareFunc) gst_split_file_src_array_sortfunc);
|
||||
g_ptr_array_add (files, NULL);
|
||||
|
||||
pattern_spec_free (pspec);
|
||||
g_dir_close (dir);
|
||||
|
||||
return (gchar **) g_ptr_array_free (files, FALSE);
|
||||
|
||||
/* ERRORS */
|
||||
invalid_location:
|
||||
{
|
||||
g_set_error_literal (err, G_FILE_ERROR, G_FILE_ERROR_INVAL,
|
||||
"No filename specified.");
|
||||
return NULL;
|
||||
}
|
||||
not_utf8:
|
||||
{
|
||||
g_dir_close (dir);
|
||||
g_set_error_literal (err, G_FILE_ERROR, G_FILE_ERROR_INVAL,
|
||||
"Filename pattern must be UTF-8 on Windows.");
|
||||
return NULL;
|
||||
}
|
||||
no_matches:
|
||||
{
|
||||
pattern_spec_free (pspec);
|
||||
g_dir_close (dir);
|
||||
g_set_error_literal (err, G_FILE_ERROR, G_FILE_ERROR_NOENT,
|
||||
"Found no files matching the pattern.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_split_file_src_start (GstBaseSrc * basesrc)
|
||||
{
|
||||
|
@ -335,7 +251,7 @@ gst_split_file_src_start (GstBaseSrc * basesrc)
|
|||
}
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
|
||||
files = gst_split_file_src_find_files (src, dirname, basename, &err);
|
||||
files = gst_split_util_find_files (dirname, basename, &err);
|
||||
|
||||
if (files == NULL || *files == NULL)
|
||||
goto no_files;
|
||||
|
|
1258
gst/multifile/gstsplitmuxpartreader.c
Normal file
1258
gst/multifile/gstsplitmuxpartreader.c
Normal file
File diff suppressed because it is too large
Load diff
117
gst/multifile/gstsplitmuxpartreader.h
Normal file
117
gst/multifile/gstsplitmuxpartreader.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
/* GStreamer Split Muxed File Source - Part reader
|
||||
* Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
|
||||
*
|
||||
* 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_SPLITMUX_PART_READER_H__
|
||||
#define __GST_SPLITMUX_PART_READER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstdataqueue.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_SPLITMUX_PART_READER \
|
||||
(gst_splitmux_part_reader_get_type())
|
||||
#define GST_SPLITMUX_PART_READER(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPLITMUX_PART_READER,GstSplitMuxSrc))
|
||||
#define GST_SPLITMUX_PART_READER_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPLITMUX_PART_READER,GstSplitMuxSrcClass))
|
||||
#define GST_IS_SPLITMUX_PART_READER(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPLITMUX_PART_READER))
|
||||
#define GST_IS_SPLITMUX_PART_READER_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPLITMUX_PART_READER))
|
||||
|
||||
typedef struct _GstSplitMuxPartReader GstSplitMuxPartReader;
|
||||
typedef struct _GstSplitMuxPartReaderClass GstSplitMuxPartReaderClass;
|
||||
typedef struct _SplitMuxSrcPad SplitMuxSrcPad;
|
||||
typedef struct _SplitMuxSrcPadClass SplitMuxSrcPadClass;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PART_STATE_NULL,
|
||||
PART_STATE_PREPARING_COLLECT_STREAMS,
|
||||
PART_STATE_PREPARING_MEASURE_STREAMS,
|
||||
PART_STATE_PREPARING_RESET_FOR_READY,
|
||||
PART_STATE_READY,
|
||||
PART_STATE_FAILED,
|
||||
} GstSplitMuxPartState;
|
||||
|
||||
typedef GstPad *(*GstSplitMuxPartReaderPadCb)(GstSplitMuxPartReader *reader, GstPad *src_pad, gpointer cb_data);
|
||||
|
||||
struct _GstSplitMuxPartReader
|
||||
{
|
||||
GstPipeline parent;
|
||||
|
||||
GstSplitMuxPartState prep_state;
|
||||
|
||||
gchar *path;
|
||||
|
||||
GstElement *src;
|
||||
GstElement *typefind;
|
||||
GstElement *demux;
|
||||
|
||||
gboolean active;
|
||||
gboolean running;
|
||||
gboolean prepared;
|
||||
gboolean flushing;
|
||||
gboolean no_more_pads;
|
||||
|
||||
GstClockTime duration;
|
||||
GstClockTime start_offset;
|
||||
|
||||
GList *pads;
|
||||
|
||||
GCond inactive_cond;
|
||||
GMutex lock;
|
||||
|
||||
GstSplitMuxPartReaderPadCb get_pad_cb;
|
||||
gpointer cb_data;
|
||||
};
|
||||
|
||||
struct _GstSplitMuxPartReaderClass
|
||||
{
|
||||
GstPipelineClass parent_class;
|
||||
|
||||
void (*prepared) (GstSplitMuxPartReader *reader);
|
||||
void (*end_of_part) (GstSplitMuxPartReader *reader);
|
||||
};
|
||||
|
||||
GType gst_splitmux_part_reader_get_type (void);
|
||||
|
||||
void gst_splitmux_part_reader_set_callbacks (GstSplitMuxPartReader *reader,
|
||||
gpointer cb_data, GstSplitMuxPartReaderPadCb get_pad_cb);
|
||||
gboolean gst_splitmux_part_reader_prepare (GstSplitMuxPartReader *part);
|
||||
void gst_splitmux_part_reader_unprepare (GstSplitMuxPartReader *part);
|
||||
void gst_splitmux_part_reader_set_location (GstSplitMuxPartReader *reader,
|
||||
const gchar *path);
|
||||
gboolean gst_splitmux_part_is_eos (GstSplitMuxPartReader *reader);
|
||||
|
||||
gboolean gst_splitmux_part_reader_activate (GstSplitMuxPartReader *part, GstSegment *seg);
|
||||
void gst_splitmux_part_reader_deactivate (GstSplitMuxPartReader *part);
|
||||
|
||||
gboolean gst_splitmux_part_reader_src_query (GstSplitMuxPartReader *part, GstPad *src_pad, GstQuery * query);
|
||||
void gst_splitmux_part_reader_set_start_offset (GstSplitMuxPartReader *part, GstClockTime offset);
|
||||
GstClockTime gst_splitmux_part_reader_get_start_offset (GstSplitMuxPartReader *part);
|
||||
GstClockTime gst_splitmux_part_reader_get_end_offset (GstSplitMuxPartReader *part);
|
||||
GstClockTime gst_splitmux_part_reader_get_duration (GstSplitMuxPartReader * reader);
|
||||
|
||||
GstPad *gst_splitmux_part_reader_lookup_pad (GstSplitMuxPartReader *reader, GstPad *target);
|
||||
GstFlowReturn gst_splitmux_part_reader_pop (GstSplitMuxPartReader *reader, GstPad *part_pad, GstDataQueueItem ** item);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
1460
gst/multifile/gstsplitmuxsink.c
Normal file
1460
gst/multifile/gstsplitmuxsink.c
Normal file
File diff suppressed because it is too large
Load diff
132
gst/multifile/gstsplitmuxsink.h
Normal file
132
gst/multifile/gstsplitmuxsink.h
Normal file
|
@ -0,0 +1,132 @@
|
|||
/* GStreamer split muxer bin
|
||||
* Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
|
||||
*
|
||||
* 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_SPLITMUXSINK_H__
|
||||
#define __GST_SPLITMUXSINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_SPLITMUX_SINK (gst_splitmux_sink_get_type())
|
||||
#define GST_SPLITMUX_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPLITMUX_SINK,GstSplitMuxSink))
|
||||
#define GST_SPLITMUX_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPLITMUX_SINK,GstSplitMuxSinkClass))
|
||||
#define GST_IS_SPLITMUX_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPLITMUX_SINK))
|
||||
#define GST_IS_SPLITMUX_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPLITMUX_SINK))
|
||||
|
||||
typedef struct _GstSplitMuxSink GstSplitMuxSink;
|
||||
typedef struct _GstSplitMuxSinkClass GstSplitMuxSinkClass;
|
||||
|
||||
GType gst_splitmux_sink_get_type(void);
|
||||
gboolean register_splitmuxsink (GstPlugin * plugin);
|
||||
|
||||
typedef enum _SplitMuxState {
|
||||
SPLITMUX_STATE_STOPPED,
|
||||
SPLITMUX_STATE_COLLECTING_GOP_START,
|
||||
SPLITMUX_STATE_WAITING_GOP_COMPLETE,
|
||||
SPLITMUX_STATE_ENDING_FILE,
|
||||
SPLITMUX_STATE_START_NEXT_FRAGMENT,
|
||||
} SplitMuxState;
|
||||
|
||||
typedef struct _MqStreamBuf
|
||||
{
|
||||
gboolean keyframe;
|
||||
GstClockTime run_ts;
|
||||
gsize buf_size;
|
||||
} MqStreamBuf;
|
||||
|
||||
typedef struct _MqStreamCtx
|
||||
{
|
||||
gint refcount;
|
||||
|
||||
GstSplitMuxSink *splitmux;
|
||||
|
||||
guint sink_pad_block_id;
|
||||
guint src_pad_block_id;
|
||||
|
||||
gboolean is_video;
|
||||
|
||||
gboolean flushing;
|
||||
gboolean in_eos;
|
||||
gboolean out_eos;
|
||||
|
||||
GstSegment in_segment;
|
||||
GstSegment out_segment;
|
||||
|
||||
GstClockTime in_running_time;
|
||||
GstClockTime out_running_time;
|
||||
|
||||
gsize in_bytes;
|
||||
|
||||
GQueue queued_bufs;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstPad *srcpad;
|
||||
|
||||
gboolean out_blocked;
|
||||
} MqStreamCtx;
|
||||
|
||||
struct _GstSplitMuxSink {
|
||||
GstBin parent;
|
||||
|
||||
GMutex lock;
|
||||
GCond data_cond;
|
||||
|
||||
SplitMuxState state;
|
||||
gdouble mux_overhead;
|
||||
|
||||
GstClockTime threshold_time;
|
||||
guint64 threshold_bytes;
|
||||
|
||||
guint mq_max_buffers;
|
||||
|
||||
GstElement *mq;
|
||||
GstElement *muxer;
|
||||
GstElement *sink;
|
||||
|
||||
GstElement *provided_muxer;
|
||||
|
||||
GstElement *provided_sink;
|
||||
GstElement *active_sink;
|
||||
|
||||
gchar *location;
|
||||
guint fragment_id;
|
||||
|
||||
GList *contexts;
|
||||
|
||||
MqStreamCtx *video_ctx;
|
||||
guint queued_gops;
|
||||
GstClockTime max_in_running_time;
|
||||
GstClockTime max_out_running_time;
|
||||
|
||||
GstClockTime muxed_out_time;
|
||||
gsize muxed_out_bytes;
|
||||
|
||||
GstClockTime mux_start_time;
|
||||
gsize mux_start_bytes;
|
||||
};
|
||||
|
||||
struct _GstSplitMuxSinkClass {
|
||||
GstBinClass parent_class;
|
||||
};
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_SPLITMUXSINK_H__ */
|
1118
gst/multifile/gstsplitmuxsrc.c
Normal file
1118
gst/multifile/gstsplitmuxsrc.c
Normal file
File diff suppressed because it is too large
Load diff
108
gst/multifile/gstsplitmuxsrc.h
Normal file
108
gst/multifile/gstsplitmuxsrc.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/* GStreamer Split Muxed File Source
|
||||
* Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
|
||||
*
|
||||
* 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_SPLITMUX_SRC_H__
|
||||
#define __GST_SPLITMUX_SRC_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gstsplitmuxpartreader.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_SPLITMUX_SRC \
|
||||
(gst_splitmux_src_get_type())
|
||||
#define GST_SPLITMUX_SRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPLITMUX_SRC,GstSplitMuxSrc))
|
||||
#define GST_SPLITMUX_SRC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPLITMUX_SRC,GstSplitMuxSrcClass))
|
||||
#define GST_IS_SPLITMUX_SRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPLITMUX_SRC))
|
||||
#define GST_IS_SPLITMUX_SRC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPLITMUX_SRC))
|
||||
|
||||
typedef struct _GstSplitMuxSrc GstSplitMuxSrc;
|
||||
typedef struct _GstSplitMuxSrcClass GstSplitMuxSrcClass;
|
||||
|
||||
struct _GstSplitMuxSrc
|
||||
{
|
||||
GstBin parent;
|
||||
|
||||
GMutex lock;
|
||||
gboolean running;
|
||||
|
||||
gchar *location; /* OBJECT_LOCK */
|
||||
|
||||
GstSplitMuxPartReader **parts;
|
||||
guint num_parts;
|
||||
guint cur_part;
|
||||
|
||||
gboolean pads_complete;
|
||||
GMutex pads_lock;
|
||||
GList *pads; /* pads_lock */
|
||||
|
||||
GstClockTime total_duration;
|
||||
GstSegment play_segment;
|
||||
};
|
||||
|
||||
struct _GstSplitMuxSrcClass
|
||||
{
|
||||
GstBinClass parent_class;
|
||||
};
|
||||
|
||||
GType splitmux_src_pad_get_type (void);
|
||||
#define SPLITMUX_TYPE_SRC_PAD splitmux_src_pad_get_type()
|
||||
#define SPLITMUX_SRC_PAD_CAST(p) ((SplitMuxSrcPad *)(p))
|
||||
#define SPLITMUX_SRC_PAD(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),SPLITMUX_TYPE_SRC_PAD,SplitMuxSrcPad))
|
||||
|
||||
struct _SplitMuxSrcPad
|
||||
{
|
||||
GstPad parent;
|
||||
|
||||
guint cur_part;
|
||||
GstSplitMuxPartReader *reader;
|
||||
GstPad *part_pad;
|
||||
|
||||
GstSegment segment;
|
||||
|
||||
gboolean set_next_discont;
|
||||
gboolean clear_next_discont;
|
||||
|
||||
gboolean sent_stream_start;
|
||||
gboolean sent_caps;
|
||||
gboolean sent_segment;
|
||||
};
|
||||
|
||||
struct _SplitMuxSrcPadClass
|
||||
{
|
||||
GstPadClass parent;
|
||||
};
|
||||
|
||||
GType gst_splitmux_src_get_type (void);
|
||||
gboolean register_splitmuxsrc (GstPlugin * plugin);
|
||||
|
||||
#define SPLITMUX_SRC_LOCK(s) g_mutex_lock(&(s)->lock)
|
||||
#define SPLITMUX_SRC_UNLOCK(s) g_mutex_unlock(&(s)->lock)
|
||||
|
||||
#define SPLITMUX_SRC_PADS_LOCK(s) g_mutex_lock(&(s)->pads_lock)
|
||||
#define SPLITMUX_SRC_PADS_UNLOCK(s) g_mutex_unlock(&(s)->pads_lock)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_SPLITMUX_SRC_H__ */
|
105
gst/multifile/gstsplitutils.c
Normal file
105
gst/multifile/gstsplitutils.c
Normal file
|
@ -0,0 +1,105 @@
|
|||
/* GStreamer Split Source Utility Functions
|
||||
* Copyright (C) 2011 Collabora Ltd. <tim.muller@collabora.co.uk>
|
||||
* Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "gstsplitutils.h"
|
||||
#include "patternspec.h"
|
||||
|
||||
static int
|
||||
gst_split_util_array_sortfunc (gchar ** a, gchar ** b)
|
||||
{
|
||||
return strcmp (*a, *b);
|
||||
}
|
||||
|
||||
gchar **
|
||||
gst_split_util_find_files (const gchar * dirname,
|
||||
const gchar * basename, GError ** err)
|
||||
{
|
||||
PatternSpec *pspec;
|
||||
GPtrArray *files;
|
||||
const gchar *name;
|
||||
GDir *dir;
|
||||
|
||||
if (dirname == NULL || basename == NULL)
|
||||
goto invalid_location;
|
||||
|
||||
GST_INFO ("checking in directory '%s' for pattern '%s'", dirname, basename);
|
||||
|
||||
dir = g_dir_open (dirname, 0, err);
|
||||
if (dir == NULL)
|
||||
return NULL;
|
||||
|
||||
if (DEFAULT_PATTERN_MATCH_MODE == MATCH_MODE_UTF8 &&
|
||||
!g_utf8_validate (basename, -1, NULL)) {
|
||||
goto not_utf8;
|
||||
}
|
||||
|
||||
/* mode will be AUTO on linux/unix and UTF8 on win32 */
|
||||
pspec = pattern_spec_new (basename, DEFAULT_PATTERN_MATCH_MODE);
|
||||
|
||||
files = g_ptr_array_new ();
|
||||
|
||||
while ((name = g_dir_read_name (dir))) {
|
||||
GST_TRACE ("check: %s", name);
|
||||
if (pattern_match_string (pspec, name)) {
|
||||
GST_DEBUG ("match: %s", name);
|
||||
g_ptr_array_add (files, g_build_filename (dirname, name, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
if (files->len == 0)
|
||||
goto no_matches;
|
||||
|
||||
g_ptr_array_sort (files, (GCompareFunc) gst_split_util_array_sortfunc);
|
||||
g_ptr_array_add (files, NULL);
|
||||
|
||||
pattern_spec_free (pspec);
|
||||
g_dir_close (dir);
|
||||
|
||||
return (gchar **) g_ptr_array_free (files, FALSE);
|
||||
|
||||
/* ERRORS */
|
||||
invalid_location:
|
||||
{
|
||||
g_set_error_literal (err, G_FILE_ERROR, G_FILE_ERROR_INVAL,
|
||||
"No filename specified.");
|
||||
return NULL;
|
||||
}
|
||||
not_utf8:
|
||||
{
|
||||
g_dir_close (dir);
|
||||
g_set_error_literal (err, G_FILE_ERROR, G_FILE_ERROR_INVAL,
|
||||
"Filename pattern must be UTF-8 on Windows.");
|
||||
return NULL;
|
||||
}
|
||||
no_matches:
|
||||
{
|
||||
pattern_spec_free (pspec);
|
||||
g_dir_close (dir);
|
||||
g_set_error_literal (err, G_FILE_ERROR, G_FILE_ERROR_NOENT,
|
||||
"Found no files matching the pattern.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
40
gst/multifile/gstsplitutils.h
Normal file
40
gst/multifile/gstsplitutils.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* GStreamer Split Source Utility Functions
|
||||
* Copyright (C) 2011 Collabora Ltd. <tim.muller@collabora.co.uk>
|
||||
* Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
|
||||
*
|
||||
* 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_SPLITUTILS_H__
|
||||
#define __GST_SPLITUTILS_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#define DEFAULT_PATTERN_MATCH_MODE MATCH_MODE_UTF8
|
||||
#else
|
||||
#define DEFAULT_PATTERN_MATCH_MODE MATCH_MODE_AUTO
|
||||
#endif
|
||||
|
||||
gchar **
|
||||
gst_split_util_find_files (const gchar * dirname,
|
||||
const gchar * basename, GError ** err);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
104
gst/multifile/test-splitmuxpartreader.c
Normal file
104
gst/multifile/test-splitmuxpartreader.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
#include <gst/gst.h>
|
||||
#include "gstsplitmuxpartreader.h"
|
||||
#include "gstsplitmuxsrc.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (splitmux_debug);
|
||||
|
||||
static const gchar *const path = "out001.mp4";
|
||||
|
||||
typedef struct _CustomData
|
||||
{
|
||||
GstSplitMuxPartReader *reader;
|
||||
GMainLoop *main_loop;
|
||||
GstBus *bus;
|
||||
} CustomData;
|
||||
|
||||
static void
|
||||
part_prepared (GstSplitMuxPartReader * reader)
|
||||
{
|
||||
g_print ("Part prepared\n");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_message (GstBus * bus, GstMessage * msg, CustomData * data)
|
||||
{
|
||||
GError *err;
|
||||
gchar *debug_info;
|
||||
|
||||
switch (GST_MESSAGE_TYPE (msg)) {
|
||||
case GST_MESSAGE_ERROR:
|
||||
gst_message_parse_error (msg, &err, &debug_info);
|
||||
g_print ("Error received from element %s: %s\n",
|
||||
GST_OBJECT_NAME (msg->src), err->message);
|
||||
g_print ("Debugging information: %s\n", debug_info ? debug_info : "none");
|
||||
g_clear_error (&err);
|
||||
g_free (debug_info);
|
||||
g_main_loop_quit (data->main_loop);
|
||||
break;
|
||||
case GST_MESSAGE_EOS:
|
||||
g_print ("End-Of-Stream reached.\n");
|
||||
g_main_loop_quit (data->main_loop);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_reader (CustomData * data)
|
||||
{
|
||||
g_print ("Preparing part reader for %s\n", path);
|
||||
gst_splitmux_part_reader_prepare (data->reader);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
handle_get_pad (GstSplitMuxPartReader * reader, GstPad * src_pad,
|
||||
CustomData * data)
|
||||
{
|
||||
/* Create a dummy target pad for the reader */
|
||||
GstPad *new_pad = g_object_new (SPLITMUX_TYPE_SRC_PAD,
|
||||
"name", GST_PAD_NAME (src_pad), "direction", GST_PAD_SRC, NULL);
|
||||
|
||||
g_print ("Creating new dummy pad %s\n", GST_PAD_NAME (src_pad));
|
||||
|
||||
return new_pad;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
CustomData data;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
data.main_loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
data.reader = g_object_new (GST_TYPE_SPLITMUX_PART_READER, NULL);
|
||||
data.bus = gst_element_get_bus (GST_ELEMENT_CAST (data.reader));
|
||||
|
||||
/* Listen for bus messages */
|
||||
gst_bus_add_watch (data.bus, (GstBusFunc) handle_message, &data);
|
||||
|
||||
gst_splitmux_part_reader_set_location (data.reader, path);
|
||||
|
||||
/* Connect to prepare signal */
|
||||
g_signal_connect (data.reader, "prepared", (GCallback) part_prepared, &data);
|
||||
gst_splitmux_part_reader_set_callbacks (data.reader, &data,
|
||||
(GstSplitMuxPartReaderPadCb) handle_get_pad);
|
||||
|
||||
g_idle_add ((GSourceFunc) start_reader, &data);
|
||||
|
||||
/* Run mainloop */
|
||||
g_main_loop_run (data.main_loop);
|
||||
|
||||
gst_splitmux_part_reader_unprepare (data.reader);
|
||||
|
||||
g_main_loop_unref (data.main_loop);
|
||||
gst_object_unref (data.bus);
|
||||
g_object_unref (data.reader);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -198,7 +198,7 @@ check_matroska =
|
|||
endif
|
||||
|
||||
if USE_PLUGIN_MULTIFILE
|
||||
check_multifile = elements/multifile
|
||||
check_multifile = elements/multifile elements/splitmux
|
||||
else
|
||||
check_multifile =
|
||||
endif
|
||||
|
|
1
tests/check/elements/.gitignore
vendored
1
tests/check/elements/.gitignore
vendored
|
@ -58,6 +58,7 @@ rtprtx
|
|||
shapewipe
|
||||
souphttpsrc
|
||||
spectrum
|
||||
splitmux
|
||||
sunaudio
|
||||
udpsink
|
||||
udpsrc
|
||||
|
|
126
tests/check/elements/splitmux.c
Normal file
126
tests/check/elements/splitmux.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
/* GStreamer unit test for splitmuxsrc/sink elements
|
||||
*
|
||||
* Copyright (C) 2007 David A. Schleef <ds@schleef.org>
|
||||
* Copyright (C) 2015 Jan Schmidt <jan@centricular.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gst/check/gstcheck.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
gchar *tmpdir = NULL;
|
||||
|
||||
static void
|
||||
tempdir_setup (void)
|
||||
{
|
||||
const gchar *systmp = g_get_tmp_dir ();
|
||||
tmpdir = g_build_filename (systmp, "splitmux-test-XXXXXX", NULL);
|
||||
/* Rewrites tmpdir template input: */
|
||||
tmpdir = g_mkdtemp (tmpdir);
|
||||
}
|
||||
|
||||
static void
|
||||
tempdir_cleanup (void)
|
||||
{
|
||||
GDir *d;
|
||||
const gchar *f;
|
||||
|
||||
fail_if (tmpdir == NULL);
|
||||
|
||||
d = g_dir_open (tmpdir, 0, NULL);
|
||||
fail_if (d == NULL);
|
||||
|
||||
while ((f = g_dir_read_name (d)) != NULL)
|
||||
fail_if (g_remove (f) != 0);
|
||||
g_dir_close (d);
|
||||
|
||||
fail_if (g_remove (tmpdir) != 0);
|
||||
|
||||
g_free (tmpdir);
|
||||
tmpdir = NULL;
|
||||
}
|
||||
|
||||
static GstMessage *
|
||||
run_pipeline (GstElement * pipeline)
|
||||
{
|
||||
GstBus *bus = gst_element_get_bus (GST_ELEMENT (pipeline));
|
||||
GstMessage *msg;
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
gst_object_unref (bus);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
GST_START_TEST (test_splitmuxsrc)
|
||||
{
|
||||
GstMessage *msg;
|
||||
GstElement *pipeline;
|
||||
GstElement *fakesink;
|
||||
gchar *in_pattern;
|
||||
gchar *uri;
|
||||
|
||||
pipeline = gst_element_factory_make ("playbin", NULL);
|
||||
fail_if (pipeline == NULL);
|
||||
|
||||
fakesink = gst_element_factory_make ("fakesink", NULL);
|
||||
fail_if (fakesink == NULL);
|
||||
g_object_set (G_OBJECT (pipeline), "video-sink", fakesink, NULL);
|
||||
|
||||
in_pattern = g_build_filename (GST_TEST_FILES_PATH, "splitvideo*.ogg", NULL);
|
||||
uri = g_strdup_printf ("splitmux://%s", in_pattern);
|
||||
g_free (in_pattern);
|
||||
|
||||
g_object_set (G_OBJECT (pipeline), "uri", uri, NULL);
|
||||
g_free (uri);
|
||||
|
||||
msg = run_pipeline (pipeline);
|
||||
gst_object_unref (pipeline);
|
||||
|
||||
fail_if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR);
|
||||
gst_message_unref (msg);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
splitmux_suite (void)
|
||||
{
|
||||
Suite *s = suite_create ("splitmux");
|
||||
TCase *tc_chain = tcase_create ("general");
|
||||
|
||||
suite_add_tcase (s, tc_chain);
|
||||
|
||||
tcase_add_checked_fixture (tc_chain, tempdir_setup, tempdir_cleanup);
|
||||
|
||||
tcase_add_test (tc_chain, test_splitmuxsrc);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
GST_CHECK_MAIN (splitmux);
|
BIN
tests/files/splitvideo00.ogg
Normal file
BIN
tests/files/splitvideo00.ogg
Normal file
Binary file not shown.
BIN
tests/files/splitvideo01.ogg
Normal file
BIN
tests/files/splitvideo01.ogg
Normal file
Binary file not shown.
BIN
tests/files/splitvideo02.ogg
Normal file
BIN
tests/files/splitvideo02.ogg
Normal file
Binary file not shown.
Loading…
Reference in a new issue