Add Fluendo MPEG-TS muxer and libtsmux to gst-plugins-bad. This is renamed to mpegtsmux to prevent conflicts. Also al...

Original commit message from CVS:
* configure.ac:
* gst/mpegtsmux/Makefile.am:
* gst/mpegtsmux/mpegtsmux.c: (mpegtsmux_base_init),
(mpegtsmux_class_init), (mpegtsmux_init), (mpegtsmux_dispose),
(gst_mpegtsmux_set_property), (gst_mpegtsmux_get_property),
(release_buffer_cb), (mpegtsmux_create_stream),
(mpegtsmux_create_streams), (mpegtsmux_choose_best_stream),
(mpegtsmux_collected), (mpegtsmux_request_new_pad),
(mpegtsmux_release_pad), (new_packet_cb),
(mpegtsdemux_prepare_srcpad), (mpegtsmux_change_state),
(plugin_init):
* gst/mpegtsmux/mpegtsmux.h:
* gst/mpegtsmux/mpegtsmux_aac.c: (mpegtsmux_prepare_aac):
* gst/mpegtsmux/mpegtsmux_aac.h:
* gst/mpegtsmux/mpegtsmux_h264.c: (mpegtsmux_prepare_h264):
* gst/mpegtsmux/mpegtsmux_h264.h:
* gst/mpegtsmux/tsmux/Makefile.am:
* gst/mpegtsmux/tsmux/crc.h:
* gst/mpegtsmux/tsmux/tsmux.c: (tsmux_new), (tsmux_set_write_func),
(tsmux_set_pat_frequency), (tsmux_get_pat_frequency), (tsmux_free),
(tsmux_program_new), (tsmux_set_pmt_frequency),
(tsmux_get_pmt_frequency), (tsmux_program_add_stream),
(tsmux_program_set_pcr_stream), (tsmux_get_new_pid),
(tsmux_create_stream), (tsmux_find_stream), (tsmux_packet_out),
(tsmux_write_adaptation_field), (tsmux_write_ts_header),
(tsmux_write_stream_packet), (tsmux_program_free),
(tsmux_write_section), (tsmux_write_section_hdr),
(tsmux_write_pat), (tsmux_write_pmt):
* gst/mpegtsmux/tsmux/tsmux.h:
* gst/mpegtsmux/tsmux/tsmuxcommon.h:
* gst/mpegtsmux/tsmux/tsmuxstream.c: (tsmux_stream_new),
(tsmux_stream_get_pid), (tsmux_stream_free),
(tsmux_stream_set_buffer_release_func), (tsmux_stream_consume),
(tsmux_stream_at_pes_start), (tsmux_stream_bytes_avail),
(tsmux_stream_bytes_in_buffer), (tsmux_stream_get_data),
(tsmux_stream_pes_header_length),
(tsmux_stream_find_pts_dts_within),
(tsmux_stream_write_pes_header), (tsmux_stream_add_data),
(tsmux_stream_get_es_descrs), (tsmux_stream_pcr_ref),
(tsmux_stream_pcr_unref), (tsmux_stream_is_pcr),
(tsmux_stream_get_pts):
* gst/mpegtsmux/tsmux/tsmuxstream.h:
Add Fluendo MPEG-TS muxer and libtsmux to gst-plugins-bad. This
is renamed to mpegtsmux to prevent conflicts. Also all relevant
informations about copyright and license are added to the top of
every file but apart from that no changes compared to the latest
SVN versions happened.
This commit is contained in:
Sebastian Dröge 2008-09-01 16:38:40 +00:00
parent 122498e169
commit 845094c32e
16 changed files with 3973 additions and 0 deletions

View file

@ -1,3 +1,53 @@
2008-09-01 Sebastian Dröge <sebastian.droege@collabora.co.uk>
* configure.ac:
* gst/mpegtsmux/Makefile.am:
* gst/mpegtsmux/mpegtsmux.c: (mpegtsmux_base_init),
(mpegtsmux_class_init), (mpegtsmux_init), (mpegtsmux_dispose),
(gst_mpegtsmux_set_property), (gst_mpegtsmux_get_property),
(release_buffer_cb), (mpegtsmux_create_stream),
(mpegtsmux_create_streams), (mpegtsmux_choose_best_stream),
(mpegtsmux_collected), (mpegtsmux_request_new_pad),
(mpegtsmux_release_pad), (new_packet_cb),
(mpegtsdemux_prepare_srcpad), (mpegtsmux_change_state),
(plugin_init):
* gst/mpegtsmux/mpegtsmux.h:
* gst/mpegtsmux/mpegtsmux_aac.c: (mpegtsmux_prepare_aac):
* gst/mpegtsmux/mpegtsmux_aac.h:
* gst/mpegtsmux/mpegtsmux_h264.c: (mpegtsmux_prepare_h264):
* gst/mpegtsmux/mpegtsmux_h264.h:
* gst/mpegtsmux/tsmux/Makefile.am:
* gst/mpegtsmux/tsmux/crc.h:
* gst/mpegtsmux/tsmux/tsmux.c: (tsmux_new), (tsmux_set_write_func),
(tsmux_set_pat_frequency), (tsmux_get_pat_frequency), (tsmux_free),
(tsmux_program_new), (tsmux_set_pmt_frequency),
(tsmux_get_pmt_frequency), (tsmux_program_add_stream),
(tsmux_program_set_pcr_stream), (tsmux_get_new_pid),
(tsmux_create_stream), (tsmux_find_stream), (tsmux_packet_out),
(tsmux_write_adaptation_field), (tsmux_write_ts_header),
(tsmux_write_stream_packet), (tsmux_program_free),
(tsmux_write_section), (tsmux_write_section_hdr),
(tsmux_write_pat), (tsmux_write_pmt):
* gst/mpegtsmux/tsmux/tsmux.h:
* gst/mpegtsmux/tsmux/tsmuxcommon.h:
* gst/mpegtsmux/tsmux/tsmuxstream.c: (tsmux_stream_new),
(tsmux_stream_get_pid), (tsmux_stream_free),
(tsmux_stream_set_buffer_release_func), (tsmux_stream_consume),
(tsmux_stream_at_pes_start), (tsmux_stream_bytes_avail),
(tsmux_stream_bytes_in_buffer), (tsmux_stream_get_data),
(tsmux_stream_pes_header_length),
(tsmux_stream_find_pts_dts_within),
(tsmux_stream_write_pes_header), (tsmux_stream_add_data),
(tsmux_stream_get_es_descrs), (tsmux_stream_pcr_ref),
(tsmux_stream_pcr_unref), (tsmux_stream_is_pcr),
(tsmux_stream_get_pts):
* gst/mpegtsmux/tsmux/tsmuxstream.h:
Add Fluendo MPEG-TS muxer and libtsmux to gst-plugins-bad. This
is renamed to mpegtsmux to prevent conflicts. Also all relevant
informations about copyright and license are added to the top of
every file but apart from that no changes compared to the latest
SVN versions happened.
2008-09-01 Wim Taymans <wim.taymans@collabora.co.uk>
* gst/selector/gstinputselector.c: (gst_input_selector_init),

View file

@ -257,6 +257,7 @@ AG_GST_CHECK_PLUGIN(h264parse)
AG_GST_CHECK_PLUGIN(librfb)
AG_GST_CHECK_PLUGIN(modplug)
AG_GST_CHECK_PLUGIN(mpegtsparse)
AG_GST_CHECK_PLUGIN(mpegtsmux)
AG_GST_CHECK_PLUGIN(mpeg4videoparse)
AG_GST_CHECK_PLUGIN(mpegvideoparse)
AG_GST_CHECK_PLUGIN(mve)
@ -1399,6 +1400,8 @@ gst/librfb/Makefile
gst/modplug/Makefile
gst/modplug/libmodplug/Makefile
gst/mpegtsparse/Makefile
gst/mpegtsmux/Makefile
gst/mpegtsmux/tsmux/Makefile
gst/mpeg4videoparse/Makefile
gst/mpegvideoparse/Makefile
gst/mve/Makefile

17
gst/mpegtsmux/Makefile.am Normal file
View file

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

821
gst/mpegtsmux/mpegtsmux.c Normal file
View file

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

163
gst/mpegtsmux/mpegtsmux.h Normal file
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

58
gst/mpegtsmux/tsmux/crc.h Normal file
View file

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

1056
gst/mpegtsmux/tsmux/tsmux.c Normal file

File diff suppressed because it is too large Load diff

183
gst/mpegtsmux/tsmux/tsmux.h Normal file
View file

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

View file

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

View file

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

View file

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