summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
Diffstat (limited to 'gst')
-rw-r--r--gst/mpegtsmux/Makefile.am17
-rw-r--r--gst/mpegtsmux/mpegtsmux.c821
-rw-r--r--gst/mpegtsmux/mpegtsmux.h163
-rw-r--r--gst/mpegtsmux/mpegtsmux_aac.c151
-rw-r--r--gst/mpegtsmux/mpegtsmux_aac.h91
-rw-r--r--gst/mpegtsmux/mpegtsmux_h264.c197
-rw-r--r--gst/mpegtsmux/mpegtsmux_h264.h91
-rw-r--r--gst/mpegtsmux/tsmux/Makefile.am8
-rw-r--r--gst/mpegtsmux/tsmux/crc.h58
-rw-r--r--gst/mpegtsmux/tsmux/tsmux.c1056
-rw-r--r--gst/mpegtsmux/tsmux/tsmux.h183
-rw-r--r--gst/mpegtsmux/tsmux/tsmuxcommon.h175
-rw-r--r--gst/mpegtsmux/tsmux/tsmuxstream.c692
-rw-r--r--gst/mpegtsmux/tsmux/tsmuxstream.h217
14 files changed, 3920 insertions, 0 deletions
diff --git a/gst/mpegtsmux/Makefile.am b/gst/mpegtsmux/Makefile.am
new file mode 100644
index 00000000..a1d76139
--- /dev/null
+++ b/gst/mpegtsmux/Makefile.am
@@ -0,0 +1,17 @@
+plugin_LTLIBRARIES = libgstmpegtsmux.la
+
+SUBDIRS = tsmux
+
+libgstmpegtsmux_la_SOURCES = \
+ mpegtsmux.c \
+ mpegtsmux_h264.c \
+ mpegtsmux_aac.c
+
+libgstmpegtsmux_la_CFLAGS = $(GST_CFLAGS)
+libgstmpegtsmux_la_LIBADD = $(top_builddir)/gst/mpegtsmux/tsmux/libtsmux.la $(GST_LIBS) $(GST_BASE_LIBS)
+libgstmpegtsmux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = \
+ mpegtsmux.h \
+ mpegtsmux_h264.h \
+ mpegtsmux_aac.h
diff --git a/gst/mpegtsmux/mpegtsmux.c b/gst/mpegtsmux/mpegtsmux.c
new file mode 100644
index 00000000..8013b51a
--- /dev/null
+++ b/gst/mpegtsmux/mpegtsmux.c
@@ -0,0 +1,821 @@
+/*
+ * Copyright 2006, 2007, 2008 Fluendo S.A.
+ * Authors: Jan Schmidt <jan@fluendo.com>
+ * Kapil Agrawal <kapil@fluendo.com>
+ * Julien Moutte <julien@fluendo.com>
+ *
+ * This library is licensed under 4 different licenses and you
+ * can choose to use it under the terms of any one of them. The
+ * four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
+ * license.
+ *
+ * MPL:
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * LGPL:
+ *
+ * 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.
+ *
+ * GPL:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * MIT:
+ *
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+
+#include "mpegtsmux.h"
+
+#include "mpegtsmux_h264.h"
+#include "mpegtsmux_aac.h"
+
+GST_DEBUG_CATEGORY (mpegtsmux_debug);
+#define GST_CAT_DEFAULT mpegtsmux_debug
+
+enum
+{
+ ARG_0,
+ ARG_M2TS_MODE
+};
+
+static GstStaticPadTemplate mpegtsmux_sink_factory =
+ GST_STATIC_PAD_TEMPLATE ("sink_%d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_STATIC_CAPS ("video/mpeg, mpegversion=(int) { 1, 2 }, "
+ "systemstream = (boolean) false; "
+ "video/x-dirac;"
+ "video/x-h264;" "audio/mpeg, mpegversion = (int) { 1, 2, 4 }")
+ );
+
+static GstStaticPadTemplate mpegtsmux_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/mpegts, "
+ "systemstream = (boolean) true, " "packetsize = (int) { 188, 192} ")
+ );
+
+static void gst_mpegtsmux_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_mpegtsmux_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void mpegtsmux_dispose (GObject * object);
+static gboolean new_packet_cb (guint8 * data, guint len, void *user_data,
+ gint64 new_pcr);
+static void release_buffer_cb (guint8 * data, void *user_data);
+
+static gboolean mpegtsdemux_prepare_srcpad (MpegTsMux * mux);
+static GstFlowReturn mpegtsmux_collected (GstCollectPads * pads,
+ MpegTsMux * mux);
+static GstPad *mpegtsmux_request_new_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * name);
+static void mpegtsmux_release_pad (GstElement * element, GstPad * pad);
+static GstStateChangeReturn mpegtsmux_change_state (GstElement * element,
+ GstStateChange transition);
+
+GST_BOILERPLATE (MpegTsMux, mpegtsmux, GstElement, GST_TYPE_ELEMENT);
+
+static void
+mpegtsmux_base_init (gpointer g_class)
+{
+ const GstElementDetails mpegtsmux_details = {
+ "MPEG Transport Stream Muxer",
+ "Codec/Muxer",
+ "Multiplexes media streams into an MPEG Transport Stream",
+ "Fluendo <contact@fluendo.com>"
+ };
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&mpegtsmux_sink_factory));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&mpegtsmux_src_factory));
+
+ gst_element_class_set_details (element_class, &mpegtsmux_details);
+}
+
+static void
+mpegtsmux_class_init (MpegTsMuxClass * klass)
+{
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_mpegtsmux_set_property);
+ gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_mpegtsmux_get_property);
+ gobject_class->dispose = mpegtsmux_dispose;
+
+ gstelement_class->request_new_pad = mpegtsmux_request_new_pad;
+ gstelement_class->release_pad = mpegtsmux_release_pad;
+ gstelement_class->change_state = mpegtsmux_change_state;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_M2TS_MODE,
+ g_param_spec_boolean ("m2ts_mode", "M2TS(192 bytes) Mode",
+ "Defines what packet size to use, normal TS format ie .ts(188 bytes) "
+ "or Blue-Ray disc ie .m2ts(192 bytes).", FALSE, G_PARAM_READWRITE));
+
+}
+
+static void
+mpegtsmux_init (MpegTsMux * mux, MpegTsMuxClass * g_class)
+{
+ mux->srcpad =
+ gst_pad_new_from_template (gst_static_pad_template_get
+ (&mpegtsmux_src_factory), "src");
+ gst_pad_use_fixed_caps (mux->srcpad);
+ gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
+
+ mux->collect = gst_collect_pads_new ();
+ gst_collect_pads_set_function (mux->collect,
+ (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (mpegtsmux_collected), mux);
+
+ mux->tsmux = tsmux_new ();
+ tsmux_set_write_func (mux->tsmux, new_packet_cb, mux);
+ mux->program = tsmux_program_new (mux->tsmux);
+
+ mux->first = TRUE;
+ mux->last_flow_ret = GST_FLOW_OK;
+ mux->adapter = gst_adapter_new ();
+ mux->m2ts_mode = FALSE;
+ mux->first_pcr = TRUE;
+ mux->last_ts = 0;
+}
+
+static void
+mpegtsmux_dispose (GObject * object)
+{
+ MpegTsMux *mux = GST_MPEG_TSMUX (object);
+
+ if (mux->adapter) {
+ gst_adapter_clear (mux->adapter);
+ gst_object_unref (mux->adapter);
+ mux->adapter = NULL;
+ }
+ if (mux->collect) {
+ gst_object_unref (mux->collect);
+ mux->collect = NULL;
+ }
+ if (mux->tsmux) {
+ tsmux_free (mux->tsmux);
+ mux->tsmux = NULL;
+ }
+
+ GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static void
+gst_mpegtsmux_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ MpegTsMux *mux = GST_MPEG_TSMUX (object);
+
+ switch (prop_id) {
+ case ARG_M2TS_MODE:
+ /*set incase if the output stream need to be of 192 bytes */
+ mux->m2ts_mode = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_mpegtsmux_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ MpegTsMux *mux = GST_MPEG_TSMUX (object);
+
+ switch (prop_id) {
+ case ARG_M2TS_MODE:
+ g_value_set_boolean (value, mux->m2ts_mode);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+release_buffer_cb (guint8 * data, void *user_data)
+{
+ GstBuffer *buf = (GstBuffer *) user_data;
+ gst_buffer_unref (buf);
+}
+
+static GstFlowReturn
+mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data, GstPad * pad)
+{
+ GstFlowReturn ret = GST_FLOW_ERROR;
+ GstCaps *caps = gst_pad_get_negotiated_caps (pad);
+ GstStructure *s;
+
+ if (caps == NULL) {
+ GST_DEBUG_OBJECT (pad, "Sink pad caps were not set before pushing");
+ return GST_FLOW_NOT_NEGOTIATED;
+ }
+
+ s = gst_caps_get_structure (caps, 0);
+ g_return_val_if_fail (s != NULL, FALSE);
+
+ if (gst_structure_has_name (s, "video/x-dirac")) {
+ GST_DEBUG_OBJECT (pad, "Creating Dirac stream with PID 0x%04x",
+ ts_data->pid);
+ ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_VIDEO_DIRAC,
+ ts_data->pid);
+ } else if (gst_structure_has_name (s, "video/x-h264")) {
+ const GValue *value;
+ GST_DEBUG_OBJECT (pad, "Creating H264 stream with PID 0x%04x",
+ ts_data->pid);
+ /* Codec data contains SPS/PPS which need to go in stream for valid ES */
+ value = gst_structure_get_value (s, "codec_data");
+ if (value) {
+ ts_data->codec_data = gst_buffer_ref (gst_value_get_buffer (value));
+ GST_DEBUG_OBJECT (pad, "we have additional codec data (%d bytes)",
+ GST_BUFFER_SIZE (ts_data->codec_data));
+ ts_data->prepare_func = mpegtsmux_prepare_h264;
+ } else {
+ ts_data->codec_data = NULL;
+ }
+ ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_VIDEO_H264,
+ ts_data->pid);
+ } else if (gst_structure_has_name (s, "audio/mpeg")) {
+ gint mpegversion;
+ if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) {
+ GST_ELEMENT_ERROR (pad, STREAM, FORMAT,
+ ("Invalid data format presented"),
+ ("Caps with type audio/mpeg did not have mpegversion"));
+ goto beach;
+ }
+
+ switch (mpegversion) {
+ case 1:
+ GST_DEBUG_OBJECT (pad, "Creating MPEG Audio, version 1 stream with "
+ "PID 0x%04x", ts_data->pid);
+ ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_AUDIO_MPEG1,
+ ts_data->pid);
+ break;
+ case 2:
+ GST_DEBUG_OBJECT (pad, "Creating MPEG Audio, version 2 stream with "
+ "PID 0x%04x", ts_data->pid);
+ ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_AUDIO_MPEG2,
+ ts_data->pid);
+ break;
+ case 4:
+ {
+ const GValue *value;
+ /* Codec data contains SPS/PPS which need to go in stream for valid ES */
+ value = gst_structure_get_value (s, "codec_data");
+ if (value) {
+ ts_data->codec_data = gst_buffer_ref (gst_value_get_buffer (value));
+ GST_DEBUG_OBJECT (pad, "we have additional codec data (%d bytes)",
+ GST_BUFFER_SIZE (ts_data->codec_data));
+ ts_data->prepare_func = mpegtsmux_prepare_aac;
+ } else {
+ ts_data->codec_data = NULL;
+ }
+ GST_DEBUG_OBJECT (pad, "Creating MPEG Audio, version 4 stream with "
+ "PID 0x%04x", ts_data->pid);
+ ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_AUDIO_AAC,
+ ts_data->pid);
+ break;
+ }
+ default:
+ GST_WARNING_OBJECT (pad, "unsupported mpegversion %d", mpegversion);
+ goto beach;
+ }
+ } else if (gst_structure_has_name (s, "video/mpeg")) {
+ gint mpegversion;
+ if (!gst_structure_get_int (s, "mpegversion", &mpegversion)) {
+ GST_ELEMENT_ERROR (mux, STREAM, FORMAT,
+ ("Invalid data format presented"),
+ ("Caps with type video/mpeg did not have mpegversion"));
+ goto beach;
+ }
+
+ if (mpegversion == 1) {
+ GST_DEBUG_OBJECT (pad,
+ "Creating MPEG Video, version 1 stream with PID 0x%04x",
+ ts_data->pid);
+ ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_VIDEO_MPEG1,
+ ts_data->pid);
+ } else {
+ GST_DEBUG_OBJECT (pad,
+ "Creating MPEG Video, version 2 stream with PID 0x%04x",
+ ts_data->pid);
+ ts_data->stream = tsmux_create_stream (mux->tsmux, TSMUX_ST_VIDEO_MPEG2,
+ ts_data->pid);
+ }
+ }
+
+ if (ts_data->stream != NULL) {
+ tsmux_stream_set_buffer_release_func (ts_data->stream, release_buffer_cb);
+ tsmux_program_add_stream (mux->program, ts_data->stream);
+
+ ret = GST_FLOW_OK;
+ }
+
+beach:
+ return ret;
+}
+
+static GstFlowReturn
+mpegtsmux_create_streams (MpegTsMux * mux)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GSList *walk = mux->collect->data;
+
+ /* Create the streams */
+ while (walk) {
+ GstCollectData *c_data = (GstCollectData *) walk->data;
+ MpegTsPadData *ts_data = (MpegTsPadData *) walk->data;
+
+ walk = g_slist_next (walk);
+
+ if (ts_data->stream == NULL) {
+ ret = mpegtsmux_create_stream (mux, ts_data, c_data->pad);
+ if (ret != GST_FLOW_OK)
+ goto no_stream;
+ }
+ }
+
+ return GST_FLOW_OK;
+no_stream:
+ GST_ELEMENT_ERROR (mux, STREAM, MUX,
+ ("Could not create handler for stream"), (NULL));
+ return ret;
+}
+
+static MpegTsPadData *
+mpegtsmux_choose_best_stream (MpegTsMux * mux)
+{
+ MpegTsPadData *best = NULL;
+ GSList *walk;
+
+ for (walk = mux->collect->data; walk != NULL; walk = g_slist_next (walk)) {
+ GstCollectData *c_data = (GstCollectData *) walk->data;
+ MpegTsPadData *ts_data = (MpegTsPadData *) walk->data;
+
+ if (ts_data->eos == FALSE) {
+ if (ts_data->queued_buf == NULL) {
+ GstBuffer *buf;
+
+ ts_data->queued_buf = buf = gst_collect_pads_pop (mux->collect, c_data);
+
+ if (buf != NULL) {
+ if (ts_data->prepare_func) {
+ buf = ts_data->prepare_func (buf, ts_data, mux);
+ if (buf) { /* Take the prepared buffer instead */
+ gst_buffer_unref (ts_data->queued_buf);
+ ts_data->queued_buf = buf;
+ } else { /* If data preparation returned NULL, use unprepared one */
+ buf = ts_data->queued_buf;
+ }
+ }
+ if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
+ /* Ignore timestamps that go backward for now. FIXME: Handle all
+ * incoming PTS */
+ if (ts_data->last_ts == GST_CLOCK_TIME_NONE ||
+ ts_data->last_ts < GST_BUFFER_TIMESTAMP (buf)) {
+ ts_data->cur_ts = ts_data->last_ts =
+ gst_segment_to_running_time (&c_data->segment,
+ GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf));
+ } else {
+ GST_DEBUG_OBJECT (mux, "Ignoring PTS that has gone backward");
+ }
+ } else
+ ts_data->cur_ts = GST_CLOCK_TIME_NONE;
+
+ GST_DEBUG_OBJECT (mux, "Pulled buffer with ts %" GST_TIME_FORMAT
+ " (uncorrected ts %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
+ ") for PID 0x%04x",
+ GST_TIME_ARGS (ts_data->cur_ts),
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
+ GST_BUFFER_TIMESTAMP (buf), ts_data->pid);
+
+ /* Choose a stream we've never seen a timestamp for to ensure
+ * we push enough buffers from it to reach a timestamp */
+ if (ts_data->last_ts == GST_CLOCK_TIME_NONE)
+ best = ts_data;
+ } else {
+ ts_data->eos = TRUE;
+ continue;
+ }
+ }
+
+ /* If we don't yet have a best pad, take this one, otherwise take
+ * whichever has the oldest timestamp */
+ if (best != NULL) {
+ if (ts_data->last_ts != GST_CLOCK_TIME_NONE &&
+ best->last_ts != GST_CLOCK_TIME_NONE &&
+ ts_data->last_ts < best->last_ts) {
+ best = ts_data;
+ }
+ } else {
+ best = ts_data;
+ }
+ }
+ }
+
+ return best;
+}
+
+static GstFlowReturn
+mpegtsmux_collected (GstCollectPads * pads, MpegTsMux * mux)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ MpegTsPadData *best = NULL;
+
+ GST_DEBUG_OBJECT (mux, "Pads collected");
+
+ if (mux->first) {
+ ret = mpegtsmux_create_streams (mux);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ return ret;
+
+ best = mpegtsmux_choose_best_stream (mux);
+
+ if (mux->pcr_stream == NULL) {
+ if (best) {
+ GstCollectData *c_data = (GstCollectData *) best;
+ /* Take the first data stream for the PCR */
+ GST_DEBUG_OBJECT (mux, "Use stream from pad %" GST_PTR_FORMAT " as PCR",
+ c_data->pad);
+ mux->pcr_stream = best->stream;
+ }
+ }
+
+ /* Set the chosen PCR stream */
+ g_return_val_if_fail (mux->pcr_stream != NULL, GST_FLOW_ERROR);
+ tsmux_program_set_pcr_stream (mux->program, mux->pcr_stream);
+
+ if (!mpegtsdemux_prepare_srcpad (mux)) {
+ GST_DEBUG_OBJECT (mux, "Failed to send new segment");
+ goto new_seg_fail;
+ }
+
+ mux->first = FALSE;
+ } else {
+ best = mpegtsmux_choose_best_stream (mux);
+ }
+
+ if (best != NULL) {
+ GstBuffer *buf = best->queued_buf;
+ GstCollectData *c_data = (GstCollectData *) best;
+ gint64 pts = -1;
+
+ g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
+
+ GST_DEBUG_OBJECT (mux,
+ "Chose stream from pad %" GST_PTR_FORMAT " for output (PID: 0x%04x)",
+ c_data->pad, best->pid);
+
+ if (GST_CLOCK_TIME_IS_VALID (best->cur_ts)) {
+ pts = GSTTIME_TO_MPEGTIME (best->cur_ts);
+ GST_DEBUG_OBJECT (mux, "Buffer has TS %" GST_TIME_FORMAT " pts %"
+ G_GINT64_FORMAT, GST_TIME_ARGS (best->cur_ts), pts);
+ }
+
+ tsmux_stream_add_data (best->stream, GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf), buf, pts, -1);
+ best->queued_buf = NULL;
+
+ while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
+ if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
+ GST_DEBUG_OBJECT (mux, "Failed to write data packet");
+ goto write_fail;
+ }
+ }
+ if (mux->pcr_stream == best->stream) {
+ mux->last_ts = best->last_ts;
+ }
+ } else {
+ /* FIXME: Drain all remaining streams */
+ /* At EOS */
+ gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
+ }
+
+ return ret;
+new_seg_fail:
+ return GST_FLOW_ERROR;
+write_fail:
+ /* FIXME: Failed writing data for some reason. Should set appropriate error */
+ return mux->last_flow_ret;
+}
+
+static GstPad *
+mpegtsmux_request_new_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * name)
+{
+ MpegTsMux *mux = GST_MPEG_TSMUX (element);
+ gint pid = -1;
+ gchar *pad_name = NULL;
+ GstPad *pad = NULL;
+ MpegTsPadData *pad_data = NULL;
+
+ if (name != NULL && sscanf (name, "sink_%d", &pid) == 1) {
+ if (tsmux_find_stream (mux->tsmux, pid))
+ goto stream_exists;
+ } else {
+ pid = tsmux_get_new_pid (mux->tsmux);
+ }
+
+ pad_name = g_strdup_printf ("sink_%d", pid);
+ pad = gst_pad_new_from_template (templ, pad_name);
+ g_free (pad_name);
+
+ pad_data = (MpegTsPadData *) gst_collect_pads_add_pad (mux->collect, pad,
+ sizeof (MpegTsPadData));
+ if (pad_data == NULL)
+ goto pad_failure;
+
+ pad_data->pid = pid;
+ pad_data->last_ts = GST_CLOCK_TIME_NONE;
+ pad_data->codec_data = NULL;
+ pad_data->prepare_func = NULL;
+
+ if (G_UNLIKELY (!gst_element_add_pad (element, pad)))
+ goto could_not_add;
+
+ return pad;
+
+stream_exists:
+ GST_ELEMENT_ERROR (element, STREAM, MUX, ("Duplicate PID requested"), (NULL));
+ return NULL;
+
+could_not_add:
+ GST_ELEMENT_ERROR (element, STREAM, FAILED,
+ ("Internal data stream error."), ("Could not add pad to element"));
+ gst_collect_pads_remove_pad (mux->collect, pad);
+ gst_object_unref (pad);
+ return NULL;
+pad_failure:
+ GST_ELEMENT_ERROR (element, STREAM, FAILED,
+ ("Internal data stream error."), ("Could not add pad to collectpads"));
+ gst_object_unref (pad);
+ return NULL;
+}
+
+static void
+mpegtsmux_release_pad (GstElement * element, GstPad * pad)
+{
+ MpegTsMux *mux = GST_MPEG_TSMUX (element);
+ MpegTsPadData *pad_data = NULL;
+
+ GST_DEBUG_OBJECT (mux, "Pad %" GST_PTR_FORMAT " being released", pad);
+
+ /* Get the MpegTsPadData out of the pad */
+ GST_OBJECT_LOCK (pad);
+ pad_data = (MpegTsPadData *) gst_pad_get_element_private (pad);
+ if (G_LIKELY (pad_data)) {
+ /* Free codec data reference if any */
+ if (pad_data->codec_data) {
+ GST_DEBUG_OBJECT (element, "releasing codec_data reference");
+ gst_buffer_unref (pad_data->codec_data);
+ pad_data->codec_data = NULL;
+ }
+ }
+ GST_OBJECT_UNLOCK (pad);
+
+ gst_collect_pads_remove_pad (mux->collect, pad);
+}
+
+static gboolean
+new_packet_cb (guint8 * data, guint len, void *user_data, gint64 new_pcr)
+{
+ /* Called when the TsMux has prepared a packet for output. Return FALSE
+ * on error */
+ MpegTsMux *mux = (MpegTsMux *) user_data;
+ GstBuffer *buf, *out_buf;
+ GstFlowReturn ret;
+ gfloat current_ts;
+ gint64 m2ts_pcr, pcr_bytes, chunk_bytes;
+ gint8 *temp_ptr;
+ gint64 ts_rate;
+
+ if (mux->m2ts_mode == TRUE) {
+ /* Enters when the m2ts-mode is set true */
+ buf = gst_buffer_new_and_alloc (M2TS_PACKET_LENGTH);
+ if (G_UNLIKELY (buf == NULL)) {
+ mux->last_flow_ret = GST_FLOW_ERROR;
+ return FALSE;
+ }
+ /* copies the ts data of 188 bytes to the m2ts buffer at an offset
+ of 4 bytes of timestamp */
+ memcpy (GST_BUFFER_DATA (buf) + 4, data, len);
+
+ if (new_pcr >= 0) {
+ /*when there is a pcr value in ts data */
+ pcr_bytes = 0;
+ if (mux->first_pcr) {
+ /*Incase of first pcr */
+ /*writing the 4 byte timestamp value */
+ GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf), new_pcr);
+
+ GST_LOG_OBJECT (mux, "Outputting a packet of length %d",
+ M2TS_PACKET_LENGTH);
+ ret = gst_pad_push (mux->srcpad, buf);
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ mux->last_flow_ret = ret;
+ return FALSE;
+ }
+ mux->first_pcr = FALSE;
+ mux->previous_pcr = new_pcr;
+ pcr_bytes = M2TS_PACKET_LENGTH;
+ }
+ chunk_bytes = gst_adapter_available (mux->adapter);
+
+ if (G_UNLIKELY (chunk_bytes)) {
+ /* calculate rate based on latest and previous pcr values */
+ ts_rate = ((chunk_bytes * STANDARD_TIME_CLOCK) / (new_pcr -
+ mux->previous_pcr));
+ while (1) {
+ /*loop till all the accumulated ts packets are transformed to
+ m2ts packets and pushed */
+ current_ts = ((gfloat) mux->previous_pcr / STANDARD_TIME_CLOCK) +
+ ((gfloat) pcr_bytes / ts_rate);
+ m2ts_pcr = (((gint64) (STANDARD_TIME_CLOCK * current_ts / 300) &
+ TWO_POW_33_MINUS1) * 300) + ((gint64) (STANDARD_TIME_CLOCK *
+ current_ts) % 300);
+ temp_ptr = (gint8 *) & m2ts_pcr;
+
+ out_buf = gst_adapter_take_buffer (mux->adapter, M2TS_PACKET_LENGTH);
+ if (G_UNLIKELY (!out_buf))
+ break;
+
+ /*writing the 4 byte timestamp value */
+ GST_WRITE_UINT32_BE (GST_BUFFER_DATA (out_buf), m2ts_pcr);
+
+ GST_LOG_OBJECT (mux, "Outputting a packet of length %d",
+ M2TS_PACKET_LENGTH);
+ ret = gst_pad_push (mux->srcpad, out_buf);
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ mux->last_flow_ret = ret;
+ return FALSE;
+ }
+ pcr_bytes += M2TS_PACKET_LENGTH;
+ }
+ mux->previous_pcr = m2ts_pcr;
+ }
+ } else
+ /* If theres no pcr in current ts packet then push the packet
+ to an adapter, which is used to create m2ts packets */
+ gst_adapter_push (mux->adapter, buf);
+ } else {
+ /* In case of Normal Ts packets */
+ GST_LOG_OBJECT (mux, "Outputting a packet of length %d", len);
+ buf = gst_buffer_new_and_alloc (len);
+ if (G_UNLIKELY (buf == NULL)) {
+ mux->last_flow_ret = GST_FLOW_ERROR;
+ return FALSE;
+ }
+
+ memcpy (GST_BUFFER_DATA (buf), data, len);
+ GST_BUFFER_TIMESTAMP (buf) = mux->last_ts;
+ ret = gst_pad_push (mux->srcpad, buf);
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ mux->last_flow_ret = ret;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+mpegtsdemux_prepare_srcpad (MpegTsMux * mux)
+{
+ GstEvent *new_seg =
+ gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0);
+ GstCaps *caps = gst_caps_new_simple ("video/mpegts",
+ "systemstream", G_TYPE_BOOLEAN, TRUE,
+ "packetsize", G_TYPE_INT,
+ (mux->m2ts_mode ? M2TS_PACKET_LENGTH : NORMAL_TS_PACKET_LENGTH),
+ NULL);
+
+// gst_static_pad_template_get_caps (&mpegtsmux_src_factory);
+
+ /* Set caps on src pad from our template and push new segment */
+ gst_pad_set_caps (mux->srcpad, caps);
+
+ if (!gst_pad_push_event (mux->srcpad, new_seg)) {
+ GST_WARNING_OBJECT (mux, "New segment event was not handled");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GstStateChangeReturn
+mpegtsmux_change_state (GstElement * element, GstStateChange transition)
+{
+ MpegTsMux *mux = GST_MPEG_TSMUX (element);
+ GstStateChangeReturn ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ gst_collect_pads_start (mux->collect);
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_collect_pads_stop (mux->collect);
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ if (mux->adapter)
+ gst_adapter_clear (mux->adapter);
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "mpegtsmux", GST_RANK_PRIMARY,
+ mpegtsmux_get_type ()))
+ return FALSE;
+
+ GST_DEBUG_CATEGORY_INIT (mpegtsmux_debug, "mpegtsmux", 0,
+ "MPEG Transport Stream muxer");
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
+ "mpegtsmux", "MPEG-TS muxer",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/mpegtsmux/mpegtsmux.h b/gst/mpegtsmux/mpegtsmux.h
new file mode 100644
index 00000000..bb46d475
--- /dev/null
+++ b/gst/mpegtsmux/mpegtsmux.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2006, 2007, 2008 Fluendo S.A.
+ * Authors: Jan Schmidt <jan@fluendo.com>
+ * Kapil Agrawal <kapil@fluendo.com>
+ * Julien Moutte <julien@fluendo.com>
+ *
+ * This library is licensed under 4 different licenses and you
+ * can choose to use it under the terms of any one of them. The
+ * four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
+ * license.
+ *
+ * MPL:
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * LGPL:
+ *
+ * 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.
+ *
+ * GPL:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * MIT:
+ *
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef __MPEGTSMUX_H__
+#define __MPEGTSMUX_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstcollectpads.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#include <tsmux/tsmux.h>
+
+#define GST_TYPE_MPEG_TSMUX (mpegtsmux_get_type())
+#define GST_MPEG_TSMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_MPEG_TSMUX, MpegTsMux))
+
+typedef struct MpegTsMux MpegTsMux;
+typedef struct MpegTsMuxClass MpegTsMuxClass;
+typedef struct MpegTsPadData MpegTsPadData;
+
+typedef GstBuffer * (*MpegTsPadDataPrepareFunction) (GstBuffer * buf,
+ MpegTsPadData * data, MpegTsMux * mux);
+
+struct MpegTsMux {
+ GstElement parent;
+
+ GstPad *srcpad;
+
+ GstCollectPads *collect;
+
+ TsMux *tsmux;
+ TsMuxProgram *program;
+
+ gboolean first;
+ TsMuxStream *pcr_stream;
+ GstFlowReturn last_flow_ret;
+ GstAdapter *adapter;
+ gint64 previous_pcr;
+ gboolean m2ts_mode;
+ gboolean first_pcr;
+
+ GstClockTime last_ts;
+};
+
+struct MpegTsMuxClass {
+ GstElementClass parent_class;
+};
+
+struct MpegTsPadData {
+ GstCollectData collect; /* Parent */
+
+ gint pid;
+ TsMuxStream *stream;
+
+ GstBuffer *queued_buf; /* Currently pulled buffer */
+ GstClockTime cur_ts; /* Adjusted TS for the pulled buffer */
+ GstClockTime last_ts; /* Most recent valid TS for this stream */
+
+ GstBuffer * codec_data; /* Optional codec data available in the caps */
+
+ MpegTsPadDataPrepareFunction prepare_func; /* Handler to prepare input data */
+
+ gboolean eos;
+};
+
+GType mpegtsmux_get_type (void);
+
+#define CLOCK_BASE 9LL
+#define CLOCK_FREQ (CLOCK_BASE * 10000)
+
+#define MPEGTIME_TO_GSTTIME(time) (gst_util_uint64_scale ((time), \
+ GST_MSECOND/10, CLOCK_BASE))
+#define GSTTIME_TO_MPEGTIME(time) (gst_util_uint64_scale ((time), \
+ CLOCK_BASE, GST_MSECOND/10))
+
+#define NORMAL_TS_PACKET_LENGTH 188
+#define M2TS_PACKET_LENGTH 192
+#define STANDARD_TIME_CLOCK 27000000
+/*33 bits as 1 ie 0x1ffffffff*/
+#define TWO_POW_33_MINUS1 ((0xffffffff * 2) - 1)
+G_END_DECLS
+
+#endif
diff --git a/gst/mpegtsmux/mpegtsmux_aac.c b/gst/mpegtsmux/mpegtsmux_aac.c
new file mode 100644
index 00000000..71727f21
--- /dev/null
+++ b/gst/mpegtsmux/mpegtsmux_aac.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2006, 2007, 2008 Fluendo S.A.
+ * Authors: Jan Schmidt <jan@fluendo.com>
+ * Kapil Agrawal <kapil@fluendo.com>
+ * Julien Moutte <julien@fluendo.com>
+ *
+ * This library is licensed under 4 different licenses and you
+ * can choose to use it under the terms of any one of them. The
+ * four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
+ * license.
+ *
+ * MPL:
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * LGPL:
+ *
+ * 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.
+ *
+ * GPL:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * MIT:
+ *
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mpegtsmux_aac.h"
+#include <string.h>
+
+GST_DEBUG_CATEGORY_EXTERN (mpegtsmux_debug);
+#define GST_CAT_DEFAULT mpegtsmux_debug
+
+GstBuffer *
+mpegtsmux_prepare_aac (GstBuffer * buf, MpegTsPadData * data, MpegTsMux * mux)
+{
+ guint8 *adts_header = g_malloc0 (7);
+ GstBuffer *out_buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) + 7);
+ gsize out_offset = 0;
+ guint8 rate_idx = 0, channels = 0, obj_type = 0;
+
+ GST_DEBUG_OBJECT (mux, "Preparing AAC buffer for output");
+
+ /* We want the same metadata */
+ gst_buffer_copy_metadata (out_buf, buf, GST_BUFFER_COPY_ALL);
+
+ /* Generate ADTS header */
+ obj_type = (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data)) & 0xC) >> 2;
+ obj_type++;
+ rate_idx = (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data)) & 0x3) << 1;
+ rate_idx |=
+ (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + 1) & 0x80) >> 7;
+ channels =
+ (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + 1) & 0x78) >> 3;
+ GST_DEBUG_OBJECT (mux, "Rate index %u, channels %u, object type %u", rate_idx,
+ channels, obj_type);
+ /* Sync point over a full byte */
+ adts_header[0] = 0xFF;
+ /* Sync point continued over first 4 bits + static 4 bits
+ * (ID, layer, protection)*/
+ adts_header[1] = 0xF1;
+ /* Object type over first 2 bits */
+ adts_header[2] = obj_type << 6;
+ /* rate index over next 4 bits */
+ adts_header[2] |= (rate_idx << 2);
+ /* channels over last 2 bits */
+ adts_header[2] |= (channels & 0x4) >> 2;
+ /* channels continued over next 2 bits + 4 bits at zero */
+ adts_header[3] = (channels & 0x3) << 6;
+ /* frame size over last 2 bits */
+ adts_header[3] |= (GST_BUFFER_SIZE (out_buf) & 0x1800) >> 11;
+ /* frame size continued over full byte */
+ adts_header[4] = (GST_BUFFER_SIZE (out_buf) & 0x1FF8) >> 3;
+ /* frame size continued first 3 bits */
+ adts_header[5] = (GST_BUFFER_SIZE (out_buf) & 0x7) << 5;
+ /* buffer fullness (0x7FF for VBR) over 5 last bits */
+ adts_header[5] |= 0x1F;
+ /* buffer fullness (0x7FF for VBR) continued over 6 first bits + 2 zeros for
+ * number of raw data blocks */
+ adts_header[6] = 0xFC;
+
+ /* Insert ADTS header */
+ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, adts_header, 7);
+ g_free (adts_header);
+ out_offset += 7;
+
+ /* Now copy complete frame */
+ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, GST_BUFFER_DATA (buf),
+ GST_BUFFER_SIZE (buf));
+
+ return out_buf;
+}
diff --git a/gst/mpegtsmux/mpegtsmux_aac.h b/gst/mpegtsmux/mpegtsmux_aac.h
new file mode 100644
index 00000000..1e898b7a
--- /dev/null
+++ b/gst/mpegtsmux/mpegtsmux_aac.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2006, 2007, 2008 Fluendo S.A.
+ * Authors: Jan Schmidt <jan@fluendo.com>
+ * Kapil Agrawal <kapil@fluendo.com>
+ * Julien Moutte <julien@fluendo.com>
+ *
+ * This library is licensed under 4 different licenses and you
+ * can choose to use it under the terms of any one of them. The
+ * four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
+ * license.
+ *
+ * MPL:
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * LGPL:
+ *
+ * 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.
+ *
+ * GPL:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * MIT:
+ *
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef __MPEGTSMUX_AAC_H__
+#define __MPEGTSMUX_AAC_H__
+
+#include "mpegtsmux.h"
+
+GstBuffer * mpegtsmux_prepare_aac (GstBuffer * buf, MpegTsPadData * data,
+ MpegTsMux * mux);
+
+#endif /* __MPEGTSMUX_AAC_H__ */
diff --git a/gst/mpegtsmux/mpegtsmux_h264.c b/gst/mpegtsmux/mpegtsmux_h264.c
new file mode 100644
index 00000000..5824f358
--- /dev/null
+++ b/gst/mpegtsmux/mpegtsmux_h264.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2006, 2007, 2008 Fluendo S.A.
+ * Authors: Jan Schmidt <jan@fluendo.com>
+ * Kapil Agrawal <kapil@fluendo.com>
+ * Julien Moutte <julien@fluendo.com>
+ *
+ * This library is licensed under 4 different licenses and you
+ * can choose to use it under the terms of any one of them. The
+ * four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
+ * license.
+ *
+ * MPL:
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * LGPL:
+ *
+ * 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.
+ *
+ * GPL:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * MIT:
+ *
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mpegtsmux_h264.h"
+#include <string.h>
+
+GST_DEBUG_CATEGORY_EXTERN (mpegtsmux_debug);
+#define GST_CAT_DEFAULT mpegtsmux_debug
+
+GstBuffer *
+mpegtsmux_prepare_h264 (GstBuffer * buf, MpegTsPadData * data, MpegTsMux * mux)
+{
+ guint8 nal_length_size = 0;
+ guint8 startcode[4] = { 0x00, 0x00, 0x00, 0x01 };
+ GstBuffer *out_buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) * 2);
+ gint offset = 4, i = 0, nb_sps = 0, nb_pps = 0;
+ gsize out_offset = 0, in_offset = 0;
+
+ GST_DEBUG_OBJECT (mux, "Preparing H264 buffer for output");
+
+ /* We want the same metadata */
+ gst_buffer_copy_metadata (out_buf, buf, GST_BUFFER_COPY_ALL);
+
+ /* Get NAL length size */
+ nal_length_size =
+ (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + offset) & 0x03) + 1;
+ GST_LOG_OBJECT (mux, "NAL length will be coded on %u bytes", nal_length_size);
+ offset++;
+
+ /* Generate SPS */
+ nb_sps = GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + offset) & 0x1f;
+ GST_DEBUG_OBJECT (mux, "we have %d Sequence Parameter Set", nb_sps);
+ offset++;
+
+ /* For each SPS */
+ for (i = 0; i < nb_sps; i++) {
+ guint16 sps_size =
+ GST_READ_UINT16_BE (GST_BUFFER_DATA (data->codec_data) + offset);
+
+ GST_LOG_OBJECT (mux, "Sequence Parameter Set is %d bytes", sps_size);
+
+ /* Jump over SPS size */
+ offset += 2;
+
+ /* Fake a start code */
+ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, startcode, 4);
+ out_offset += 4;
+ /* Now push the SPS */
+ memcpy (GST_BUFFER_DATA (out_buf) + out_offset,
+ GST_BUFFER_DATA (data->codec_data) + offset, sps_size);
+
+ out_offset += sps_size;
+ offset += sps_size;
+ }
+
+ nb_pps = GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + offset);
+ GST_LOG_OBJECT (mux, "we have %d Picture Parameter Set", nb_sps);
+ offset++;
+
+ /* For each PPS */
+ for (i = 0; i < nb_pps; i++) {
+ gint pps_size =
+ GST_READ_UINT16_BE (GST_BUFFER_DATA (data->codec_data) + offset);
+
+ GST_LOG_OBJECT (mux, "Picture Parameter Set is %d bytes", pps_size);
+
+ /* Jump over PPS size */
+ offset += 2;
+
+ /* Fake a start code */
+ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, startcode, 4);
+ out_offset += 4;
+ /* Now push the PPS */
+ memcpy (GST_BUFFER_DATA (out_buf) + out_offset,
+ GST_BUFFER_DATA (data->codec_data) + offset, pps_size);
+
+ out_offset += pps_size;
+ offset += pps_size;
+ }
+
+ while (in_offset < GST_BUFFER_SIZE (buf) &&
+ out_offset < GST_BUFFER_SIZE (out_buf) - 4) {
+ guint32 nal_size = 0;
+
+ switch (nal_length_size) {
+ case 1:
+ nal_size = GST_READ_UINT8 (GST_BUFFER_DATA (buf) + in_offset);
+ break;
+ case 2:
+ nal_size = GST_READ_UINT16_BE (GST_BUFFER_DATA (buf) + in_offset);
+ break;
+ case 4:
+ nal_size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf) + in_offset);
+ break;
+ default:
+ GST_WARNING_OBJECT (mux, "unsupported NAL length size %u",
+ nal_length_size);
+ }
+ in_offset += nal_length_size;
+
+ /* Generate an Elementary stream buffer by inserting a startcode */
+ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, startcode, 4);
+ out_offset += 4;
+ memcpy (GST_BUFFER_DATA (out_buf) + out_offset,
+ GST_BUFFER_DATA (buf) + in_offset,
+ MIN (nal_size, GST_BUFFER_SIZE (out_buf) - out_offset));
+ in_offset += nal_size;
+ out_offset += nal_size;
+ }
+
+ GST_BUFFER_SIZE (out_buf) = out_offset;
+
+ return out_buf;
+}
diff --git a/gst/mpegtsmux/mpegtsmux_h264.h b/gst/mpegtsmux/mpegtsmux_h264.h
new file mode 100644
index 00000000..be5692a0
--- /dev/null
+++ b/gst/mpegtsmux/mpegtsmux_h264.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2006, 2007, 2008 Fluendo S.A.
+ * Authors: Jan Schmidt <jan@fluendo.com>
+ * Kapil Agrawal <kapil@fluendo.com>
+ * Julien Moutte <julien@fluendo.com>
+ *
+ * This library is licensed under 4 different licenses and you
+ * can choose to use it under the terms of any one of them. The
+ * four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
+ * license.
+ *
+ * MPL:
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * LGPL:
+ *
+ * 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.
+ *
+ * GPL:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * MIT:
+ *
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef __MPEGTSMUX_H264_H__
+#define __MPEGTSMUX_H264_H__
+
+#include "mpegtsmux.h"
+
+GstBuffer * mpegtsmux_prepare_h264 (GstBuffer * buf, MpegTsPadData * data,
+ MpegTsMux * mux);
+
+#endif /* __MPEGTSMUX_H264_H__ */
diff --git a/gst/mpegtsmux/tsmux/Makefile.am b/gst/mpegtsmux/tsmux/Makefile.am
new file mode 100644
index 00000000..e995cf7c
--- /dev/null
+++ b/gst/mpegtsmux/tsmux/Makefile.am
@@ -0,0 +1,8 @@
+noinst_LTLIBRARIES = libtsmux.la
+
+libtsmux_la_CFLAGS = $(GST_CFLAGS)
+libtsmux_la_LIBADD = $(GST_LIBS)
+libtsmux_la_LDFLAGS = -module -avoid-version
+libtsmux_la_SOURCES = tsmux.c tsmuxstream.c
+
+noinst_HEADERS = crc.h tsmuxcommon.h tsmux.h tsmuxstream.h
diff --git a/gst/mpegtsmux/tsmux/crc.h b/gst/mpegtsmux/tsmux/crc.h
new file mode 100644
index 00000000..089ce2c5
--- /dev/null
+++ b/gst/mpegtsmux/tsmux/crc.h
@@ -0,0 +1,58 @@
+static guint32 crc_tab[256] = {
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
+ 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
+ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
+ 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
+ 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
+ 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
+ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
+ 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
+ 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
+ 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
+ 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
+ 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
+ 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
+ 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
+ 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
+ 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
+ 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+};
+
+static guint32
+calc_crc32 (guint8 *data, guint datalen)
+{
+ guint i;
+ guint32 crc = 0xffffffff;
+
+ for (i=0; i<datalen; i++) {
+ crc = (crc << 8) ^ crc_tab[((crc >> 24) ^ *data++) & 0xff];
+ }
+
+ return crc;
+}
diff --git a/gst/mpegtsmux/tsmux/tsmux.c b/gst/mpegtsmux/tsmux/tsmux.c
new file mode 100644
index 00000000..0952f699
--- /dev/null
+++ b/gst/mpegtsmux/tsmux/tsmux.c
@@ -0,0 +1,1056 @@
+/*
+ * Copyright 2006 BBC and Fluendo S.A.
+ *
+ * This library is licensed under 4 different licenses and you
+ * can choose to use it under the terms of any one of them. The
+ * four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
+ * license.
+ *
+ * MPL:
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * LGPL:
+ *
+ * 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.
+ *
+ * GPL:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * MIT:
+ *
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "tsmux.h"
+#include "tsmuxstream.h"
+#include "crc.h"
+
+/* Maximum total data length for a PAT section is 1024 bytes, minus an
+ * 8 byte header, then the length of each program entry is 32 bits,
+ * then finally a 32 bit CRC. Thus the maximum number of programs in this mux
+ * is (1024 - 8 - 4) / 4 = 253 because it only supports single section PATs */
+#define TSMUX_MAX_PROGRAMS 253
+
+#define TSMUX_SECTION_HDR_SIZE 8
+
+#define TSMUX_DEFAULT_NETWORK_ID 0x0001
+#define TSMUX_DEFAULT_TS_ID 0x0001
+
+#define TSMUX_START_PROGRAM_ID 0x0001
+#define TSMUX_START_PMT_PID 0x0010
+#define TSMUX_START_ES_PID 0x0040
+
+/* HACK: We use a fixed buffering offset for the PCR at the moment -
+ * this is the amount 'in advance' of the stream that the PCR sits.
+ * 1/8 second atm */
+#define TSMUX_PCR_OFFSET (TSMUX_CLOCK_FREQ / 8)
+
+/* Times per second to write PCR */
+#define TSMUX_DEFAULT_PCR_FREQ (25)
+
+/* PAT frequency (1/10th sec) */
+#define TSMUX_DEFAULT_PAT_FREQ (TSMUX_CLOCK_FREQ / 10)
+/* PMT frequency (1/10th sec) */
+#define TSMUX_DEFAULT_PMT_FREQ (TSMUX_CLOCK_FREQ / 10)
+
+static gboolean tsmux_write_pat (TsMux * mux);
+static gboolean tsmux_write_pmt (TsMux * mux, TsMuxProgram * program);
+
+/**
+ * tsmux_new:
+ *
+ * Create a new muxer session.
+ *
+ * Returns: A new #TsMux object.
+ */
+TsMux *
+tsmux_new ()
+{
+ TsMux *mux;
+
+ mux = g_new0 (TsMux, 1);
+
+ mux->transport_id = TSMUX_DEFAULT_TS_ID;
+
+ mux->next_pgm_no = TSMUX_START_PROGRAM_ID;
+ mux->next_pmt_pid = TSMUX_START_PMT_PID;
+ mux->next_stream_pid = TSMUX_START_ES_PID;
+
+ mux->pat_changed = TRUE;
+ mux->last_pat_ts = -1;
+ mux->pat_frequency = TSMUX_DEFAULT_PAT_FREQ;
+
+ return mux;
+}
+
+/**
+ * tsmux_set_write_func:
+ * @mux: a #TsMux
+ * @func: a user callback function
+ * @user_data: user data passed to @func
+ *
+ * Set the callback function and user data to be called when @mux has output to
+ * produce. @user_data will be passed as user data in @func.
+ */
+void
+tsmux_set_write_func (TsMux * mux, TsMuxWriteFunc func, void *user_data)
+{
+ g_return_if_fail (mux != NULL);
+
+ mux->write_func = func;
+ mux->write_func_data = user_data;
+}
+
+/**
+ * tsmux_set_pat_frequency:
+ * @mux: a #TsMux
+ * @freq: a new PAT frequency
+ *
+ * Set the frequency (against the 90Hz clock) for writing out the PAT table.
+ * A frequency of 0 will only write the PAT table when it changes.
+ *
+ * Many transport stream clients might have problems if the PAT table is not
+ * inserted in the stream at regular intervals, especially when initially trying
+ * to figure out the contents of the stream.
+ */
+void
+tsmux_set_pat_frequency (TsMux * mux, guint freq)
+{
+ g_return_if_fail (mux != NULL);
+
+ mux->pat_frequency = freq;
+}
+
+/**
+ * tsmux_get_pat_frequency:
+ * @mux: a #TsMux
+ *
+ * Get the configured PAT frequency. See also tsmux_set_pat_frequency().
+ *
+ * Returns: the configured PAT frequency
+ */
+guint
+tsmux_get_pat_frequency (TsMux * mux)
+{
+ g_return_val_if_fail (mux != NULL, 0);
+
+ return mux->pat_frequency;
+}
+
+/**
+ * tsmux_free:
+ * @mux: a #TsMux
+ *
+ * Free all resources associated with @mux. After calling this function @mux can
+ * not be used anymore.
+ */
+void
+tsmux_free (TsMux * mux)
+{
+ GList *cur;
+
+ g_return_if_fail (mux != NULL);
+
+ /* Free all programs */
+ for (cur = g_list_first (mux->programs); cur != NULL; cur = g_list_next (cur)) {
+ TsMuxProgram *program = (TsMuxProgram *) cur->data;
+
+ tsmux_program_free (program);
+ }
+ g_list_free (mux->programs);
+
+ /* Free all streams */
+ for (cur = g_list_first (mux->streams); cur != NULL; cur = g_list_next (cur)) {
+ TsMuxStream *stream = (TsMuxStream *) cur->data;
+
+ tsmux_stream_free (stream);
+ }
+ g_list_free (mux->streams);
+
+ g_free (mux);
+}
+
+/**
+ * tsmux_program_new:
+ * @mux: a #TsMux
+ *
+ * Create a new program in the mising session @mux.
+ *
+ * Returns: a new #TsMuxProgram or %NULL when the maximum number of programs has
+ * been reached.
+ */
+TsMuxProgram *
+tsmux_program_new (TsMux * mux)
+{
+ TsMuxProgram *program;
+
+ g_return_val_if_fail (mux != NULL, NULL);
+
+ /* Ensure we have room for another program */
+ if (mux->nb_programs == TSMUX_MAX_PROGRAMS)
+ return NULL;
+
+ program = g_new0 (TsMuxProgram, 1);
+
+ program->pmt_changed = TRUE;
+ program->last_pmt_ts = -1;
+ program->pmt_frequency = TSMUX_DEFAULT_PMT_FREQ;
+
+ program->pgm_number = mux->next_pgm_no++;
+ program->pmt_pid = mux->next_pmt_pid++;
+ program->pcr_stream = NULL;
+ program->last_pcr = -1;
+
+ program->streams = g_array_sized_new (FALSE, TRUE, sizeof (TsMuxStream *), 1);
+
+ mux->programs = g_list_prepend (mux->programs, program);
+ mux->nb_programs++;
+ mux->pat_changed = TRUE;
+
+ return program;
+}
+
+/**
+ * tsmux_set_pmt_frequency:
+ * @program: a #TsMuxProgram
+ * @freq: a new PMT frequency
+ *
+ * Set the frequency (against the 90Hz clock) for writing out the PMT table.
+ * A frequency of 0 will only write the PMT table when it changes.
+ *
+ * Many transport stream clients might have problems if the PMT table is not
+ * inserted in the stream at regular intervals, especially when initially trying
+ * to figure out the contents of the stream.
+ */
+void
+tsmux_set_pmt_frequency (TsMuxProgram * program, guint freq)
+{
+ g_return_if_fail (program != NULL);
+
+ program->pmt_frequency = freq;
+}
+
+/**
+ * tsmux_get_pmt_frequency:
+ * @program: a #TsMuxProgram
+ *
+ * Get the configured PMT frequency. See also tsmux_set_pmt_frequency().
+ *
+ * Returns: the configured PMT frequency
+ */
+guint
+tsmux_get_pmt_frequency (TsMuxProgram * program)
+{
+ g_return_val_if_fail (program != NULL, 0);
+
+ return program->pmt_frequency;
+}
+
+/**
+ * tsmux_program_add_stream:
+ * @program: a #TsMuxProgram
+ * @stream: a #TsMuxStream
+ *
+ * Add @stream to @program.
+ */
+void
+tsmux_program_add_stream (TsMuxProgram * program, TsMuxStream * stream)
+{
+ g_return_if_fail (program != NULL);
+ g_return_if_fail (stream != NULL);
+
+ program->nb_streams++;
+ g_array_append_val (program->streams, stream);
+ program->pmt_changed = TRUE;
+}
+
+/**
+ * tsmux_program_set_pcr_stream:
+ * @program: a #TsMuxProgram
+ * @stream: a #TsMuxStream
+ *
+ * Set @stream as the PCR stream for @program, overwriting the previously
+ * configured PCR stream. When @stream is NULL, program will have no PCR stream
+ * configured.
+ */
+void
+tsmux_program_set_pcr_stream (TsMuxProgram * program, TsMuxStream * stream)
+{
+ g_return_if_fail (program != NULL);
+
+ if (program->pcr_stream == stream)
+ return;
+
+ if (program->pcr_stream != NULL)
+ tsmux_stream_pcr_unref (program->pcr_stream);
+ if (stream)
+ tsmux_stream_pcr_ref (stream);
+ program->pcr_stream = stream;
+
+ program->pmt_changed = TRUE;
+}
+
+/**
+ * tsmux_get_new_pid:
+ * @mux: a #TsMux
+ *
+ * Get a new free PID.
+ *
+ * Returns: a new free PID.
+ */
+guint16
+tsmux_get_new_pid (TsMux * mux)
+{
+ g_return_val_if_fail (mux != NULL, -1);
+
+ /* FIXME: It's possible that this next PID is already taken if a
+ * specific PID was requested earlier. We should find a free PID */
+ return mux->next_stream_pid++;
+}
+
+/**
+ * tsmux_create_stream:
+ * @mux: a #TsMux
+ * @stream_type: a #TsMuxStreamType
+ * @pid: the PID of the new stream.
+ *
+ * Create a new stream of @stream_type in the muxer session @mux.
+ *
+ * When @pid is set to #TSMUX_PID_AUTO, a new free PID will automatically
+ * be allocated for the new stream.
+ *
+ * Returns: a new #TsMuxStream.
+ */
+TsMuxStream *
+tsmux_create_stream (TsMux * mux, TsMuxStreamType stream_type, guint16 pid)
+{
+ TsMuxStream *stream;
+ guint16 new_pid;
+
+ g_return_val_if_fail (mux != NULL, NULL);
+
+ if (pid == TSMUX_PID_AUTO) {
+ new_pid = tsmux_get_new_pid (mux);
+ } else {
+ new_pid = pid & 0x1FFF;
+ }
+
+ /* Ensure we're not creating a PID collision */
+ if (tsmux_find_stream (mux, new_pid))
+ return NULL;
+
+ stream = tsmux_stream_new (new_pid, stream_type);
+
+ mux->streams = g_list_prepend (mux->streams, stream);
+ mux->nb_streams++;
+
+ return stream;
+}
+
+/**
+ * tsmux_find_stream:
+ * @mux: a #TsMux
+ * @pid: the PID to find.
+ *
+ * Find the stream associated wih PID.
+ *
+ * Returns: a #TsMuxStream with @pid or NULL when the stream was not found.
+ */
+TsMuxStream *
+tsmux_find_stream (TsMux * mux, guint16 pid)
+{
+ TsMuxStream *found = NULL;
+ GList *cur;
+
+ g_return_val_if_fail (mux != NULL, NULL);
+
+ for (cur = g_list_first (mux->streams); cur != NULL; cur = g_list_next (cur)) {
+ TsMuxStream *stream = (TsMuxStream *) cur->data;
+
+ if (tsmux_stream_get_pid (stream) == pid) {
+ found = stream;
+ break;
+ }
+ }
+ return found;
+}
+
+static gboolean
+tsmux_packet_out (TsMux * mux)
+{
+ if (G_UNLIKELY (mux->write_func == NULL))
+ return TRUE;
+
+ return mux->write_func (mux->packet_buf, TSMUX_PACKET_LENGTH,
+ mux->write_func_data, mux->new_pcr);
+}
+
+/*
+ * adaptation_field() {
+ * adaptation_field_length 8 uimsbf
+ * if(adaptation_field_length >0) {
+ * discontinuity_indicator 1 bslbf
+ * random_access_indicator 1 bslbf
+ * elementary_stream_priority_indicator 1 bslbf
+ * PCR_flag 1 bslbf
+ * OPCR_flag 1 bslbf
+ * splicing_point_flag 1 bslbf
+ * transport_private_data_flag 1 bslbf
+ * adaptation_field_extension_flag 1 bslbf
+ * if(PCR_flag == '1') {
+ * program_clock_reference_base 33 uimsbf
+ * reserved 6 bslbf
+ * program_clock_reference_extension 9 uimsbf
+ * }
+ * if(OPCR_flag == '1') {
+ * original_program_clock_reference_base 33 uimsbf
+ * reserved 6 bslbf
+ * original_program_clock_reference_extension 9 uimsbf
+ * }
+ * if (splicing_point_flag == '1') {
+ * splice_countdown 8 tcimsbf
+ * }
+ * if(transport_private_data_flag == '1') {
+ * transport_private_data_length 8 uimsbf
+ * for (i=0; i<transport_private_data_length;i++){
+ * private_data_byte 8 bslbf
+ * }
+ * }
+ * if (adaptation_field_extension_flag == '1' ) {
+ * adaptation_field_extension_length 8 uimsbf
+ * ltw_flag 1 bslbf
+ * piecewise_rate_flag 1 bslbf
+ * seamless_splice_flag 1 bslbf
+ * reserved 5 bslbf
+ * if (ltw_flag == '1') {
+ * ltw_valid_flag 1 bslbf
+ * ltw_offset 15 uimsbf
+ * }
+ * if (piecewise_rate_flag == '1') {
+ * reserved 2 bslbf
+ * piecewise_rate 22 uimsbf
+ * }
+ * if (seamless_splice_flag == '1'){
+ * splice_type 4 bslbf
+ * DTS_next_AU[32..30] 3 bslbf
+ * marker_bit 1 bslbf
+ * DTS_next_AU[29..15] 15 bslbf
+ * marker_bit 1 bslbf
+ * DTS_next_AU[14..0] 15 bslbf
+ * marker_bit 1 bslbf
+ * }
+ * for ( i=0;i<N;i++) {
+ * reserved 8 bslbf
+ * }
+ * }
+ * for (i=0;i<N;i++){
+ * stuffing_byte 8 bslbf
+ * }
+ * }
+ * }
+ */
+static gboolean
+tsmux_write_adaptation_field (guint8 * buf,
+ TsMuxPacketInfo * pi, guint8 min_length, guint8 * written)
+{
+ guint8 pos = 2;
+ guint8 flags = 0;
+
+ g_assert (min_length <= TSMUX_PAYLOAD_LENGTH);
+
+ /* Write out all the fields from the packet info only if the
+ * user set the flag to request the adaptation field - if the flag
+ * isn't set, we're just supposed to write stuffing bytes */
+ if (pi->flags & TSMUX_PACKET_FLAG_ADAPTATION) {
+ TS_DEBUG ("writing adaptation fields");
+ if (pi->flags & TSMUX_PACKET_FLAG_DISCONT)
+ flags |= 0x80;
+ if (pi->flags & TSMUX_PACKET_FLAG_RANDOM_ACCESS)
+ flags |= 0x40;
+ if (pi->flags & TSMUX_PACKET_FLAG_PRIORITY)
+ flags |= 0x20;
+ if (pi->flags & TSMUX_PACKET_FLAG_WRITE_PCR) {
+ guint64 pcr_base;
+ guint32 pcr_ext;
+
+ pcr_base = (pi->pcr / 300);
+ pcr_ext = (pi->pcr % 300);
+
+ flags |= 0x10;
+ TS_DEBUG ("Writing PCR %" G_GUINT64_FORMAT " + ext %u", pcr_base,
+ pcr_ext);
+ buf[pos++] = (pcr_base >> 25) & 0xff;
+ buf[pos++] = (pcr_base >> 17) & 0xff;
+ buf[pos++] = (pcr_base >> 9) & 0xff;
+ buf[pos++] = (pcr_base >> 1) & 0xff;
+ buf[pos++] = ((pcr_base << 7) & 0x80) | ((pcr_ext >> 8) & 0x01);
+ buf[pos++] = (pcr_ext) & 0xff;
+ }
+ if (pi->flags & TSMUX_PACKET_FLAG_WRITE_OPCR) {
+ guint64 opcr_base;
+ guint32 opcr_ext;
+
+ opcr_base = (pi->opcr / 300);
+ opcr_ext = (pi->opcr % 300);
+
+ flags |= 0x08;
+ TS_DEBUG ("Writing OPCR");
+ buf[pos++] = (opcr_base >> 25) & 0xff;
+ buf[pos++] = (opcr_base >> 17) & 0xff;
+ buf[pos++] = (opcr_base >> 9) & 0xff;
+ buf[pos++] = (opcr_base >> 1) & 0xff;
+ buf[pos++] = ((opcr_base << 7) & 0x80) | ((opcr_ext >> 8) & 0x01);
+ buf[pos++] = (opcr_ext) & 0xff;
+ }
+ if (pi->flags & TSMUX_PACKET_FLAG_WRITE_SPLICE) {
+ flags |= 0x04;
+ buf[pos++] = pi->splice_countdown;
+ }
+ if (pi->private_data_len > 0) {
+ flags |= 0x02;
+ /* Private data to write, ensure we have enough room */
+ if ((1 + pi->private_data_len) > (TSMUX_PAYLOAD_LENGTH - pos))
+ return FALSE;
+ buf[pos++] = pi->private_data_len;
+ memcpy (&(buf[pos]), pi->private_data, pi->private_data_len);
+ pos += pi->private_data_len;
+ TS_DEBUG ("%u bytes of private data", pi->private_data_len);
+ }
+ if (pi->flags & TSMUX_PACKET_FLAG_WRITE_ADAPT_EXT) {
+ flags |= 0x01;
+ TS_DEBUG ("FIXME: write Adaptation extension");
+ /* Write an empty extension for now */
+ buf[pos++] = 1;
+ buf[pos++] = 0;
+ }
+ }
+ /* Write the flags at the start */
+ buf[1] = flags;
+
+ /* Stuffing bytes if needed */
+ while (pos < min_length)
+ buf[pos++] = 0xff;
+
+ /* Write the adaptation field length, which doesn't include its own byte */
+ buf[0] = pos - 1;
+
+ if (written)
+ *written = pos;
+
+ return TRUE;
+}
+
+static gboolean
+tsmux_write_ts_header (guint8 * buf, TsMuxPacketInfo * pi,
+ guint * payload_len_out, guint * payload_offset_out)
+{
+ guint8 *tmp;
+ guint8 adaptation_flag;
+ guint8 adapt_min_length = 0;
+ guint8 adapt_len;
+ guint payload_len;
+ gboolean write_adapt = FALSE;
+
+ /* Sync byte */
+ buf[0] = TSMUX_SYNC_BYTE;
+
+ TS_DEBUG ("PID 0x%04x, counter = 0x%01x, %u bytes avail", pi->pid,
+ pi->packet_count & 0x0f, pi->stream_avail);
+
+ /* 3 bits:
+ * transport_error_indicator
+ * payload_unit_start_indicator
+ * transport_priority: (00)
+ * 13 bits: PID
+ */
+ tmp = buf + 1;
+ if (pi->packet_start_unit_indicator) {
+ tsmux_put16 (&tmp, 0x4000 | pi->pid);
+ } else
+ tsmux_put16 (&tmp, pi->pid);
+
+ /* 2 bits: scrambling_control (NOT SUPPORTED) (00)
+ * 2 bits: adaptation field control (1x has_adaptation_field | x1 has_payload)
+ * 4 bits: continuity counter (xxxx)
+ */
+ adaptation_flag = pi->packet_count & 0x0f;
+
+ if (pi->flags & TSMUX_PACKET_FLAG_ADAPTATION) {
+ write_adapt = TRUE;
+ }
+
+ if (pi->stream_avail < TSMUX_PAYLOAD_LENGTH) {
+ /* Need an adaptation field regardless for stuffing */
+ adapt_min_length = TSMUX_PAYLOAD_LENGTH - pi->stream_avail;
+ write_adapt = TRUE;
+ }
+
+ if (write_adapt) {
+ gboolean res;
+
+ /* Flag the adaptation field presence */
+ adaptation_flag |= 0x20;
+ res = tsmux_write_adaptation_field (buf + TSMUX_HEADER_LENGTH,
+ pi, adapt_min_length, &adapt_len);
+ if (G_UNLIKELY (res == FALSE))
+ return FALSE;
+
+ /* Should have written at least the number of bytes we requested */
+ g_assert (adapt_len >= adapt_min_length);
+ } else {
+ adapt_len = 0;
+ }
+
+ /* The amount of packet data we wrote is the remaining space after
+ * the adaptation field */
+ *payload_len_out = payload_len = TSMUX_PAYLOAD_LENGTH - adapt_len;
+ *payload_offset_out = TSMUX_HEADER_LENGTH + adapt_len;
+
+ /* Now if we are going to write out some payload, flag that fact */
+ if (payload_len > 0 && pi->stream_avail > 0) {
+ /* Flag the presence of a payload */
+ adaptation_flag |= 0x10;
+
+ /* We must have enough data to fill the payload, or some calculation
+ * went wrong */
+ g_assert (payload_len <= pi->stream_avail);
+
+ /* Packet with payload, increment the continuity counter */
+ pi->packet_count++;
+ }
+
+ /* Write the byte of transport_scrambling_control, adaptation_field_control
+ * + continuity counter out */
+ buf[3] = adaptation_flag;
+
+
+ if (write_adapt) {
+ TS_DEBUG ("Adaptation field of size >= %d + %d bytes payload",
+ adapt_len, payload_len);
+ } else {
+ TS_DEBUG ("Payload of %d bytes only", payload_len);
+ }
+
+ return TRUE;
+}
+
+/**
+ * tsmux_write_stream_packet:
+ * @mux: a #TsMux
+ * @stream: a #TsMuxStream
+ *
+ * Write a packet of @stream.
+ *
+ * Returns: TRUE if the packet could be written.
+ */
+gboolean
+tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
+{
+ guint payload_len, payload_offs;
+ TsMuxPacketInfo *pi = &stream->pi;
+ gboolean res;
+
+
+ mux->new_pcr = -1;
+ g_return_val_if_fail (mux != NULL, FALSE);
+ g_return_val_if_fail (stream != NULL, FALSE);
+
+ if (tsmux_stream_is_pcr (stream)) {
+ gint64 cur_pcr = 0;
+ gint64 cur_pts = tsmux_stream_get_pts (stream);
+ gboolean write_pat;
+ GList *cur;
+
+ if (cur_pts != -1) {
+ TS_DEBUG ("TS for PCR stream is %" G_GINT64_FORMAT, cur_pts);
+ }
+
+ /* FIXME: The current PCR needs more careful calculation than just
+ * writing a fixed offset */
+ if (cur_pts != -1 && (cur_pts >= TSMUX_PCR_OFFSET))
+ cur_pcr = (cur_pts - TSMUX_PCR_OFFSET) *
+ (TSMUX_SYS_CLOCK_FREQ / TSMUX_CLOCK_FREQ);
+
+ /* Need to decide whether to write a new PCR in this packet */
+ if (stream->last_pcr == -1 ||
+ (cur_pcr - stream->last_pcr >
+ (TSMUX_CLOCK_FREQ / TSMUX_DEFAULT_PCR_FREQ))) {
+
+ stream->pi.flags |=
+ TSMUX_PACKET_FLAG_ADAPTATION | TSMUX_PACKET_FLAG_WRITE_PCR;
+ stream->pi.pcr = cur_pcr;
+ stream->last_pcr = cur_pcr;
+ mux->new_pcr = cur_pcr;
+ }
+
+ /* check if we need to rewrite pat */
+ if (mux->last_pat_ts == -1 || mux->pat_changed)
+ write_pat = TRUE;
+ else if (cur_pcr >= mux->last_pat_ts + mux->pat_frequency)
+ write_pat = TRUE;
+ else
+ write_pat = FALSE;
+
+ if (write_pat) {
+ mux->last_pat_ts = cur_pcr;
+ if (!tsmux_write_pat (mux))
+ return FALSE;
+ }
+
+ /* check if we need to rewrite any of the current pmts */
+ for (cur = g_list_first (mux->programs); cur != NULL;
+ cur = g_list_next (cur)) {
+ TsMuxProgram *program = (TsMuxProgram *) cur->data;
+ gboolean write_pmt;
+
+ if (program->last_pmt_ts == -1 || program->pmt_changed)
+ write_pmt = TRUE;
+ else if (cur_pcr >= program->last_pmt_ts + program->pmt_frequency)
+ write_pmt = TRUE;
+ else
+ write_pmt = FALSE;
+
+ if (write_pmt) {
+ program->last_pmt_ts = cur_pcr;
+ if (!tsmux_write_pmt (mux, program))
+ return FALSE;
+ }
+ }
+ }
+
+ pi->stream_avail = tsmux_stream_bytes_avail (stream);
+ pi->packet_start_unit_indicator = tsmux_stream_at_pes_start (stream);
+
+ if (!tsmux_write_ts_header (mux->packet_buf, pi, &payload_len, &payload_offs))
+ return FALSE;
+
+ if (!tsmux_stream_get_data (stream, mux->packet_buf + payload_offs,
+ payload_len))
+ return FALSE;
+
+ res = tsmux_packet_out (mux);
+
+ /* Reset all dynamic flags */
+ stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
+
+ return res;
+}
+
+/**
+ * tsmux_program_free:
+ * @program: a #TsMuxProgram
+ *
+ * Free the resources of @program. After this call @program can not be used
+ * anymore.
+ */
+void
+tsmux_program_free (TsMuxProgram * program)
+{
+ g_return_if_fail (program != NULL);
+
+ g_array_free (program->streams, TRUE);
+ g_free (program);
+}
+
+static gboolean
+tsmux_write_section (TsMux * mux, TsMuxSection * section)
+{
+ guint8 *cur_in;
+ guint payload_remain;
+ guint payload_len, payload_offs;
+ TsMuxPacketInfo *pi;
+
+ pi = &section->pi;
+
+ pi->packet_start_unit_indicator = TRUE;
+
+ cur_in = section->data;
+ payload_remain = pi->stream_avail;
+
+ while (payload_remain > 0) {
+ if (pi->packet_start_unit_indicator) {
+ /* Need to write an extra single byte start pointer */
+ pi->stream_avail++;
+
+ if (!tsmux_write_ts_header (mux->packet_buf, pi,
+ &payload_len, &payload_offs)) {
+ pi->stream_avail--;
+ return FALSE;
+ }
+ pi->stream_avail--;
+
+ /* Write the pointer byte */
+ mux->packet_buf[payload_offs] = 0x00;
+
+ payload_offs++;
+ payload_len--;
+ pi->packet_start_unit_indicator = FALSE;
+ } else {
+ if (!tsmux_write_ts_header (mux->packet_buf, pi,
+ &payload_len, &payload_offs))
+ return FALSE;
+ }
+
+ TS_DEBUG ("Outputting %d bytes to section. %d remaining after",
+ payload_len, payload_remain - payload_len);
+
+ memcpy (mux->packet_buf + payload_offs, cur_in, payload_len);
+
+ cur_in += payload_len;
+ payload_remain -= payload_len;
+
+ if (G_UNLIKELY (!tsmux_packet_out (mux))) {
+ mux->new_pcr = -1;
+ return FALSE;
+ }
+ mux->new_pcr = -1;
+ }
+
+ return TRUE;
+}
+
+static void
+tsmux_write_section_hdr (guint8 * pos, guint8 table_id, guint16 len,
+ guint16 id, guint8 version, guint8 section_nr, guint8 last_section_nr)
+{
+ /* The length passed is the total length of the section, but we're not
+ * supposed to include the first 3 bytes of the header in the count */
+ len -= 3;
+
+ /* 1 byte table identifier */
+ *pos++ = table_id;
+ /* section_syntax_indicator = '0' | '0' | '11' reserved bits | (len >> 8) */
+ tsmux_put16 (&pos, 0xB000 | len);
+ /* 2 bytes transport/program id */
+ tsmux_put16 (&pos, id);
+
+ /* '11' reserved | version 'xxxxxx' | 'x' current_next */
+ *pos++ = 0xC0 | ((version & 0x1F) << 1) | 0x01;
+ *pos++ = section_nr;
+ *pos++ = last_section_nr;
+}
+
+static gboolean
+tsmux_write_pat (TsMux * mux)
+{
+ GList *cur;
+ TsMuxSection *pat = &mux->pat;
+
+ if (mux->pat_changed) {
+ /* program_association_section ()
+ * table_id 8 uimsbf
+ * section_syntax_indicator 1 bslbf
+ * '0' 1 bslbf
+ * reserved 2 bslbf
+ * section_length 12 uimsbf
+ * transport_stream_id 16 uimsbf
+ * reserved 2 bslbf
+ * version_number 5 uimsbf
+ * current_next_indicator 1 bslbf
+ * section_number 8 uimsbf
+ * last_section_number 8 uimsbf
+ * for (i = 0; i < N; i++) {
+ * program_number 16 uimsbf
+ * reserved 3 bslbf
+ * network_PID_or_program_map_PID 13 uimbsf
+ * }
+ * CRC_32 32 rbchof
+ */
+ guint8 *pos;
+ guint32 crc;
+
+ /* Prepare the section data after the section header */
+ pos = pat->data + TSMUX_SECTION_HDR_SIZE;
+
+ for (cur = g_list_first (mux->programs); cur != NULL;
+ cur = g_list_next (cur)) {
+ TsMuxProgram *program = (TsMuxProgram *) cur->data;
+
+ tsmux_put16 (&pos, program->pgm_number);
+ tsmux_put16 (&pos, 0xE000 | program->pmt_pid);
+ }
+
+ /* Measure the section length, include extra 4 bytes for CRC below */
+ pat->pi.stream_avail = pos - pat->data + 4;
+
+ /* Go back and write the header now that we know the final length.
+ * table_id = 0 for PAT */
+ tsmux_write_section_hdr (pat->data, 0x00, pat->pi.stream_avail,
+ mux->transport_id, mux->pat_version, 0, 0);
+
+ /* Calc and output CRC for data bytes, not including itself */
+ crc = calc_crc32 (pat->data, pat->pi.stream_avail - 4);
+ tsmux_put32 (&pos, crc);
+
+ TS_DEBUG ("PAT has %d programs, is %u bytes",
+ mux->nb_programs, pat->pi.stream_avail);
+ mux->pat_changed = FALSE;
+ mux->pat_version++;
+ }
+
+ return tsmux_write_section (mux, pat);
+}
+
+static gboolean
+tsmux_write_pmt (TsMux * mux, TsMuxProgram * program)
+{
+ TsMuxSection *pmt = &program->pmt;
+
+ if (program->pmt_changed) {
+ /* program_association_section ()
+ * table_id 8 uimsbf
+ * section_syntax_indicator 1 bslbf
+ * '0' 1 bslbf
+ * reserved 2 bslbf
+ * section_length 12 uimsbf
+ * program_id 16 uimsbf
+ * reserved 2 bslbf
+ * version_number 5 uimsbf
+ * current_next_indicator 1 bslbf
+ * section_number 8 uimsbf
+ * last_section_number 8 uimsbf
+ * reserved 3 bslbf
+ * PCR_PID 13 uimsbf
+ * reserved 4 bslbf
+ * program_info_length 12 uimsbf
+ * for (i = 0; i < N; i++)
+ * descriptor ()
+ *
+ * for (i = 0; i < N1; i++) {
+ * stream_type 8 uimsbf
+ * reserved 3 bslbf
+ * elementary_PID 13 uimbsf
+ * reserved 4 bslbf
+ * ES_info_length 12 uimbsf
+ * for (i = 0; i < N1; i++) {
+ * descriptor ();
+ * }
+ * }
+ * CRC_32 32 rbchof
+ */
+ guint8 *pos;
+ guint32 crc;
+ guint i;
+
+ /* Prepare the section data after the basic section header */
+ pos = pmt->data + TSMUX_SECTION_HDR_SIZE;
+
+ if (program->pcr_stream == NULL)
+ tsmux_put16 (&pos, 0xFFFF);
+ else
+ tsmux_put16 (&pos, 0xE000 | tsmux_stream_get_pid (program->pcr_stream));
+
+ /* FIXME: Write program descriptors if needed, for now write a
+ * length of 0 */
+ tsmux_put16 (&pos, 0xF000);
+
+ /* Write out the entries */
+ for (i = 0; i < program->nb_streams; i++) {
+ TsMuxStream *stream = g_array_index (program->streams, TsMuxStream *, i);
+ guint16 es_info_len;
+
+ /* FIXME: Use API to retrieve this from the stream */
+ *pos++ = stream->stream_type;
+ tsmux_put16 (&pos, 0xE000 | tsmux_stream_get_pid (stream));
+
+ /* Write any ES descriptors needed */
+ tsmux_stream_get_es_descrs (stream, mux->es_info_buf, &es_info_len);
+ tsmux_put16 (&pos, 0xF000 | es_info_len);
+
+ if (es_info_len > 0) {
+ TS_DEBUG ("Writing descriptor of len %d for PID 0x%04x",
+ es_info_len, tsmux_stream_get_pid (stream));
+ if (G_UNLIKELY (pos + es_info_len >=
+ pmt->data + TSMUX_MAX_SECTION_LENGTH))
+ return FALSE;
+
+ memcpy (pos, mux->es_info_buf, es_info_len);
+ pos += es_info_len;
+ }
+ }
+
+ /* Include the CRC in the byte count */
+ pmt->pi.stream_avail = pos - pmt->data + 4;
+
+ /* Go back and patch the pmt_header now that we know the length.
+ * table_id = 2 for PMT */
+ tsmux_write_section_hdr (pmt->data, 0x02, pmt->pi.stream_avail,
+ program->pgm_number, program->pmt_version, 0, 0);
+
+ /* Calc and output CRC for data bytes,
+ * but not counting the CRC bytes this time */
+ crc = calc_crc32 (pmt->data, pmt->pi.stream_avail - 4);
+ tsmux_put32 (&pos, crc);
+
+ TS_DEBUG ("PMT for program %d has %d streams, is %u bytes",
+ program->pgm_number, program->nb_streams, pmt->pi.stream_avail);
+
+ pmt->pi.pid = program->pmt_pid;
+ program->pmt_changed = FALSE;
+ program->pmt_version++;
+ }
+
+ return tsmux_write_section (mux, pmt);
+}
diff --git a/gst/mpegtsmux/tsmux/tsmux.h b/gst/mpegtsmux/tsmux/tsmux.h
new file mode 100644
index 00000000..fb0a81b5
--- /dev/null
+++ b/gst/mpegtsmux/tsmux/tsmux.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2006 BBC and Fluendo S.A.
+ *
+ * This library is licensed under 4 different licenses and you
+ * can choose to use it under the terms of any one of them. The
+ * four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
+ * license.
+ *
+ * MPL:
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * LGPL:
+ *
+ * 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.
+ *
+ * GPL:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * MIT:
+ *
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef __TSMUX_H__
+#define __TSMUX_H__
+
+#include <glib.h>
+
+#include <tsmux/tsmuxcommon.h>
+#include <tsmux/tsmuxstream.h>
+
+G_BEGIN_DECLS
+
+#define TSMUX_MAX_ES_INFO_LENGTH ((1 << 12) - 1)
+#define TSMUX_MAX_SECTION_LENGTH (4096)
+
+#define TSMUX_PID_AUTO ((guint16)-1)
+
+typedef struct TsMuxSection TsMuxSection;
+typedef struct TsMux TsMux;
+
+typedef gboolean (*TsMuxWriteFunc) (guint8 *data, guint len, void *user_data, gint64 new_pcr);
+
+struct TsMuxSection {
+ TsMuxPacketInfo pi;
+
+ /* Private sections can be up to 4096 bytes */
+ guint8 data[TSMUX_MAX_SECTION_LENGTH];
+};
+
+/* Information for the streams associated with one program */
+struct TsMuxProgram {
+ TsMuxSection pmt;
+ guint8 pmt_version;
+ gboolean pmt_changed;
+
+ guint pmt_frequency;
+ gint64 last_pmt_ts;
+
+ guint16 pgm_number; /* program ID for the PAT */
+ guint16 pmt_pid; /* PID to write the PMT */
+
+ TsMuxStream *pcr_stream; /* Stream which carries the PCR */
+ gint64 last_pcr;
+
+ GArray *streams; /* Array of TsMuxStream pointers */
+ guint nb_streams;
+};
+
+struct TsMux {
+ guint nb_streams;
+ GList *streams; /* TsMuxStream* array of all streams */
+
+ guint nb_programs;
+ GList *programs; /* TsMuxProgram* array of all programs */
+
+ guint16 transport_id;
+
+ guint16 next_pgm_no;
+ guint16 next_pmt_pid;
+ guint16 next_stream_pid;
+
+ TsMuxSection pat;
+ guint8 pat_version;
+ gboolean pat_changed;
+
+ guint pat_frequency;
+ gint64 last_pat_ts;
+
+ guint8 packet_buf[TSMUX_PACKET_LENGTH];
+ TsMuxWriteFunc write_func;
+ void *write_func_data;
+
+ /* Scratch space for writing ES_info descriptors */
+ guint8 es_info_buf[TSMUX_MAX_ES_INFO_LENGTH];
+ gint64 new_pcr;
+};
+
+/* create/free new muxer session */
+TsMux * tsmux_new (void);
+void tsmux_free (TsMux *mux);
+
+/* Setting muxing session properties */
+void tsmux_set_write_func (TsMux *mux, TsMuxWriteFunc func, void *user_data);
+void tsmux_set_pat_frequency (TsMux *mux, guint freq);
+guint tsmux_get_pat_frequency (TsMux *mux);
+guint16 tsmux_get_new_pid (TsMux *mux);
+
+/* pid/program management */
+TsMuxProgram * tsmux_program_new (TsMux *mux);
+void tsmux_program_free (TsMuxProgram *program);
+void tsmux_set_pmt_frequency (TsMuxProgram *program, guint freq);
+guint tsmux_get_pmt_frequency (TsMuxProgram *program);
+
+/* stream management */
+TsMuxStream * tsmux_create_stream (TsMux *mux, TsMuxStreamType stream_type, guint16 pid);
+TsMuxStream * tsmux_find_stream (TsMux *mux, guint16 pid);
+
+void tsmux_program_add_stream (TsMuxProgram *program, TsMuxStream *stream);
+void tsmux_program_set_pcr_stream (TsMuxProgram *program, TsMuxStream *stream);
+
+/* writing stuff */
+gboolean tsmux_write_stream_packet (TsMux *mux, TsMuxStream *stream);
+
+G_END_DECLS
+
+#endif
diff --git a/gst/mpegtsmux/tsmux/tsmuxcommon.h b/gst/mpegtsmux/tsmux/tsmuxcommon.h
new file mode 100644
index 00000000..3eb709df
--- /dev/null
+++ b/gst/mpegtsmux/tsmux/tsmuxcommon.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2006 BBC and Fluendo S.A.
+ *
+ * This library is licensed under 4 different licenses and you
+ * can choose to use it under the terms of any one of them. The
+ * four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
+ * license.
+ *
+ * MPL:
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * LGPL:
+ *
+ * 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.
+ *
+ * GPL:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * MIT:
+ *
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef __TSMUX_COMMON_H__
+#define __TSMUX_COMMON_H__
+
+#include <glib.h>
+
+#undef TS_DEBUG_ON
+
+G_BEGIN_DECLS
+
+#define TSMUX_SYNC_BYTE 0x47
+#define TSMUX_PACKET_LENGTH 188
+#define TSMUX_HEADER_LENGTH 4
+#define TSMUX_PAYLOAD_LENGTH (TSMUX_PACKET_LENGTH - TSMUX_HEADER_LENGTH)
+
+#define TSMUX_MIN_ES_DESC_LEN 8
+
+/* Frequency for PCR representation */
+#define TSMUX_SYS_CLOCK_FREQ (27000000L)
+/* Frequency for PTS values */
+#define TSMUX_CLOCK_FREQ (TSMUX_SYS_CLOCK_FREQ / 300)
+
+#define TSMUX_PACKET_FLAG_NONE (0)
+#define TSMUX_PACKET_FLAG_ADAPTATION (1 << 0)
+#define TSMUX_PACKET_FLAG_DISCONT (1 << 1)
+#define TSMUX_PACKET_FLAG_RANDOM_ACCESS (1 << 2)
+#define TSMUX_PACKET_FLAG_PRIORITY (1 << 3)
+#define TSMUX_PACKET_FLAG_WRITE_PCR (1 << 4)
+#define TSMUX_PACKET_FLAG_WRITE_OPCR (1 << 5)
+#define TSMUX_PACKET_FLAG_WRITE_SPLICE (1 << 6)
+#define TSMUX_PACKET_FLAG_WRITE_ADAPT_EXT (1 << 7)
+
+/* PES stream specific flags */
+#define TSMUX_PACKET_FLAG_PES_FULL_HEADER (1 << 8)
+#define TSMUX_PACKET_FLAG_PES_WRITE_PTS (1 << 9)
+#define TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS (1 << 10)
+#define TSMUX_PACKET_FLAG_PES_WRITE_ESCR (1 << 11)
+#define TSMUX_PACKET_FLAG_PES_EXT_STREAMID (1 << 12)
+
+typedef struct TsMuxPacketInfo TsMuxPacketInfo;
+typedef struct TsMuxProgram TsMuxProgram;
+typedef struct TsMuxStream TsMuxStream;
+
+struct TsMuxPacketInfo {
+ guint16 pid;
+ guint32 flags;
+
+ guint64 pcr;
+ guint64 opcr;
+
+ guint8 splice_countdown;
+
+ guint8 private_data_len;
+ guint8 private_data [256];
+
+ guint8 packet_count; /* continuity counter */
+
+ guint stream_avail; /* Number of payload bytes available */
+ gboolean packet_start_unit_indicator;
+};
+
+static inline void
+tsmux_put16 (guint8 **pos, guint16 val)
+{
+ *(*pos)++ = (val >> 8) & 0xff;
+ *(*pos)++ = val & 0xff;
+}
+
+static inline void
+tsmux_put32 (guint8 **pos, guint32 val)
+{
+ *(*pos)++ = (val >> 24) & 0xff;
+ *(*pos)++ = (val >> 16) & 0xff;
+ *(*pos)++ = (val >> 8) & 0xff;
+ *(*pos)++ = val & 0xff;
+}
+
+static inline void
+tsmux_put_ts (guint8 **pos, guint8 id, gint64 ts)
+{
+ /* 1: 4 bit id value | TS [32..30] | marker_bit */
+ *(*pos)++ = ((id << 4) | ((ts >> 29) & 0x0E) | 0x01) & 0xff;
+ /* 2, 3: TS[29..15] | marker_bit */
+ tsmux_put16 (pos, ((ts >> 14) & 0xfffe) | 0x01);
+ /* 4, 5: TS[14..0] | marker_bit */
+ tsmux_put16 (pos, ((ts << 1) & 0xfffe) | 0x01);
+}
+
+#ifdef TS_DEBUG_ON
+#define TS_DEBUG(...) g_print(__VA_ARGS__); g_print ("\n")
+#else
+#define TS_DEBUG(...)
+#endif
+
+G_END_DECLS
+
+#endif
diff --git a/gst/mpegtsmux/tsmux/tsmuxstream.c b/gst/mpegtsmux/tsmux/tsmuxstream.c
new file mode 100644
index 00000000..74b3c82b
--- /dev/null
+++ b/gst/mpegtsmux/tsmux/tsmuxstream.c
@@ -0,0 +1,692 @@
+/*
+ * Copyright 2006 BBC and Fluendo S.A.
+ *
+ * This library is licensed under 4 different licenses and you
+ * can choose to use it under the terms of any one of them. The
+ * four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
+ * license.
+ *
+ * MPL:
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * LGPL:
+ *
+ * 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.
+ *
+ * GPL:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * MIT:
+ *
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "tsmuxcommon.h"
+#include "tsmuxstream.h"
+
+static guint8 tsmux_stream_pes_header_length (TsMuxStream * stream);
+static void tsmux_stream_write_pes_header (TsMuxStream * stream, guint8 * data);
+static void tsmux_stream_find_pts_dts_within (TsMuxStream * stream, guint bound,
+ gint64 * pts, gint64 * dts);
+
+struct TsMuxStreamBuffer
+{
+ guint8 *data;
+ guint32 size;
+
+ /* PTS & DTS associated with the contents of this buffer */
+ gint64 pts;
+ gint64 dts;
+
+ void *user_data;
+};
+
+/**
+ * tsmux_stream_new:
+ * @pid: a PID
+ * @stream_type: the stream type
+ *
+ * Create a new stream with PID of @pid and @stream_type.
+ *
+ * Returns: a new #TsMuxStream.
+ */
+TsMuxStream *
+tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type)
+{
+ TsMuxStream *stream = g_new0 (TsMuxStream, 1);
+
+ stream->state = TSMUX_STREAM_STATE_HEADER;
+ stream->pi.pid = pid;
+ stream->stream_type = stream_type;
+
+ stream->pes_payload_size = 0;
+ stream->cur_pes_payload_size = 0;
+ stream->pes_bytes_written = 0;
+
+ switch (stream_type) {
+ case TSMUX_ST_VIDEO_MPEG1:
+ case TSMUX_ST_VIDEO_MPEG2:
+ case TSMUX_ST_VIDEO_MPEG4:
+ case TSMUX_ST_VIDEO_H264:
+ /* FIXME: Assign sequential IDs? */
+ stream->id = 0xE0;
+ stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
+ stream->is_video_stream = TRUE;
+ break;
+ case TSMUX_ST_AUDIO_AAC:
+ case TSMUX_ST_AUDIO_MPEG1:
+ case TSMUX_ST_AUDIO_MPEG2:
+ /* FIXME: Assign sequential IDs? */
+ stream->id = 0xC0;
+ stream->pi.flags |= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
+ break;
+ case TSMUX_ST_VIDEO_DIRAC:
+ stream->id = 0xFD;
+ /* FIXME: assign sequential extended IDs? */
+ stream->id_extended = 0x60;
+
+ stream->pi.flags |=
+ TSMUX_PACKET_FLAG_PES_FULL_HEADER |
+ TSMUX_PACKET_FLAG_PES_EXT_STREAMID;
+ stream->is_video_stream = TRUE;
+ break;
+ default:
+ g_critical ("Stream type 0x%0x not yet implemented", stream_type);
+ break;
+ }
+
+ stream->last_pts = -1;
+ stream->last_dts = -1;
+
+ stream->pcr_ref = 0;
+ stream->last_pcr = -1;
+
+ return stream;
+}
+
+/**
+ * tsmux_stream_get_pid:
+ * @stream: a #TsMuxStream
+ *
+ * Get the PID of @stream.
+ *
+ * Returns: The PID of @stream. 0xffff on error.
+ */
+guint16
+tsmux_stream_get_pid (TsMuxStream * stream)
+{
+ g_return_val_if_fail (stream != NULL, G_MAXUINT16);
+
+ return stream->pi.pid;
+}
+
+/**
+ * tsmux_stream_free:
+ * @stream: a #TsMuxStream
+ *
+ * Free the resources of @stream.
+ */
+void
+tsmux_stream_free (TsMuxStream * stream)
+{
+ g_return_if_fail (stream != NULL);
+
+ g_free (stream);
+}
+
+/**
+ * tsmux_stream_set_buffer_release_func:
+ * @stream: a #TsMuxStream
+ * @func: the new #TsMuxStreamBufferReleaseFunc
+ *
+ * Set the function that will be called when a a piece of data fed to @stream
+ * with tsmux_stream_add_data() can be freed. @func will be called with user
+ * data as provided with the call to tsmux_stream_add_data().
+ */
+void
+tsmux_stream_set_buffer_release_func (TsMuxStream * stream,
+ TsMuxStreamBufferReleaseFunc func)
+{
+ g_return_if_fail (stream != NULL);
+
+ stream->buffer_release = func;
+}
+
+/* Advance the current packet stream position by len bytes.
+ * Mustn't consume more than available in the current packet */
+static void
+tsmux_stream_consume (TsMuxStream * stream, guint len)
+{
+ g_assert (stream->cur_buffer != NULL);
+ g_assert (len <= stream->cur_buffer->size - stream->cur_buffer_consumed);
+
+ stream->cur_buffer_consumed += len;
+ stream->bytes_avail -= len;
+
+ if (stream->cur_buffer_consumed == 0)
+ return;
+
+ if (stream->cur_buffer->pts != -1) {
+ stream->last_pts = stream->cur_buffer->pts;
+ stream->last_dts = stream->cur_buffer->dts;
+ } else if (stream->cur_buffer->dts != -1)
+ stream->last_dts = stream->cur_buffer->dts;
+
+ if (stream->cur_buffer_consumed == stream->cur_buffer->size) {
+ /* Current packet is completed, move along */
+ stream->buffers = g_list_delete_link (stream->buffers, stream->buffers);
+
+ if (stream->buffer_release) {
+ stream->buffer_release (stream->cur_buffer->data,
+ stream->cur_buffer->user_data);
+ }
+
+ g_free (stream->cur_buffer);
+ stream->cur_buffer = NULL;
+ /* FIXME: As a hack, for unbounded streams, start a new PES packet for each
+ * incoming packet we receive. This assumes that incoming data is
+ * packetised sensibly - ie, every video frame */
+ if (stream->cur_pes_payload_size == 0)
+ stream->state = TSMUX_STREAM_STATE_HEADER;
+ }
+}
+
+/**
+ * tsmux_stream_at_pes_start:
+ * @stream: a #TsMuxStream
+ *
+ * Check if @stream is at the start of a PES packet.
+ *
+ * Returns: TRUE if @stream is at a PES header packet.
+ */
+gboolean
+tsmux_stream_at_pes_start (TsMuxStream * stream)
+{
+ g_return_val_if_fail (stream != NULL, FALSE);
+
+ return stream->state == TSMUX_STREAM_STATE_HEADER;
+}
+
+/**
+ * tsmux_stream_bytes_avail:
+ * @stream: a #TsMuxStream
+ *
+ * Calculate how much bytes are available.
+ *
+ * Returns: The number of bytes available.
+ */
+gint
+tsmux_stream_bytes_avail (TsMuxStream * stream)
+{
+ gint bytes_avail;
+
+ g_return_val_if_fail (stream != NULL, 0);
+
+ if (stream->cur_pes_payload_size != 0)
+ bytes_avail = stream->cur_pes_payload_size - stream->pes_bytes_written;
+ else
+ bytes_avail = tsmux_stream_bytes_in_buffer (stream);
+
+ bytes_avail = MIN (bytes_avail, tsmux_stream_bytes_in_buffer (stream));
+
+ /* Calculate the number of bytes available in the current PES */
+ if (stream->state == TSMUX_STREAM_STATE_HEADER)
+ bytes_avail += tsmux_stream_pes_header_length (stream);
+
+ return bytes_avail;
+}
+
+/**
+ * tsmux_stream_bytes_in_buffer:
+ * @stream: a #TsMuxStream
+ *
+ * Calculate how much bytes are in the buffer.
+ *
+ * Returns: The number of bytes in the buffer.
+ */
+gint
+tsmux_stream_bytes_in_buffer (TsMuxStream * stream)
+{
+ g_return_val_if_fail (stream != NULL, 0);
+
+ return stream->bytes_avail;
+}
+
+/**
+ * tsmux_stream_get_data:
+ * @stream: a #TsMuxStream
+ * @buf: a buffer to hold the result
+ * @len: the length of @buf
+ *
+ * Copy up to @len available data in @stream into the buffer @buf.
+ *
+ * Returns: TRUE if @len bytes could be retrieved.
+ */
+gboolean
+tsmux_stream_get_data (TsMuxStream * stream, guint8 * buf, guint len)
+{
+ g_return_val_if_fail (stream != NULL, FALSE);
+ g_return_val_if_fail (buf != NULL, FALSE);
+
+ if (stream->state == TSMUX_STREAM_STATE_HEADER) {
+ guint8 pes_hdr_length;
+
+ if (stream->pes_payload_size != 0) {
+ /* Use prescribed fixed PES payload size */
+ stream->cur_pes_payload_size = stream->pes_payload_size;
+ tsmux_stream_find_pts_dts_within (stream, stream->cur_pes_payload_size,
+ &stream->pts, &stream->dts);
+ } else if (stream->is_video_stream) {
+ /* Unbounded for video streams */
+ stream->cur_pes_payload_size = 0;
+ tsmux_stream_find_pts_dts_within (stream,
+ tsmux_stream_bytes_in_buffer (stream), &stream->pts, &stream->dts);
+ } else {
+ /* Output a PES packet of all currently available bytes otherwise */
+ stream->cur_pes_payload_size = tsmux_stream_bytes_in_buffer (stream);
+ tsmux_stream_find_pts_dts_within (stream, stream->cur_pes_payload_size,
+ &stream->pts, &stream->dts);
+ }
+
+ stream->pi.flags &= ~(TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS |
+ TSMUX_PACKET_FLAG_PES_WRITE_PTS);
+
+ if (stream->pts != -1 && stream->dts != -1)
+ stream->pi.flags |= TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS;
+ else {
+ if (stream->pts != -1)
+ stream->pi.flags |= TSMUX_PACKET_FLAG_PES_WRITE_PTS;
+ }
+
+ pes_hdr_length = tsmux_stream_pes_header_length (stream);
+
+ /* Submitted buffer must be at least as large as the PES header */
+ if (len < pes_hdr_length)
+ return FALSE;
+
+ TS_DEBUG ("Writing PES header of length %u and payload %d",
+ pes_hdr_length, stream->cur_pes_payload_size);
+ tsmux_stream_write_pes_header (stream, buf);
+
+ len -= pes_hdr_length;
+ buf += pes_hdr_length;
+
+ stream->state = TSMUX_STREAM_STATE_PACKET;
+ }
+
+ if (len > (guint) tsmux_stream_bytes_avail (stream))
+ return FALSE;
+
+ stream->pes_bytes_written += len;
+
+ if (stream->cur_pes_payload_size != 0 &&
+ stream->pes_bytes_written == stream->cur_pes_payload_size) {
+ TS_DEBUG ("Finished PES packet");
+ stream->state = TSMUX_STREAM_STATE_HEADER;
+ stream->pes_bytes_written = 0;
+ }
+
+ while (len > 0) {
+ guint32 avail;
+ guint8 *cur;
+
+ if (stream->cur_buffer == NULL) {
+ /* Start next packet */
+ if (stream->buffers == NULL)
+ return FALSE;
+ stream->cur_buffer = (TsMuxStreamBuffer *) (stream->buffers->data);
+ stream->cur_buffer_consumed = 0;
+ }
+
+ /* Take as much as we can from the current buffer */
+ avail = stream->cur_buffer->size - stream->cur_buffer_consumed;
+ cur = stream->cur_buffer->data + stream->cur_buffer_consumed;
+ if (avail < len) {
+ memcpy (buf, cur, avail);
+ tsmux_stream_consume (stream, avail);
+
+ buf += avail;
+ len -= avail;
+ } else {
+ memcpy (buf, cur, len);
+ tsmux_stream_consume (stream, len);
+
+ len = 0;
+ }
+ }
+
+ return TRUE;
+}
+
+static guint8
+tsmux_stream_pes_header_length (TsMuxStream * stream)
+{
+ guint8 packet_len;
+
+ /* Calculate the length of the header for this stream */
+
+ /* start_code prefix + stream_id + pes_packet_length = 6 bytes */
+ packet_len = 6;
+
+ if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_FULL_HEADER) {
+ /* For a PES 'full header' we have at least 3 more bytes,
+ * and then more based on flags */
+ packet_len += 3;
+ if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS) {
+ packet_len += 10;
+ } else if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_WRITE_PTS) {
+ packet_len += 5;
+ }
+ if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_EXT_STREAMID) {
+ /* Need basic extension flags (1 byte), plus 2 more bytes for the
+ * length + extended stream id */
+ packet_len += 3;
+ }
+ }
+
+ return packet_len;
+}
+
+/* Find a PTS/DTS to write into the pes header within the next bound bytes
+ * of the data */
+static void
+tsmux_stream_find_pts_dts_within (TsMuxStream * stream, guint bound,
+ gint64 * pts, gint64 * dts)
+{
+ GList *cur;
+
+ *pts = -1;
+ *dts = -1;
+
+ for (cur = g_list_first (stream->buffers); cur != NULL;
+ cur = g_list_next (cur)) {
+ TsMuxStreamBuffer *curbuf = cur->data;
+
+ /* FIXME: This isn't quite correct - if the 'bound' is within this
+ * buffer, we don't know if the timestamp is before or after the split
+ * so we shouldn't return it */
+ if (bound <= curbuf->size) {
+ *pts = curbuf->pts;
+ *dts = curbuf->dts;
+ return;
+ }
+
+ /* Have we found a buffer with pts/dts set? */
+ if (curbuf->pts != -1 || curbuf->dts != -1) {
+ *pts = curbuf->pts;
+ *dts = curbuf->dts;
+ return;
+ }
+
+ bound -= curbuf->size;
+ }
+}
+
+static void
+tsmux_stream_write_pes_header (TsMuxStream * stream, guint8 * data)
+{
+ guint16 length_to_write;
+ guint8 hdr_len = tsmux_stream_pes_header_length (stream);
+
+ /* start_code prefix + stream_id + pes_packet_length = 6 bytes */
+ data[0] = 0x00;
+ data[1] = 0x00;
+ data[2] = 0x01;
+ data[3] = stream->id;
+ data += 4;
+
+ /* Write 2 byte PES packet length here. 0 (unbounded) is only
+ * valid for video packets */
+ if (stream->cur_pes_payload_size != 0) {
+ length_to_write = hdr_len + stream->cur_pes_payload_size - 6;
+ } else {
+ length_to_write = 0;
+ }
+
+ tsmux_put16 (&data, length_to_write);
+
+ if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_FULL_HEADER) {
+ guint8 flags = 0;
+
+ /* Not scrambled, original, not-copyrighted, data_alignment not specified */
+ *data++ = 0x81;
+
+ /* Flags */
+ if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS)
+ flags |= 0xC0;
+ else if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_WRITE_PTS)
+ flags |= 0x80;
+ if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_EXT_STREAMID)
+ flags |= 0x01; /* Enable PES_extension_flag */
+ *data++ = flags;
+
+ /* Header length is the total pes length,
+ * minus the 9 bytes of start codes, flags + hdr_len */
+ g_return_if_fail (hdr_len >= 9);
+ *data++ = (hdr_len - 9);
+
+ if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS) {
+ tsmux_put_ts (&data, 0x3, stream->pts);
+ tsmux_put_ts (&data, 0x1, stream->dts);
+ } else if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_WRITE_PTS) {
+ tsmux_put_ts (&data, 0x2, stream->pts);
+ }
+ if (stream->pi.flags & TSMUX_PACKET_FLAG_PES_EXT_STREAMID) {
+ guint8 ext_len;
+
+ flags = 0x0f; /* (reserved bits) | PES_extension_flag_2 */
+ *data++ = flags;
+
+ ext_len = 1; /* Only writing 1 byte into the extended fields */
+ *data++ = 0x80 | ext_len;
+ /* Write the extended streamID */
+ *data++ = 0x80 | stream->id_extended;
+ }
+ }
+}
+
+/**
+ * tsmux_stream_add_data:
+ * @stream: a #TsMuxStream
+ * @data: data to add
+ * @len: length of @data
+ * @user_data: user data to pass to release func
+ * @pts: PTS of access unit in @data
+ * @dts: DTS of access unit in @data
+ *
+ * Submit @len bytes of @data into @stream. @pts and @dts can be set to the
+ * timestamp (against a 90Hz clock) of the first access unit in @data. A
+ * timestamp of -1 for @pts or @dts means unknown.
+ *
+ * @user_data will be passed to the release function as set with
+ * tsmux_stream_set_buffer_release_func() when @data can be freed.
+ */
+void
+tsmux_stream_add_data (TsMuxStream * stream, guint8 * data, guint len,
+ void *user_data, gint64 pts, gint64 dts)
+{
+ TsMuxStreamBuffer *packet;
+
+ g_return_if_fail (stream != NULL);
+
+ packet = g_new (TsMuxStreamBuffer, 1);
+ packet->data = data;
+ packet->size = len;
+ packet->user_data = user_data;
+
+ packet->pts = pts;
+ packet->dts = dts;
+
+ if (stream->bytes_avail == 0)
+ stream->last_pts = pts;
+
+ stream->bytes_avail += len;
+ stream->buffers = g_list_append (stream->buffers, packet);
+}
+
+/**
+ * tsmux_stream_get_es_descrs:
+ * @stream: a #TsMuxStream
+ * @buf: a buffer to hold the ES descriptor
+ * @len: the length used in @buf
+ *
+ * Write an Elementary Stream Descriptor for @stream into @buf. the number of
+ * bytes consumed in @buf will be updated in @len.
+ *
+ * @buf and @len must be at least #TSMUX_MIN_ES_DESC_LEN.
+ */
+void
+tsmux_stream_get_es_descrs (TsMuxStream * stream, guint8 * buf, guint16 * len)
+{
+ guint8 *pos;
+
+ g_return_if_fail (stream != NULL);
+
+ if (buf == NULL) {
+ if (len != NULL)
+ *len = 0;
+ return;
+ }
+
+ /* Based on the stream type, write out any descriptors to go in the
+ * PMT ES_info field */
+ pos = buf;
+
+ switch (stream->stream_type) {
+ case TSMUX_ST_VIDEO_DIRAC:
+ /* tag (registration_descriptor), length, format_identifier */
+ *pos++ = 0x05;
+ *pos++ = 4;
+ *pos++ = 0x64; /* 'd' */
+ *pos++ = 0x72; /* 'r' */
+ *pos++ = 0x61; /* 'a' */
+ *pos++ = 0x63; /* 'c' */
+ break;
+ default:
+ break;
+ }
+
+ if (len)
+ *len = (pos - buf);
+}
+
+/**
+ * tsmux_stream_pcr_ref:
+ * @stream: a #TsMuxStream
+ *
+ * Mark the stream as being used as the PCR for some program.
+ */
+void
+tsmux_stream_pcr_ref (TsMuxStream * stream)
+{
+ g_return_if_fail (stream != NULL);
+
+ stream->pcr_ref++;
+}
+
+/**
+ * tsmux_stream_pcr_unref:
+ * @stream: a #TsMuxStream
+ *
+ * Mark the stream as no longer being used as the PCR for some program.
+ */
+void
+tsmux_stream_pcr_unref (TsMuxStream * stream)
+{
+ g_return_if_fail (stream != NULL);
+
+ stream->pcr_ref--;
+}
+
+/**
+ * tsmux_stream_is_pcr:
+ * @stream: a #TsMuxStream
+ *
+ * Check if @stream is used as the PCR for some program.
+ *
+ * Returns: TRUE if the stream is in use as the PCR for some program.
+ */
+gboolean
+tsmux_stream_is_pcr (TsMuxStream * stream)
+{
+ return stream->pcr_ref != 0;
+}
+
+/**
+ * tsmux_stream_get_pts:
+ * @stream: a #TsMuxStream
+ *
+ * Return the PTS of the last buffer that has had bytes written and
+ * which _had_ a PTS in @stream.
+ *
+ * Returns: the PTS of the last buffer in @stream.
+ */
+guint64
+tsmux_stream_get_pts (TsMuxStream * stream)
+{
+ g_return_val_if_fail (stream != NULL, -1);
+
+ return stream->last_pts;
+}
diff --git a/gst/mpegtsmux/tsmux/tsmuxstream.h b/gst/mpegtsmux/tsmux/tsmuxstream.h
new file mode 100644
index 00000000..9cc049ad
--- /dev/null
+++ b/gst/mpegtsmux/tsmux/tsmuxstream.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2006 BBC and Fluendo S.A.
+ *
+ * This library is licensed under 4 different licenses and you
+ * can choose to use it under the terms of any one of them. The
+ * four licenses are the MPL 1.1, the LGPL, the GPL and the MIT
+ * license.
+ *
+ * MPL:
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * LGPL:
+ *
+ * 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.
+ *
+ * GPL:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * MIT:
+ *
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef __TSMUXSTREAM_H__
+#define __TSMUXSTREAM_H__
+
+#include <glib.h>
+
+#include <tsmux/tsmuxcommon.h>
+
+G_BEGIN_DECLS
+
+typedef enum TsMuxStreamType TsMuxStreamType;
+typedef enum TsMuxStreamState TsMuxStreamState;
+typedef struct TsMuxStreamBuffer TsMuxStreamBuffer;
+
+typedef void (*TsMuxStreamBufferReleaseFunc) (guint8 *data, void *user_data);
+
+/* Stream type assignments
+ *
+ * 0x00 ITU-T | ISO/IEC Reserved
+ * 0x01 ISO/IEC 11172 Video
+ * 0x02 ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or
+ * ISO/IEC 11172-2 constrained parameter video
+ * stream
+ * 0x03 ISO/IEC 11172 Audio
+ * 0x04 ISO/IEC 13818-3 Audio
+ * 0x05 ITU-T Rec. H.222.0 | ISO/IEC 13818-1
+ * private_sections
+ * 0x06 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES
+ * packets containing private data
+ * 0x07 ISO/IEC 13522 MHEG
+ * 0x08 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A
+ * DSM CC
+ * 0x09 ITU-T Rec. H.222.1
+ * 0x0A ISO/IEC 13818-6 type A
+ * 0x0B ISO/IEC 13818-6 type B
+ * 0x0C ISO/IEC 13818-6 type C
+ * 0x0D ISO/IEC 13818-6 type D
+ * 0x0E ISO/IEC 13818-1 auxiliary
+ * 0x0F-0x7F ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved
+ * 0x80-0xFF User Private
+ */
+enum TsMuxStreamType {
+ TSMUX_ST_RESERVED = 0x00,
+ TSMUX_ST_VIDEO_MPEG1 = 0x01,
+ TSMUX_ST_VIDEO_MPEG2 = 0x02,
+ TSMUX_ST_AUDIO_MPEG1 = 0x03,
+ TSMUX_ST_AUDIO_MPEG2 = 0x04,
+ TSMUX_ST_PRIVATE_SECTIONS = 0x05,
+ TSMUX_ST_PRIVATE_DATA = 0x06,
+ TSMUX_ST_MHEG = 0x07,
+ TSMUX_ST_DSMCC = 0x08,
+ TSMUX_ST_H222_1 = 0x09,
+
+ /* later extensions */
+ TSMUX_ST_AUDIO_AAC = 0x0f,
+ TSMUX_ST_VIDEO_MPEG4 = 0x10,
+ TSMUX_ST_VIDEO_H264 = 0x1b,
+
+ /* private stream types */
+ TSMUX_ST_PS_AUDIO_AC3 = 0x81,
+ TSMUX_ST_PS_AUDIO_DTS = 0x8a,
+ TSMUX_ST_PS_AUDIO_LPCM = 0x8b,
+ TSMUX_ST_PS_DVD_SUBPICTURE = 0xff,
+
+ /* Non-standard definitions */
+ TSMUX_ST_VIDEO_DIRAC = 0xD1
+};
+
+enum TsMuxStreamState {
+ TSMUX_STREAM_STATE_HEADER,
+ TSMUX_STREAM_STATE_PACKET
+};
+
+/* TsMuxStream receives elementary streams for parsing.
+ * Via the write_bytes() method, it can output a PES stream piecemeal */
+struct TsMuxStream {
+ TsMuxStreamState state;
+ TsMuxPacketInfo pi;
+ TsMuxStreamType stream_type;
+ guint8 id; /* stream id */
+ guint8 id_extended; /* extended stream id (13818-1 Amdt 2) */
+
+ gboolean is_video_stream;
+
+ /* List of data buffers available for writing out */
+ GList *buffers;
+ guint32 bytes_avail;
+
+ /* Current data buffer being consumed */
+ TsMuxStreamBuffer *cur_buffer;
+ guint32 cur_buffer_consumed;
+
+ TsMuxStreamBufferReleaseFunc buffer_release;
+
+ guint16 pes_payload_size;
+ guint16 cur_pes_payload_size;
+ guint16 pes_bytes_written;
+
+ /* PTS/DTS to write if the flags in the packet info are set */
+ gint64 pts;
+ gint64 dts;
+
+ gint64 last_pts;
+ gint64 last_dts;
+
+ gint pcr_ref;
+ gint64 last_pcr;
+};
+
+/* stream management */
+TsMuxStream * tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type);
+void tsmux_stream_free (TsMuxStream *stream);
+
+guint16 tsmux_stream_get_pid (TsMuxStream *stream);
+
+void tsmux_stream_set_buffer_release_func (TsMuxStream *stream,
+ TsMuxStreamBufferReleaseFunc func);
+
+/* Add a new buffer to the pool of available bytes. If pts or dts are not -1, they
+ * indicate the PTS or DTS of the first access unit within this packet */
+void tsmux_stream_add_data (TsMuxStream *stream, guint8 *data, guint len,
+ void *user_data, gint64 pts, gint64 dts);
+
+void tsmux_stream_pcr_ref (TsMuxStream *stream);
+void tsmux_stream_pcr_unref (TsMuxStream *stream);
+gboolean tsmux_stream_is_pcr (TsMuxStream *stream);
+
+gboolean tsmux_stream_at_pes_start (TsMuxStream *stream);
+void tsmux_stream_get_es_descrs (TsMuxStream *stream, guint8 *buf, guint16 *len);
+
+gint tsmux_stream_bytes_in_buffer (TsMuxStream *stream);
+gint tsmux_stream_bytes_avail (TsMuxStream *stream);
+gboolean tsmux_stream_get_data (TsMuxStream *stream, guint8 *buf, guint len);
+
+guint64 tsmux_stream_get_pts (TsMuxStream *stream);
+
+G_END_DECLS
+
+#endif