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/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 \

View file

@ -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" />

View file

@ -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>

View file

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

View file

@ -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

View file

@ -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 \

View file

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

View file

@ -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;

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
if USE_PLUGIN_MULTIFILE
check_multifile = elements/multifile
check_multifile = elements/multifile elements/splitmux
else
check_multifile =
endif

View file

@ -58,6 +58,7 @@ rtprtx
shapewipe
souphttpsrc
spectrum
splitmux
sunaudio
udpsink
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.