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:
Jan Schmidt 2014-08-01 00:07:53 +10:00
parent 59431f663a
commit 5e2214d309
23 changed files with 4633 additions and 88 deletions

View file

@ -157,6 +157,8 @@ EXTRA_HFILES = \
$(top_srcdir)/gst/multifile/gstmultifilesink.h \ $(top_srcdir)/gst/multifile/gstmultifilesink.h \
$(top_srcdir)/gst/multifile/gstmultifilesrc.h \ $(top_srcdir)/gst/multifile/gstmultifilesrc.h \
$(top_srcdir)/gst/multifile/gstsplitfilesrc.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/multipartdemux.h \
$(top_srcdir)/gst/multipart/multipartmux.h \ $(top_srcdir)/gst/multipart/multipartmux.h \
$(top_srcdir)/gst/isomp4/qtdemux.h \ $(top_srcdir)/gst/isomp4/qtdemux.h \

View file

@ -162,6 +162,8 @@
<xi:include href="xml/element-speexenc.xml" /> <xi:include href="xml/element-speexenc.xml" />
<xi:include href="xml/element-speexdec.xml" /> <xi:include href="xml/element-speexdec.xml" />
<xi:include href="xml/element-splitfilesrc.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-streaktv.xml" />
<xi:include href="xml/element-taginject.xml" /> <xi:include href="xml/element-taginject.xml" />
<xi:include href="xml/element-udpsrc.xml" /> <xi:include href="xml/element-udpsrc.xml" />

View file

@ -2013,6 +2013,34 @@ GST_TYPE_SPLIT_FILE_SRC
gst_split_file_src_get_type gst_split_file_src_get_type
</SECTION> </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> <SECTION>
<FILE>element-taginject</FILE> <FILE>element-taginject</FILE>
<TITLE>taginject</TITLE> <TITLE>taginject</TITLE>

View file

@ -152,6 +152,8 @@ GObject
GstRTSPSrc GstRTSPSrc
GstRgVolume GstRgVolume
GstRtpBin GstRtpBin
GstSplitMuxSink
GstSplitMuxSrc
GstCutter GstCutter
GstDVDec GstDVDec
GstDVDemux GstDVDemux

View file

@ -71,6 +71,8 @@ GstSoupHTTPSrc GstURIHandler
GstSpeexEnc GstPreset GstTagSetter GstSpeexEnc GstPreset GstTagSetter
GstSpeexEnc GstTagSetter GstPreset GstSpeexEnc GstTagSetter GstPreset
GstSplitFileSrc GstURIHandler GstSplitFileSrc GstURIHandler
GstSplitMuxSink GstChildProxy
GstSplitMuxSrc GstChildProxy GstURIHandler
GstSwitchSink GstChildProxy GstSwitchSink GstChildProxy
GstSwitchSrc GstChildProxy GstSwitchSrc GstChildProxy
GstTagLibMux GstTagSetter GstTagLibMux GstTagSetter

View file

@ -6,14 +6,30 @@ libgstmultifile_la_SOURCES = \
gstmultifilesrc.c \ gstmultifilesrc.c \
gstmultifile.c \ gstmultifile.c \
gstsplitfilesrc.c \ gstsplitfilesrc.c \
gstsplitmuxsink.c \
gstsplitmuxpartreader.c \
gstsplitmuxsrc.c \
gstsplitutils.c \
patternspec.c patternspec.c
libgstmultifile_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS) 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_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@ $(GST_BASE_LIBS) $(GST_LIBS) $(GIO_LIBS)
libgstmultifile_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstmultifile_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstmultifile_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) 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) Android.mk: Makefile.am $(BUILT_SOURCES)
androgenizer \ androgenizer \

View file

@ -31,6 +31,8 @@
#include "gstmultifilesink.h" #include "gstmultifilesink.h"
#include "gstmultifilesrc.h" #include "gstmultifilesrc.h"
#include "gstsplitfilesrc.h" #include "gstsplitfilesrc.h"
#include "gstsplitmuxsink.h"
#include "gstsplitmuxsrc.h"
static gboolean static gboolean
plugin_init (GstPlugin * plugin) plugin_init (GstPlugin * plugin)
@ -42,6 +44,12 @@ plugin_init (GstPlugin * plugin)
gst_element_register (plugin, "splitfilesrc", GST_RANK_NONE, gst_element_register (plugin, "splitfilesrc", GST_RANK_NONE,
gst_split_file_src_get_type ()); gst_split_file_src_get_type ());
if (!register_splitmuxsink (plugin))
return FALSE;
if (!register_splitmuxsrc (plugin))
return FALSE;
return TRUE; return TRUE;
} }

View file

@ -45,16 +45,10 @@
#endif #endif
#include "gstsplitfilesrc.h" #include "gstsplitfilesrc.h"
#include "patternspec.h" #include "gstsplitutils.h"
#include <string.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 enum
{ {
PROP_LOCATION = 1 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 static gboolean
gst_split_file_src_start (GstBaseSrc * basesrc) gst_split_file_src_start (GstBaseSrc * basesrc)
{ {
@ -335,7 +251,7 @@ gst_split_file_src_start (GstBaseSrc * basesrc)
} }
GST_OBJECT_UNLOCK (src); 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) if (files == NULL || *files == NULL)
goto no_files; goto no_files;

File diff suppressed because it is too large Load diff

View 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

File diff suppressed because it is too large Load diff

View 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__ */

File diff suppressed because it is too large Load diff

View 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__ */

View 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;
}
}

View 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

View 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;
}

View file

@ -198,7 +198,7 @@ check_matroska =
endif endif
if USE_PLUGIN_MULTIFILE if USE_PLUGIN_MULTIFILE
check_multifile = elements/multifile check_multifile = elements/multifile elements/splitmux
else else
check_multifile = check_multifile =
endif endif

View file

@ -58,6 +58,7 @@ rtprtx
shapewipe shapewipe
souphttpsrc souphttpsrc
spectrum spectrum
splitmux
sunaudio sunaudio
udpsink udpsink
udpsrc udpsrc

View 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);

Binary file not shown.

Binary file not shown.

Binary file not shown.