summaryrefslogtreecommitdiffstats
path: root/ext/mplex
diff options
context:
space:
mode:
Diffstat (limited to 'ext/mplex')
-rw-r--r--ext/mplex/Makefile.am20
-rw-r--r--ext/mplex/gstmplex.cc741
-rw-r--r--ext/mplex/gstmplex.h103
-rw-r--r--ext/mplex/gstmplex.hh64
-rw-r--r--ext/mplex/gstmplexibitstream.cc112
-rw-r--r--ext/mplex/gstmplexibitstream.hh50
-rw-r--r--ext/mplex/gstmplexjob.cc232
-rw-r--r--ext/mplex/gstmplexjob.hh42
-rw-r--r--ext/mplex/gstmplexoutputstream.cc101
-rw-r--r--ext/mplex/gstmplexoutputstream.hh54
10 files changed, 942 insertions, 577 deletions
diff --git a/ext/mplex/Makefile.am b/ext/mplex/Makefile.am
index 5f9d847f..d99b5b7c 100644
--- a/ext/mplex/Makefile.am
+++ b/ext/mplex/Makefile.am
@@ -1,11 +1,17 @@
-
plugin_LTLIBRARIES = libgstmplex.la
-libgstmplex_la_SOURCES = gstmplex.cc
-libgstmplex_la_CXXFLAGS = $(GST_CFLAGS) -I$(top_srcdir)/gst-libs/ext/mplex/
-libgstmplex_la_LIBADD = $(LIBM_LIBS) $(top_builddir)/gst-libs/ext/mplex/libmplex.la
-libgstmplex_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-
-noinst_HEADERS = gstmplex.h
+libgstmplex_la_SOURCES = \
+ gstmplex.cc \
+ gstmplexibitstream.cc \
+ gstmplexjob.cc \
+ gstmplexoutputstream.cc
+libgstmplex_la_CXXFLAGS = $(GST_CFLAGS) $(MPLEX_CFLAGS)
+libgstmplex_la_LIBADD = $(MPLEX_LIBS)
+libgstmplex_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+noinst_HEADERS = \
+ gstmplex.hh \
+ gstmplexibitstream.hh \
+ gstmplexjob.hh \
+ gstmplexoutputstream.hh
diff --git a/ext/mplex/gstmplex.cc b/ext/mplex/gstmplex.cc
index 7de9ab56..1ad948af 100644
--- a/ext/mplex/gstmplex.cc
+++ b/ext/mplex/gstmplex.cc
@@ -1,5 +1,7 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+/* GStreamer mplex (mjpegtools) wrapper
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * gstmplex.cc: gstreamer mplex wrapper
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,562 +23,368 @@
#include "config.h"
#endif
-#include <string.h>
-
-#include "gstmplex.h"
-
-#include "videostrm.hh"
-#include "audiostrm.hh"
-
-
-/* elementfactory information */
-static GstElementDetails gst_mplex_details = {
- "MPlex multiplexer",
- "Codec/Muxer",
- "multiplex mpeg audio and video into a system stream",
- "Wim Taymans <wim.taymans@chello.be> ",
-};
-
-/* Sidec signals and args */
-enum {
- /* FILL ME */
- LAST_SIGNAL
-};
-
-enum {
- ARG_0,
- ARG_MUX_FORMAT,
- ARG_MUX_BITRATE,
- ARG_VIDEO_BUFFER,
- ARG_SYNC_OFFSET,
- ARG_SECTOR_SIZE,
- ARG_VBR,
- ARG_PACKETS_PER_PACK,
- ARG_SYSTEM_HEADERS,
- /* FILL ME */
-};
-
-static GstStaticPadTemplate src_factory =
+#include "gstmplex.hh"
+#include "gstmplexoutputstream.hh"
+#include "gstmplexibitstream.hh"
+#include "gstmplexjob.hh"
+
+static GstStaticPadTemplate src_templ =
GST_STATIC_PAD_TEMPLATE (
"src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/mpeg, "
- "mpegversion = (int) [ 1, 2 ], "
+ GST_STATIC_CAPS (
+ "video/mpeg, "
"systemstream = (boolean) true"
)
);
-static GstStaticPadTemplate video_sink_factory =
+static GstStaticPadTemplate video_sink_templ =
GST_STATIC_PAD_TEMPLATE (
"video_%d",
GST_PAD_SINK,
GST_PAD_REQUEST,
- GST_STATIC_CAPS ("video/mpeg, "
+ GST_STATIC_CAPS (
+ "video/mpeg, "
"mpegversion = (int) [ 1, 2 ], "
"systemstream = (boolean) false"
)
);
-
-static GstStaticPadTemplate audio_sink_factory =
+
+static GstStaticPadTemplate audio_sink_templ =
GST_STATIC_PAD_TEMPLATE (
"audio_%d",
GST_PAD_SINK,
GST_PAD_REQUEST,
- GST_STATIC_CAPS ("audio/mpeg, "
+ GST_STATIC_CAPS (
+ "audio/mpeg, "
"mpegversion = (int) 1, "
- "layer = (int) [ 1, 3 ]"
+ "layer = (int) [ 1, 2 ]; "
+ "audio/x-ac3; "
+ "audio/x-dts; "
+ "audio/x-raw-int, "
+ "endianness = (int) BYTE_ORDER, "
+ "signed = (boolean) TRUE, "
+ "width = (int) { 16, 20, 24 }, "
+ "depth = (int) { 16, 20, 24 }, "
+ "rate = (int) { 48000, 96000 }, "
+ "channels = (int) [ 1, 6 ]"
)
);
-static GstStaticPadTemplate private_1_sink_factory =
-GST_STATIC_PAD_TEMPLATE (
- "private_stream_1_%d",
- GST_PAD_SINK,
- GST_PAD_REQUEST,
- GST_STATIC_CAPS ("audio/x-ac3")
-);
+/* FIXME: subtitles */
-static GstStaticPadTemplate private_2_sink_factory =
-GST_STATIC_PAD_TEMPLATE (
- "private_stream_2",
- GST_PAD_SINK,
- GST_PAD_REQUEST,
- GST_STATIC_CAPS_ANY
-);
+static void gst_mplex_base_init (GstMplexClass *klass);
+static void gst_mplex_class_init (GstMplexClass *klass);
+static void gst_mplex_init (GstMplex *enc);
+static void gst_mplex_dispose (GObject *object);
-#define GST_TYPE_MPLEX_MUX_FORMAT (gst_mplex_mux_format_get_type())
-static GType
-gst_mplex_mux_format_get_type (void)
-{
- static GType mplex_mux_format_type = 0;
- static GEnumValue mplex_mux_format[] = {
- { MPEG_FORMAT_MPEG1, "0", "Generic MPEG1" },
- { MPEG_FORMAT_VCD, "1", "VCD" },
- { MPEG_FORMAT_VCD_NSR, "2", "user-rate VCD" },
- { MPEG_FORMAT_MPEG2, "3", "Generic MPEG2" },
- { MPEG_FORMAT_SVCD, "4", "SVCD" },
- { MPEG_FORMAT_SVCD_NSR, "5", "user-rate SVCD" },
- { MPEG_FORMAT_VCD_STILL, "6", "VCD Stills" },
- { MPEG_FORMAT_SVCD_STILL, "7", "SVCD Stills" },
- { MPEG_FORMAT_DVD, "8", "DVD" },
- {0, NULL, NULL},
- };
- if (!mplex_mux_format_type) {
- mplex_mux_format_type = g_enum_register_static("GstMPlexMuxFormat", mplex_mux_format);
- }
- return mplex_mux_format_type;
-}
+static void gst_mplex_loop (GstElement *element);
+
+static GstPad *gst_mplex_request_new_pad (GstElement *element,
+ GstPadTemplate *templ,
+ const gchar *name);
+
+static GstElementStateReturn
+ gst_mplex_change_state (GstElement *element);
-static void gst_mplex_base_init (gpointer g_class);
-static void gst_mplex_class_init (GstMPlex *klass);
-static void gst_mplex_init (GstMPlex *mplex);
-
-static GstPad* gst_mplex_request_new_pad (GstElement *element,
- GstPadTemplate *templ,
- const gchar *req_name);
-static void gst_mplex_loop (GstElement *element);
-static size_t gst_mplex_read_callback (BitStream *bitstream,
- uint8_t *dest, size_t size,
- void *user_data);
-static size_t gst_mplex_write_callback (PS_Stream *stream,
- uint8_t *data, size_t size,
- void *user_data);
-
-static void gst_mplex_get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *pspec);
-static void gst_mplex_set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *pspec);
+static void gst_mplex_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gst_mplex_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
static GstElementClass *parent_class = NULL;
-//static guint gst_mplex_signals[LAST_SIGNAL] = { 0 };
GType
-gst_mplex_get_type (void)
+gst_mplex_get_type (void)
{
- static GType mplex_type = 0;
+ static GType gst_mplex_type = 0;
- if (!mplex_type) {
- static const GTypeInfo mplex_info = {
- sizeof(GstMPlexClass),
- gst_mplex_base_init,
+ if (!gst_mplex_type) {
+ static const GTypeInfo gst_mplex_info = {
+ sizeof (GstMplexClass),
+ (GBaseInitFunc) gst_mplex_base_init,
NULL,
(GClassInitFunc) gst_mplex_class_init,
NULL,
NULL,
- sizeof(GstMPlex),
+ sizeof (GstMplex),
0,
(GInstanceInitFunc) gst_mplex_init,
- NULL
};
- mplex_type = g_type_register_static (GST_TYPE_ELEMENT, "GstMPlex", &mplex_info, (GTypeFlags)0);
+
+ gst_mplex_type =
+ g_type_register_static (GST_TYPE_ELEMENT,
+ "GstMplex",
+ &gst_mplex_info,
+ (GTypeFlags) 0);
}
- return mplex_type;
+ return gst_mplex_type;
}
static void
-gst_mplex_base_init (gpointer g_class)
+gst_mplex_base_init (GstMplexClass *klass)
{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory));
- gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&audio_sink_factory));
- gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&video_sink_factory));
- gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&private_1_sink_factory));
- gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&private_2_sink_factory));
-
- gst_element_class_set_details (element_class, &gst_mplex_details);
+ static GstElementDetails gst_mplex_details = {
+ "mplex video multiplexer",
+ "Codec/Muxer",
+ "High-quality MPEG/DVD/SVCD/VCD video/audio multiplexer",
+ "Andrew Stevens <andrew.stevens@nexgo.de>\n"
+ "Ronald Bultje <rbultje@ronald.bitfreak.net>"
+ };
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_templ));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&video_sink_templ));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&audio_sink_templ));
+ gst_element_class_set_details (element_class,
+ &gst_mplex_details);
}
static void
-gst_mplex_class_init (GstMPlex *klass)
+gst_mplex_class_init (GstMplexClass *klass)
{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass*)klass;
- gstelement_class = (GstElementClass*)klass;
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
parent_class = GST_ELEMENT_CLASS (g_type_class_ref (GST_TYPE_ELEMENT));
- gobject_class->set_property = gst_mplex_set_property;
- gobject_class->get_property = gst_mplex_get_property;
-
- g_object_class_install_property (gobject_class, ARG_MUX_FORMAT,
- g_param_spec_enum ("mux_format", "Mux format", "Set defaults for particular MPEG profiles",
- GST_TYPE_MPLEX_MUX_FORMAT, MPEG_FORMAT_MPEG1, (GParamFlags) G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, ARG_MUX_BITRATE,
- g_param_spec_int ("mux_bitrate", "Mux bitrate", "Specify data rate of output stream in kbit/sec"
- "(0 = Compute from source streams)",
- 0, G_MAXINT, 0, (GParamFlags) G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, ARG_VIDEO_BUFFER,
- g_param_spec_int ("video_buffer", "Video buffer", "Specifies decoder buffers size in kB",
- 20, 2000, 20, (GParamFlags) G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, ARG_SYNC_OFFSET,
- g_param_spec_int ("sync_offset", "Sync offset", "Specify offset of timestamps (video-audio) in mSec",
- G_MININT, G_MAXINT, 0, (GParamFlags) G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, ARG_SECTOR_SIZE,
- g_param_spec_int ("sector_size", "Sector size", "Specify sector size in bytes for generic formats",
- 256, 16384, 2028, (GParamFlags) G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, ARG_VBR,
- g_param_spec_boolean ("vbr", "VBR", "Multiplex variable bit-rate video",
- TRUE, (GParamFlags) G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, ARG_PACKETS_PER_PACK,
- g_param_spec_int ("packets_per_pack", "Packets per pack",
- "Number of packets per pack generic formats",
- 1, 100, 1, (GParamFlags) G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, ARG_SYSTEM_HEADERS,
- g_param_spec_boolean ("system_headers", "System headers",
- " Create System header in every pack in generic formats",
- TRUE, (GParamFlags) G_PARAM_READWRITE));
-
- gstelement_class->request_new_pad = gst_mplex_request_new_pad;
-}
-
-static void
-gst_mplex_init (GstMPlex *mplex)
-{
- mplex->srcpad = gst_pad_new_from_template (
- gst_static_pad_template_get (&src_factory), "src");
- gst_element_add_pad (GST_ELEMENT (mplex), mplex->srcpad);
-
- gst_element_set_loop_function (GST_ELEMENT (mplex), gst_mplex_loop);
+ /* register arguments */
+ mjpeg_default_handler_verbosity (0);
+ GstMplexJob::initProperties (object_class);
- mplex->ostrm = new OutputStream ();
- mplex->strms = new vector<ElementaryStream *>();
+ object_class->set_property = gst_mplex_set_property;
+ object_class->get_property = gst_mplex_get_property;
- mplex->state = GST_MPLEX_OPEN_STREAMS;
+ object_class->dispose = gst_mplex_dispose;
- mplex->ostrm->opt_mux_format = 0;
-
- (void)mjpeg_default_handler_verbosity(mplex->ostrm->opt_verbosity);
+ element_class->change_state = gst_mplex_change_state;
+ element_class->request_new_pad = gst_mplex_request_new_pad;
}
-static GstPadLinkReturn
-gst_mplex_video_link (GstPad *pad, const GstCaps *caps)
-{
- GstMPlex *mplex;
- gint version;
- GstMPlexStream *stream;
- GstStructure *structure;
-
- mplex = GST_MPLEX (gst_pad_get_parent (pad));
-
- stream = (GstMPlexStream *) gst_pad_get_element_private (pad);
-
- structure = gst_caps_get_structure (caps, 0);
-
- if (!gst_structure_get_int (structure, "mpegversion", &version)){
- return GST_PAD_LINK_REFUSED;
- }
+static void
+gst_mplex_dispose (GObject *object)
+{
+ GstMplex *mplex = GST_MPLEX (object);
- if (version == 2) {
- stream->type = GST_MPLEX_STREAM_DVD_VIDEO;
- }
- else {
- stream->type = GST_MPLEX_STREAM_VIDEO;
+ if (mplex->mux) {
+ delete mplex->mux;
+ mplex->mux = NULL;
}
-
- return GST_PAD_LINK_OK;
+ delete mplex->job;
}
-
-static GstPad*
-gst_mplex_request_new_pad (GstElement *element,
- GstPadTemplate *templ,
- const gchar *req_name)
+static void
+gst_mplex_init (GstMplex *mplex)
{
- GstMPlexStream *stream;
- GstMPlex *mplex;
- GstPad *pad = NULL;
+ GstElement *element = GST_ELEMENT (mplex);
- mplex = GST_MPLEX (element);
-
- stream = g_new0 (GstMPlexStream, 1);
+ GST_FLAG_SET (element, GST_ELEMENT_EVENT_AWARE);
- if (!strncmp (templ->name_template, "audio", 5)) {
- gchar *name = g_strdup_printf (templ->name_template, mplex->num_audio);
-
- pad = gst_pad_new (name, GST_PAD_SINK);
- g_free (name);
-
- stream->type = GST_MPLEX_STREAM_MPA;
- }
- else if (!strncmp (templ->name_template, "video", 5)) {
- gchar *name = g_strdup_printf (templ->name_template, mplex->num_video);
+ mplex->srcpad = gst_pad_new_from_template (
+ gst_element_get_pad_template (element, "src"), "src");
+ gst_element_add_pad (element, mplex->srcpad);
- pad = gst_pad_new (name, GST_PAD_SINK);
- /* we still need to figure out the mpeg version */
- gst_pad_set_link_function (pad, gst_mplex_video_link);
- g_free (name);
+ mplex->job = new GstMplexJob ();
+ mplex->mux = NULL;
+ mplex->num_apads = 0;
+ mplex->num_vpads = 0;
- stream->type = GST_MPLEX_STREAM_UNKOWN;
- }
- else if (!strncmp (templ->name_template, "private_stream_1", 16)) {
- gchar *name = g_strdup_printf (templ->name_template, mplex->num_private1);
+ gst_element_set_loop_function (element, gst_mplex_loop);
+}
- pad = gst_pad_new (name, GST_PAD_SINK);
- g_free (name);
+static void
+gst_mplex_loop (GstElement *element)
+{
+ GstMplex *mplex = GST_MPLEX (element);
+
+ if (!mplex->mux) {
+ GstMplexOutputStream *out;
+ const GList *item;
+
+ for (item = gst_element_get_pad_list (element);
+ item != NULL; item = item->next) {
+ StreamKind type;
+ GstMplexIBitStream *inputstream;
+ JobStream *jobstream;
+ GstPad *pad = GST_PAD (item->data);
+ GstStructure *structure;
+ const GstCaps *caps;
+ const gchar *mime;
+
+ /* skip our source pad */
+ if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC)
+ continue;
+
+ /* create inputstream, assure we've got caps */
+ inputstream = new GstMplexIBitStream (pad);
+
+ /* skip unnegotiated pads */
+ if (!(caps = GST_PAD_CAPS (pad))) {
+ delete inputstream;
+ continue;
+ }
- stream->type = GST_MPLEX_STREAM_AC3;
- }
- else if (!strncmp (templ->name_template, "private_stream_2", 16)) {
- pad = gst_pad_new ("private_stream_2", GST_PAD_SINK);
+ /* get format */
+ structure = gst_caps_get_structure (caps, 0);
+ mime = gst_structure_get_name (structure);
+
+ if (!strcmp (mime, "video/mpeg")) {
+ VideoParams *params;
+
+ type = MPEG_VIDEO;
+
+ params = VideoParams::Default (mplex->job->mux_format);
+ mplex->job->video_param.push_back (params);
+ mplex->job->video_tracks++;
+ } else if (!strcmp (mime, "audio/mpeg")) {
+ type = MPEG_AUDIO;
+ mplex->job->audio_tracks++;
+ } else if (!strcmp (mime, "audio/x-ac3")) {
+ type = AC3_AUDIO;
+ mplex->job->audio_tracks++;
+ } else if (!strcmp (mime, "audio/x-dts")) {
+ type = DTS_AUDIO;
+ mplex->job->audio_tracks++;
+ } else if (!strcmp (mime, "audio/x-raw-int")) {
+ LpcmParams *params;
+ gint bits, chans, rate;
+
+ type = LPCM_AUDIO;
+
+ /* set LPCM params */
+ gst_structure_get_int (structure, "depth", &bits);
+ gst_structure_get_int (structure, "rate", &rate);
+ gst_structure_get_int (structure, "channels", &chans);
+ params = LpcmParams::Checked (rate, chans, bits);
+
+ mplex->job->lpcm_param.push_back (params);
+ mplex->job->audio_tracks++;
+ mplex->job->lpcm_tracks++;
+ } else {
+ delete inputstream;
+ continue;
+ }
- stream->type = GST_MPLEX_STREAM_UNKOWN;
- }
-
- if (pad) {
- stream->pad = pad;
- stream->bitstream = new IBitStream();
- stream->bytestream = gst_bytestream_new (pad);
- stream->eos = FALSE;
+ jobstream = new JobStream (inputstream, type);
+ mplex->job->streams.push_back (jobstream);
+ }
- mplex->streams = g_list_prepend (mplex->streams, stream);
+ if (!mplex->job->video_tracks && !mplex->job->audio_tracks) {
+ gst_element_error (element,
+ "No input stream set-up");
+ return;
+ }
- gst_element_add_pad (element, pad);
- gst_pad_set_element_private (pad, stream);
- }
- else {
- /* no pad, free our stream again */
- g_free (stream);
+ /* create new encoder with inputs/output */
+ out = new GstMplexOutputStream (element, mplex->srcpad);
+ mplex->mux = new Multiplexor (*mplex->job, *out);
}
- return pad;
+ mplex->mux->Multiplex ();
}
-
-static size_t
-gst_mplex_read_callback (BitStream *bitstream, uint8_t *dest, size_t size, void *user_data)
+static GstPadLinkReturn
+gst_mplex_sink_link (GstPad *pad,
+ const GstCaps *caps)
{
- GstMPlexStream *stream;
- guint8 *data;
- guint32 len;
-
- stream = (GstMPlexStream *) user_data;
-
- if (stream->eos)
- return 0;
-
- do {
- len = gst_bytestream_peek_bytes (stream->bytestream, &data, size);
- if (len < size) {
- guint32 avail= 0;
- GstEvent *event = NULL;
-
- gst_bytestream_get_status (stream->bytestream, &avail, &event);
- if (event != NULL) {
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- stream->eos = TRUE;
- break;
- default:
- break;
- }
- gst_event_unref (event);
- }
- }
- }
- while (len == 0);
-
- memcpy (dest, data, len);
-
- gst_bytestream_flush_fast (stream->bytestream, len);
-
- return len;
-}
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+ const gchar *mime = gst_structure_get_name (structure);
-static size_t
-gst_mplex_write_callback (PS_Stream *stream, uint8_t *data, size_t size, void *user_data)
-{
- GstMPlex *mplex;
- GstBuffer *outbuf;
+ /* raw audio caps needs to be fixed */
+ if (!strcmp (mime, "audio/x-raw-int")) {
+ gint width, depth;
- mplex = GST_MPLEX (user_data);
+ if (!gst_caps_is_fixed (caps))
+ return GST_PAD_LINK_DELAYED;
- if (GST_PAD_IS_USABLE (mplex->srcpad)) {
- outbuf = gst_buffer_new_and_alloc (size);
- memcpy (GST_BUFFER_DATA (outbuf), data, size);
+ gst_structure_get_int (structure, "width", &width);
+ gst_structure_get_int (structure, "depth", &depth);
- gst_pad_push (mplex->srcpad, GST_DATA (outbuf));
+ if (depth != width)
+ return GST_PAD_LINK_REFUSED;
}
- return size;
+ /* we do the actual inputstream setup in our first loopfunc cycle */
+g_print ("Pad %s linked with caps %s\n",
+ gst_pad_get_name (pad),
+ gst_caps_to_string (caps));
+ return GST_PAD_LINK_OK;
}
-static void
-gst_mplex_loop (GstElement *element)
+static GstPad *
+gst_mplex_request_new_pad (GstElement *element,
+ GstPadTemplate *templ,
+ const gchar *name)
{
- GstMPlex *mplex;
-
- mplex = GST_MPLEX (element);
-
- switch (mplex->state) {
- case GST_MPLEX_OPEN_STREAMS:
- {
- mplex->ostrm->InitSyntaxParameters();
-
- GList *walk = mplex->streams;
- while (walk) {
- GstMPlexStream *stream = (GstMPlexStream *) walk->data;
-
- stream->bitstream->open (gst_mplex_read_callback, stream);
-
- switch (stream->type) {
- case GST_MPLEX_STREAM_MPA:
- {
- MPAStream *mpastream;
-
- mpastream = new MPAStream(*stream->bitstream, *mplex->ostrm);
- mpastream->Init(0);
- stream->elem_stream = mpastream;
- break;
- }
- case GST_MPLEX_STREAM_AC3:
- {
- AC3Stream *ac3stream;
-
- ac3stream = new AC3Stream(*stream->bitstream, *mplex->ostrm);
- ac3stream->Init(0);
- stream->elem_stream = ac3stream;
- break;
- }
- case GST_MPLEX_STREAM_DVD_VIDEO:
- {
- DVDVideoStream *dvdstream;
-
- dvdstream = new DVDVideoStream(*stream->bitstream, *mplex->ostrm);
- dvdstream->Init(0);
- stream->elem_stream = dvdstream;
- break;
- }
- case GST_MPLEX_STREAM_VIDEO:
- {
- VideoStream *videostream;
-
- videostream = new VideoStream(*stream->bitstream, *mplex->ostrm);
- videostream->Init(0);
- stream->elem_stream = videostream;
- break;
- }
- default:
- break;
- }
- mplex->strms->push_back(stream->elem_stream);
-
- walk = g_list_next (walk);
- }
-
- mplex->ps_stream = new PS_Stream (gst_mplex_write_callback, mplex);
- mplex->ostrm->Init (mplex->strms, mplex->ps_stream);
-
- /* move to running state after this */
- mplex->state = GST_MPLEX_RUN;
- break;
- }
- case GST_MPLEX_RUN:
- if (!mplex->ostrm->OutputMultiplex()) {
- mplex->state = GST_MPLEX_END;
- }
- break;
- case GST_MPLEX_END:
- {
- mplex->ostrm->Close ();
- gst_pad_push (mplex->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
- gst_element_set_eos (element);
- break;
- }
- default:
- break;
+ GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
+ GstMplex *mplex = GST_MPLEX (element);
+ gchar *padname;
+ GstPad *newpad;
+
+ if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
+ padname = g_strdup_printf ("audio_%d", mplex->num_apads++);
+ } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
+ padname = g_strdup_printf ("video_%d", mplex->num_vpads++);
+ } else {
+ g_warning ("mplex: this is not our template!");
+ return NULL;
}
+ newpad = gst_pad_new_from_template (templ, padname);
+ gst_pad_set_link_function (newpad, gst_mplex_sink_link);
+ gst_element_add_pad (element, newpad);
+ g_free (padname);
+
+ return newpad;
}
-static void
-gst_mplex_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+static void
+gst_mplex_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- GstMPlex *mplex;
-
- mplex = GST_MPLEX(object);
-
- switch(prop_id) {
- case ARG_MUX_FORMAT:
- mplex->ostrm->opt_mux_format = g_value_get_enum (value);
- break;
- case ARG_MUX_BITRATE:
- mplex->data_rate = g_value_get_int (value);
- mplex->ostrm->opt_data_rate = ((mplex->data_rate * 1000 / 8 + 49) / 50) * 50;
- break;
- case ARG_VIDEO_BUFFER:
- mplex->ostrm->opt_buffer_size = g_value_get_int (value);
- break;
- case ARG_SYNC_OFFSET:
- {
- mplex->sync_offset = g_value_get_int (value);
- if (mplex->sync_offset < 0) {
- mplex->ostrm->opt_audio_offset = -mplex->sync_offset;
- mplex->ostrm->opt_video_offset = 0;
- }
- else {
- mplex->ostrm->opt_video_offset = mplex->sync_offset;
- }
- break;
- }
- case ARG_SECTOR_SIZE:
- mplex->ostrm->opt_sector_size = g_value_get_int (value);
- break;
- case ARG_VBR:
- mplex->ostrm->opt_VBR = g_value_get_boolean (value);
- break;
- case ARG_PACKETS_PER_PACK:
- mplex->ostrm->opt_packets_per_pack = g_value_get_int (value);
- break;
- case ARG_SYSTEM_HEADERS:
- mplex->ostrm->opt_always_system_headers = g_value_get_boolean (value);
- break;
- default:
- //G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- return;
- }
+ GST_MPLEX (object)->job->getProperty (prop_id, value);
}
-static void
-gst_mplex_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+static void
+gst_mplex_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- GstMPlex *mplex;
-
- mplex = GST_MPLEX(object);
+ GST_MPLEX (object)->job->setProperty (prop_id, value);
+}
- switch(prop_id) {
- case ARG_MUX_FORMAT:
- g_value_set_enum (value, mplex->ostrm->opt_mux_format);
- break;
- case ARG_MUX_BITRATE:
- g_value_set_int (value, mplex->data_rate);
- break;
- case ARG_VIDEO_BUFFER:
- g_value_set_int (value, mplex->ostrm->opt_buffer_size);
- break;
- case ARG_SYNC_OFFSET:
- g_value_set_int (value, mplex->sync_offset);
- break;
- case ARG_SECTOR_SIZE:
- g_value_set_int (value, mplex->ostrm->opt_sector_size);
- break;
- case ARG_VBR:
- g_value_set_boolean (value, mplex->ostrm->opt_VBR);
- break;
- case ARG_PACKETS_PER_PACK:
- g_value_set_int (value, mplex->ostrm->opt_packets_per_pack);
- break;
- case ARG_SYSTEM_HEADERS:
- g_value_set_boolean (value, mplex->ostrm->opt_always_system_headers);
+static GstElementStateReturn
+gst_mplex_change_state (GstElement *element)
+{
+ GstMplex *mplex = GST_MPLEX (element);
+
+ switch (GST_STATE_TRANSITION (element)) {
+ case GST_STATE_PAUSED_TO_READY:
+ delete mplex->mux;
+ mplex->mux = NULL;
+ mplex->num_apads = 0;
+ mplex->num_vpads = 0;
break;
default:
- //G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
+
+ if (parent_class->change_state)
+ return parent_class->change_state (element);
+
+ return GST_STATE_SUCCESS;
}
static gboolean
@@ -585,20 +393,19 @@ plugin_init (GstPlugin *plugin)
if (!gst_library_load ("gstbytestream"))
return FALSE;
- if (!gst_element_register (plugin, "mplex", GST_RANK_NONE, GST_TYPE_MPLEX))
- return FALSE;
-
- return TRUE;
+ return gst_element_register (plugin, "mplex",
+ GST_RANK_NONE,
+ GST_TYPE_MPLEX);
}
GST_PLUGIN_DEFINE (
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"mplex",
- "MPlexs an audio and video stream into a system stream",
+ "High-quality MPEG/DVD/SVCD/VCD video/audio multiplexer",
plugin_init,
VERSION,
- "LGPL",
+ "GPL",
GST_PACKAGE,
- GST_ORIGIN)
-
+ GST_ORIGIN
+)
diff --git a/ext/mplex/gstmplex.h b/ext/mplex/gstmplex.h
deleted file mode 100644
index 20107252..00000000
--- a/ext/mplex/gstmplex.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- *
- * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-#ifndef __GST_MPLEX_H__
-#define __GST_MPLEX_H__
-
-
-#include <stdlib.h>
-
-#include <gst/gst.h>
-#include <gst/bytestream/bytestream.h>
-
-#include "outputstream.hh"
-#include "bits.hh"
-
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_MPLEX \
- (gst_mplex_get_type())
-#define GST_MPLEX(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MPLEX,GstMPlex))
-#define GST_MPLEX_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MPLEX,GstMPlex))
-#define GST_IS_MPLEX(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MPLEX))
-#define GST_IS_MPLEX_CLASS(obj) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MPLEX))
-
-typedef enum {
- GST_MPLEX_INIT,
- GST_MPLEX_OPEN_STREAMS,
- GST_MPLEX_RUN,
- GST_MPLEX_END
-} GstMPlexState;
-
-typedef enum {
- GST_MPLEX_STREAM_UNKOWN,
- GST_MPLEX_STREAM_AC3,
- GST_MPLEX_STREAM_MPA,
- GST_MPLEX_STREAM_LPCM,
- GST_MPLEX_STREAM_VIDEO,
- GST_MPLEX_STREAM_DVD_VIDEO,
-} GstMPlexStreamType;
-
-typedef struct _GstMPlex GstMPlex;
-typedef struct _GstMPlexStream GstMPlexStream;
-typedef struct _GstMPlexClass GstMPlexClass;
-
-struct _GstMPlexStream {
- IBitStream *bitstream;
- ElementaryStream *elem_stream;
- GstPad *pad;
- GstMPlexStreamType type;
- GstByteStream *bytestream;
- gboolean eos;
-};
-
-struct _GstMPlex {
- GstElement element;
-
- GstMPlexState state;
- /* pads */
- GstPad *srcpad;
- GList *streams;
-
- vector<ElementaryStream *> *strms;
- OutputStream *ostrm;
- PS_Stream *ps_stream;
- gint data_rate;
- gint sync_offset;
-
- gint num_video;
- gint num_audio;
- gint num_private1;
-};
-
-struct _GstMPlexClass {
- GstElementClass parent_class;
-};
-
-GType gst_mplex_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_MPLEX_H__ */
diff --git a/ext/mplex/gstmplex.hh b/ext/mplex/gstmplex.hh
new file mode 100644
index 00000000..e8497ed6
--- /dev/null
+++ b/ext/mplex/gstmplex.hh
@@ -0,0 +1,64 @@
+/* GStreamer mplex (mjpegtools) wrapper
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * gstmplex.hh: gstreamer mplex wrapper
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_MPLEX_H__
+#define __GST_MPLEX_H__
+
+#include <gst/gst.h>
+#include <multiplexor.hpp>
+#include "gstmplexjob.hh"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MPLEX \
+ (gst_mplex_get_type ())
+#define GST_MPLEX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MPLEX, GstMplex))
+#define GST_MPLEX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MPLEX, GstMplex))
+#define GST_IS_MPLEX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MPLEX))
+#define GST_IS_MPLEX_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MPLEX))
+
+typedef struct _GstMplex {
+ GstElement parent;
+
+ /* pads */
+ GstPad *sinkpad, *srcpad;
+ guint num_apads, num_vpads;
+
+ /* options wrapper */
+ GstMplexJob *job;
+
+ /* general muxing object (contains rest) */
+ Multiplexor *mux;
+} GstMplex;
+
+typedef struct _GstMplexClass {
+ GstElementClass parent;
+} GstMplexClass;
+
+GType gst_mplex_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_MPLEX_H__ */
diff --git a/ext/mplex/gstmplexibitstream.cc b/ext/mplex/gstmplexibitstream.cc
new file mode 100644
index 00000000..59f913a6
--- /dev/null
+++ b/ext/mplex/gstmplexibitstream.cc
@@ -0,0 +1,112 @@
+/* GStreamer mplex (mjpegtools) wrapper
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * gstmplexibitstream.hh: gstreamer/mplex input bitstream wrapper
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstmplexibitstream.hh"
+
+/*
+ * Class init/exit functions.
+ */
+
+GstMplexIBitStream::GstMplexIBitStream (GstPad *_pad,
+ guint buf_size) :
+ IBitStream ()
+{
+ guint8 *data;
+
+ pad = _pad;
+ bs = gst_bytestream_new (pad);
+ eos = FALSE;
+
+ streamname = g_strdup (gst_pad_get_name (_pad));
+
+ SetBufSize (buf_size);
+ eobs = false;
+ byteidx = 0;
+
+ /* we peek 1 byte (not even caring about the return value) so we
+ * are sure that we have data and thus capsnego must be completed
+ * when we return. */
+ gst_bytestream_peek_bytes (bs, &data, 1);
+
+ if (!ReadIntoBuffer () && buffered == 0) {
+ gst_element_error (gst_pad_get_parent (_pad),
+ "Failed to read from input stream %s",
+ gst_pad_get_name (pad));
+ }
+}
+
+GstMplexIBitStream::~GstMplexIBitStream (void)
+{
+ gst_bytestream_destroy (bs);
+}
+
+/*
+ * Read data.
+ */
+
+size_t
+GstMplexIBitStream::ReadStreamBytes (uint8_t *buf,
+ size_t size)
+{
+ guint8 *data;
+ guint read;
+
+ if (eos)
+ return 0;
+
+ if ((read = gst_bytestream_peek_bytes (bs, &data, size)) != size) {
+ GstEvent *event;
+ guint pending;
+
+ gst_bytestream_get_status (bs, &pending, &event);
+ if (event) {
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ eos = TRUE;
+ break;
+ default:
+ break;
+ }
+ gst_event_unref (event);
+ }
+ }
+
+ memcpy (buf, data, read);
+ gst_bytestream_flush_fast (bs, read);
+
+ return read;
+}
+
+/*
+ * Are we at EOS?
+ */
+
+bool
+GstMplexIBitStream::EndOfStream (void)
+{
+ return eos;
+}
diff --git a/ext/mplex/gstmplexibitstream.hh b/ext/mplex/gstmplexibitstream.hh
new file mode 100644
index 00000000..504835a4
--- /dev/null
+++ b/ext/mplex/gstmplexibitstream.hh
@@ -0,0 +1,50 @@
+/* GStreamer mplex (mjpegtools) wrapper
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * gstmplexibitstream.hh: gstreamer/mplex input bitstream wrapper
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_MPLEXIBITSTREAM_H__
+#define __GST_MPLEXIBITSTREAM_H__
+
+#include <gst/gst.h>
+#include <gst/bytestream/bytestream.h>
+#include <mjpeg_types.h>
+#include <bits.hpp>
+
+class GstMplexIBitStream : public IBitStream {
+public:
+ GstMplexIBitStream (GstPad *pad,
+ guint buf_size = BUFFER_SIZE);
+ ~GstMplexIBitStream (void);
+
+protected:
+ /* read data */
+ size_t ReadStreamBytes (uint8_t *buf,
+ size_t number);
+
+ /* are we at EOS? */
+ bool EndOfStream (void);
+
+private:
+ GstPad *pad;
+ GstByteStream *bs;
+ gboolean eos;
+};
+
+#endif /* __GST_MPLEXIBITSTREAM_H__ */
diff --git a/ext/mplex/gstmplexjob.cc b/ext/mplex/gstmplexjob.cc
new file mode 100644
index 00000000..058ff9a4
--- /dev/null
+++ b/ext/mplex/gstmplexjob.cc
@@ -0,0 +1,232 @@
+/* GStreamer mplex (mjpegtools) wrapper
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * gstmplexjob.hh: gstreamer/mplex multiplex-job wrapper
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstmplexjob.hh"
+
+
+enum {
+ ARG_0,
+ ARG_FORMAT,
+ ARG_MUX_BITRATE,
+ ARG_VBR,
+ ARG_SYSTEM_HEADERS,
+ ARG_SPLIT_SEQUENCE,
+ ARG_SEGMENT_SIZE,
+ ARG_PACKETS_PER_PACK,
+ ARG_SECTOR_SIZE,
+ ARG_WORKAROUND_MPLAYER_HDR
+ /* FILL ME */
+};
+
+/*
+ * Property enumeration types.
+ */
+
+#define GST_TYPE_MPLEX_FORMAT \
+ (gst_mplex_format_get_type ())
+
+static GType
+gst_mplex_format_get_type (void)
+{
+ static GType mplex_format_type = 0;
+
+ if (!mplex_format_type) {
+ static const GEnumValue mplex_formats[] = {
+ { 0, "0", "Generic MPEG-1" },
+ { 1, "1", "Standard VCD" },
+ { 2, "2", "User VCD" },
+ { 3, "3", "Generic MPEG-2" },
+ { 4, "4", "Standard SVCD" },
+ { 5, "5", "User SVCD" },
+ { 6, "6", "VCD Stills sequences" },
+ { 7, "7", "SVCD Stills sequences" },
+ { 8, "8", "DVD MPEG-2 for dvdauthor" },
+ { 9, "9", "DVD MPEG-2" },
+ { 0, NULL, NULL },
+ };
+
+ mplex_format_type =
+ g_enum_register_static ("GstMplexFormat",
+ mplex_formats);
+ }
+
+ return mplex_format_type;
+}
+
+/*
+ * Class init functions.
+ */
+
+GstMplexJob::GstMplexJob (void) :
+ MultiplexJob ()
+{
+ /* blabla */
+}
+
+/*
+ * GObject properties.
+ */
+
+void
+GstMplexJob::initProperties (GObjectClass *klass)
+{
+ /* encoding profile */
+ g_object_class_install_property (klass, ARG_FORMAT,
+ g_param_spec_enum ("format", "Format", "Encoding profile format",
+ GST_TYPE_MPLEX_FORMAT, 0,
+ (GParamFlags) G_PARAM_READWRITE));
+
+ /* total stream datarate. Normally, this shouldn't be needed, but
+ * some DVD/VCD/SVCD players really need strict values to handle
+ * the created files correctly. */
+ g_object_class_install_property (klass, ARG_MUX_BITRATE,
+ g_param_spec_int ("mux-bitrate", "Mux. bitrate",
+ "Bitrate of output stream in kbps (0 = autodetect)",
+ 0, 15 * 1024, 0, (GParamFlags) G_PARAM_READWRITE));
+
+#if 0
+ { "video-buffer", 1, 0, 'b' },
+#endif
+
+ /* some boolean stuff for headers */
+ g_object_class_install_property (klass, ARG_VBR,
+ g_param_spec_boolean ("vbr", "VBR",
+ "Whether the input video stream is variable bitrate",
+ FALSE, (GParamFlags) G_PARAM_READWRITE));
+ g_object_class_install_property (klass, ARG_SYSTEM_HEADERS,
+ g_param_spec_boolean ("system-headers", "System headers",
+ "Create system header in every pack for generic formats",
+ FALSE, (GParamFlags) G_PARAM_READWRITE));
+ g_object_class_install_property (klass, ARG_SPLIT_SEQUENCE,
+ g_param_spec_boolean ("split-sequence", "Split sequence",
+ "Simply split a sequence across files "
+ "(rather than building run-out/run-in)",
+ FALSE, (GParamFlags) G_PARAM_READWRITE));
+
+ /* size of a segment (followed by EOS) */
+ g_object_class_install_property (klass, ARG_SEGMENT_SIZE,
+ g_param_spec_int ("max-segment-size", "Max. segment size",
+ "Max. size per segment/file in MB (0 = unlimited)",
+ 0, 10 * 1024, 0, (GParamFlags) G_PARAM_READWRITE));
+
+ /* packets per pack (generic formats) */
+ g_object_class_install_property (klass, ARG_PACKETS_PER_PACK,
+ g_param_spec_int ("packets-per-pack", "Packets per pack",
+ "Number of packets per pack for generic formats",
+ 1, 100, 1, (GParamFlags) G_PARAM_READWRITE));
+
+ /* size of one sector */
+ g_object_class_install_property (klass, ARG_SECTOR_SIZE,
+ g_param_spec_int ("sector-size", "Sector size",
+ "Specify sector size in bytes for generic formats",
+ 256, 16384, 2048, (GParamFlags) G_PARAM_READWRITE));
+
+ /* workarounds */
+ g_object_class_install_property (klass, ARG_WORKAROUND_MPLAYER_HDR,
+ g_param_spec_boolean ("mplayer-hdr-workaround", "MPlayer header workaround",
+ "Enable a workaround for bugs in MPlayer LCPM header parsing",
+ FALSE, (GParamFlags) G_PARAM_READWRITE));
+}
+
+/*
+ * set/get gobject properties.
+ */
+
+void
+GstMplexJob::getProperty (guint prop_id,
+ GValue *value)
+{
+ switch (prop_id) {
+ case ARG_FORMAT:
+ g_value_set_enum (value, mux_format);
+ break;
+ case ARG_MUX_BITRATE:
+ g_value_set_int (value, data_rate / 1000);
+ break;
+ case ARG_VBR:
+ g_value_set_boolean (value, VBR);
+ break;
+ case ARG_SYSTEM_HEADERS:
+ g_value_set_boolean (value, always_system_headers);
+ break;
+ case ARG_SPLIT_SEQUENCE:
+ g_value_set_boolean (value, multifile_segment);
+ break;
+ case ARG_SEGMENT_SIZE:
+ g_value_set_int (value, max_segment_size);
+ break;
+ case ARG_PACKETS_PER_PACK:
+ g_value_set_int (value, packets_per_pack);
+ break;
+ case ARG_SECTOR_SIZE:
+ g_value_set_int (value, sector_size);
+ break;
+ case ARG_WORKAROUND_MPLAYER_HDR:
+ g_value_set_boolean (value, workarounds.mplayer_pes_headers);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+GstMplexJob::setProperty (guint prop_id,
+ const GValue *value)
+{
+ switch (prop_id) {
+ case ARG_FORMAT:
+ mux_format = g_value_get_enum (value);
+ break;
+ case ARG_MUX_BITRATE:
+ /* data_rate expects bytes (don't ask me why the property itself is
+ * in bits, I'm just staying compatible to mjpegtools options), and
+ * rounded up to 50-bytes. */
+ data_rate = ((g_value_get_int (value) * 1000 / 8 + 49) / 50 ) * 50;
+ break;
+ case ARG_VBR:
+ VBR = g_value_get_boolean (value);
+ break;
+ case ARG_SYSTEM_HEADERS:
+ always_system_headers = g_value_get_boolean (value);
+ break;
+ case ARG_SPLIT_SEQUENCE:
+ multifile_segment = g_value_get_boolean (value);
+ break;
+ case ARG_SEGMENT_SIZE:
+ max_segment_size = g_value_get_int (value);
+ break;
+ case ARG_PACKETS_PER_PACK:
+ packets_per_pack = g_value_get_int (value);
+ break;
+ case ARG_SECTOR_SIZE:
+ sector_size = g_value_get_int (value);
+ break;
+ case ARG_WORKAROUND_MPLAYER_HDR:
+ workarounds.mplayer_pes_headers = g_value_get_boolean (value);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/ext/mplex/gstmplexjob.hh b/ext/mplex/gstmplexjob.hh
new file mode 100644
index 00000000..8aa5b14d
--- /dev/null
+++ b/ext/mplex/gstmplexjob.hh
@@ -0,0 +1,42 @@
+/* GStreamer mplex (mjpegtools) wrapper
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * gstmplexjob.hh: gstreamer/mplex multiplex-job wrapper
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_MPLEXJOB_H__
+#define __GST_MPLEXJOB_H__
+
+#include <glib-object.h>
+#include <interact.hpp>
+
+class GstMplexJob : public MultiplexJob {
+public:
+ GstMplexJob (void);
+
+ /* gobject properties */
+ static void initProperties (GObjectClass *klass);
+
+ /* set/get gobject properties */
+ void getProperty (guint prop_id,
+ GValue *value);
+ void setProperty (guint prop_id,
+ const GValue *value);
+};
+
+#endif /* __GST_MPLEXJOB_H__ */
diff --git a/ext/mplex/gstmplexoutputstream.cc b/ext/mplex/gstmplexoutputstream.cc
new file mode 100644
index 00000000..c0a2976d
--- /dev/null
+++ b/ext/mplex/gstmplexoutputstream.cc
@@ -0,0 +1,101 @@
+/* GStreamer mplex (mjpegtools) wrapper
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * gstmplexoutputstream.hh: gstreamer/mplex output stream wrapper
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "gstmplexoutputstream.hh"
+
+/*
+ * Class init functions.
+ */
+
+GstMplexOutputStream::GstMplexOutputStream (GstElement *_element,
+ GstPad *_pad) :
+ OutputStream ()
+{
+ element = _element;
+ pad = _pad;
+ size = 0;
+}
+
+/*
+ * Open/close. Basically 'no-op's (close() sets EOS).
+ *
+ * Open (): -1 means failure, 0 means success.
+ */
+
+int
+GstMplexOutputStream::Open (void)
+{
+ return 0;
+}
+
+void
+GstMplexOutputStream::Close (void)
+{
+ gst_pad_push (pad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
+ gst_element_set_eos (element);
+}
+
+/*
+ * Get size of current segment.
+ */
+
+off_t
+GstMplexOutputStream::SegmentSize (void)
+{
+ return size;
+}
+
+/*
+ * Next segment.
+ */
+
+void
+GstMplexOutputStream::NextSegment (void)
+{
+ size = 0;
+
+ /* send EOS. The filesink (or whatever) handles that
+ * and opens a new file. */
+ gst_pad_push (pad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
+}
+
+/*
+ * Write data.
+ */
+
+void
+GstMplexOutputStream::Write (guint8 *data,
+ guint len)
+{
+ GstBuffer *buf;
+
+ buf = gst_buffer_new_and_alloc (len);
+ memcpy (GST_BUFFER_DATA (buf), data, len);
+
+ size += len;
+ gst_pad_push (pad, GST_DATA (buf));
+}
diff --git a/ext/mplex/gstmplexoutputstream.hh b/ext/mplex/gstmplexoutputstream.hh
new file mode 100644
index 00000000..c67040b7
--- /dev/null
+++ b/ext/mplex/gstmplexoutputstream.hh
@@ -0,0 +1,54 @@
+/* GStreamer mplex (mjpegtools) wrapper
+ * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * gstmplexoutputstream.hh: gstreamer/mplex output stream wrapper
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_MPLEXOUTPUTSTREAM_H__
+#define __GST_MPLEXOUTPUTSTREAM_H__
+
+#include <gst/gst.h>
+#include <mjpeg_types.h>
+#include <outputstrm.hpp>
+
+class GstMplexOutputStream : public OutputStream {
+public:
+ GstMplexOutputStream (GstElement *element,
+ GstPad *pad);
+
+ /* open/close. Basically 'no-op's (close() sets EOS). */
+ int Open (void);
+ void Close (void);
+
+ /* get size of current segment */
+ off_t SegmentSize (void);
+
+ /* next segment */
+ void NextSegment (void);
+
+ /* write data */
+ void Write (guint8 *data,
+ guint len);
+
+private:
+ GstElement *element;
+ GstPad *pad;
+ guint64 size;
+};
+
+#endif /* __GST_MPLEXOUTPUTSTREAM_H__ */