mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
mpegtsmux: port to 0.11
https://bugzilla.gnome.org/show_bug.cgi?id=678130
This commit is contained in:
parent
830e8b6ec6
commit
6229305d7b
9 changed files with 264 additions and 555 deletions
|
@ -315,7 +315,7 @@ GST_PLUGINS_NONPORTED=" aiff \
|
|||
dccp faceoverlay festival \
|
||||
fieldanalysis freeverb freeze frei0r \
|
||||
hdvparse id3tag inter interlace ivfparse jpegformat jp2kdecimator \
|
||||
kate liveadder librfb mpegtsmux \
|
||||
kate liveadder librfb \
|
||||
mpegpsmux mve mxf mythtv nsf nuvdemux \
|
||||
patchdetect pnm real \
|
||||
sdi siren speed subenc stereo tta videofilters \
|
||||
|
|
|
@ -4,7 +4,6 @@ SUBDIRS = tsmux
|
|||
|
||||
libgstmpegtsmux_la_SOURCES = \
|
||||
mpegtsmux.c \
|
||||
mpegtsmux_h264.c \
|
||||
mpegtsmux_aac.c
|
||||
|
||||
libgstmpegtsmux_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
|
||||
|
@ -15,5 +14,4 @@ libgstmpegtsmux_la_LIBTOOLFLAGS = --tag=disable-static
|
|||
|
||||
noinst_HEADERS = \
|
||||
mpegtsmux.h \
|
||||
mpegtsmux_h264.h \
|
||||
mpegtsmux_aac.h
|
||||
|
|
|
@ -96,7 +96,6 @@
|
|||
|
||||
#include "mpegtsmux.h"
|
||||
|
||||
#include "mpegtsmux_h264.h"
|
||||
#include "mpegtsmux_aac.h"
|
||||
|
||||
GST_DEBUG_CATEGORY (mpegtsmux_debug);
|
||||
|
@ -162,64 +161,83 @@ static gboolean new_packet_m2ts (MpegTsMux * mux, GstBuffer * buf,
|
|||
gint64 new_pcr);
|
||||
|
||||
static void mpegtsdemux_prepare_srcpad (MpegTsMux * mux);
|
||||
static GstFlowReturn mpegtsmux_collected (GstCollectPads2 * pads,
|
||||
static GstFlowReturn mpegtsmux_collected (GstCollectPads * pads,
|
||||
MpegTsMux * mux);
|
||||
static gboolean mpegtsmux_sink_event (GstCollectPads2 * pads,
|
||||
GstCollectData2 * data, GstEvent * event, gpointer user_data);
|
||||
static gboolean mpegtsmux_sink_event (GstCollectPads * pads,
|
||||
GstCollectData * data, GstEvent * event, gpointer user_data);
|
||||
static GstPad *mpegtsmux_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * name);
|
||||
GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
|
||||
static void mpegtsmux_release_pad (GstElement * element, GstPad * pad);
|
||||
static GstStateChangeReturn mpegtsmux_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
static void mpegtsdemux_set_header_on_caps (MpegTsMux * mux);
|
||||
static gboolean mpegtsmux_src_event (GstPad * pad, GstEvent * event);
|
||||
static gboolean mpegtsmux_src_event (GstPad * pad, GstObject * parent,
|
||||
GstEvent * event);
|
||||
|
||||
#if 0
|
||||
static void mpegtsmux_set_index (GstElement * element, GstIndex * index);
|
||||
static GstIndex *mpegtsmux_get_index (GstElement * element);
|
||||
|
||||
static GstFormat pts_format;
|
||||
static GstFormat spn_format;
|
||||
#endif
|
||||
|
||||
GST_BOILERPLATE (MpegTsMux, mpegtsmux, GstElement, GST_TYPE_ELEMENT);
|
||||
typedef struct
|
||||
{
|
||||
GstMapInfo map_info;
|
||||
GstBuffer *buffer;
|
||||
} StreamData;
|
||||
|
||||
G_DEFINE_TYPE (MpegTsMux, mpegtsmux, GST_TYPE_ELEMENT)
|
||||
|
||||
static StreamData *stream_data_new (GstBuffer * buffer)
|
||||
{
|
||||
StreamData *res = g_new (StreamData, 1);
|
||||
res->buffer = buffer;
|
||||
gst_buffer_map (buffer, &(res->map_info), GST_MAP_READ);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
mpegtsmux_base_init (gpointer g_class)
|
||||
stream_data_free (StreamData * data)
|
||||
{
|
||||
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
||||
|
||||
gst_element_class_add_static_pad_template (element_class,
|
||||
&mpegtsmux_sink_factory);
|
||||
gst_element_class_add_static_pad_template (element_class,
|
||||
&mpegtsmux_src_factory);
|
||||
|
||||
gst_element_class_set_details_simple (element_class,
|
||||
"MPEG Transport Stream Muxer", "Codec/Muxer",
|
||||
"Multiplexes media streams into an MPEG Transport Stream",
|
||||
"Fluendo <contact@fluendo.com>");
|
||||
|
||||
pts_format =
|
||||
gst_format_register ("PTS", "MPEG System Presentation Time Stamp");
|
||||
spn_format = gst_format_register ("SPN", "Source Packet Number");
|
||||
if (data) {
|
||||
gst_buffer_unmap (data->buffer, &data->map_info);
|
||||
gst_buffer_unref (data->buffer);
|
||||
g_free (data);
|
||||
}
|
||||
}
|
||||
|
||||
#define parent_class mpegtsmux_parent_class
|
||||
|
||||
static void
|
||||
mpegtsmux_class_init (MpegTsMuxClass * klass)
|
||||
{
|
||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&mpegtsmux_sink_factory));
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&mpegtsmux_src_factory));
|
||||
|
||||
gst_element_class_set_details_simple (gstelement_class,
|
||||
"MPEG Transport Stream Muxer", "Codec/Muxer",
|
||||
"Multiplexes media streams into an MPEG Transport Stream",
|
||||
"Fluendo <contact@fluendo.com>");
|
||||
|
||||
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 =
|
||||
GST_DEBUG_FUNCPTR (mpegtsmux_request_new_pad);
|
||||
gstelement_class->release_pad = GST_DEBUG_FUNCPTR (mpegtsmux_release_pad);
|
||||
gstelement_class->change_state = GST_DEBUG_FUNCPTR (mpegtsmux_change_state);
|
||||
gstelement_class->request_new_pad = mpegtsmux_request_new_pad;
|
||||
gstelement_class->release_pad = mpegtsmux_release_pad;
|
||||
gstelement_class->change_state = mpegtsmux_change_state;
|
||||
|
||||
#if 0
|
||||
gstelement_class->set_index = GST_DEBUG_FUNCPTR (mpegtsmux_set_index);
|
||||
gstelement_class->get_index = GST_DEBUG_FUNCPTR (mpegtsmux_get_index);
|
||||
#endif
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PROG_MAP,
|
||||
g_param_spec_boxed ("prog-map", "Program map",
|
||||
|
@ -253,21 +271,26 @@ mpegtsmux_class_init (MpegTsMuxClass * klass)
|
|||
}
|
||||
|
||||
static void
|
||||
mpegtsmux_init (MpegTsMux * mux, MpegTsMuxClass * g_class)
|
||||
mpegtsmux_init (MpegTsMux * mux)
|
||||
{
|
||||
mux->srcpad =
|
||||
gst_pad_new_from_static_template (&mpegtsmux_src_factory, "src");
|
||||
gst_pad_use_fixed_caps (mux->srcpad);
|
||||
gst_pad_set_event_function (mux->srcpad, mpegtsmux_src_event);
|
||||
gst_pad_set_event_function (mux->srcpad,
|
||||
GST_DEBUG_FUNCPTR (mpegtsmux_src_event));
|
||||
gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
|
||||
|
||||
mux->collect = gst_collect_pads2_new ();
|
||||
gst_collect_pads2_set_function (mux->collect,
|
||||
(GstCollectPads2Function) GST_DEBUG_FUNCPTR (mpegtsmux_collected), mux);
|
||||
gst_collect_pads2_set_event_function (mux->collect,
|
||||
(GstCollectPads2EventFunction) GST_DEBUG_FUNCPTR (mpegtsmux_sink_event),
|
||||
mux->collect = gst_collect_pads_new ();
|
||||
gst_collect_pads_set_function (mux->collect,
|
||||
(GstCollectPadsFunction) GST_DEBUG_FUNCPTR (mpegtsmux_collected), mux);
|
||||
|
||||
gst_collect_pads_set_event_function (mux->collect,
|
||||
(GstCollectPadsEventFunction) GST_DEBUG_FUNCPTR (mpegtsmux_sink_event),
|
||||
mux);
|
||||
|
||||
mux->tsmux = tsmux_new ();
|
||||
tsmux_set_write_func (mux->tsmux, new_packet_cb, mux);
|
||||
|
||||
mux->adapter = gst_adapter_new ();
|
||||
mux->out_adapter = gst_adapter_new ();
|
||||
|
||||
|
@ -286,11 +309,15 @@ static void
|
|||
mpegtsmux_pad_reset (MpegTsPadData * pad_data)
|
||||
{
|
||||
pad_data->pid = 0;
|
||||
pad_data->last_ts = GST_CLOCK_TIME_NONE;
|
||||
pad_data->cur_ts = GST_CLOCK_TIME_NONE;
|
||||
pad_data->last_pts = GST_CLOCK_TIME_NONE;
|
||||
pad_data->last_dts = GST_CLOCK_TIME_NONE;
|
||||
pad_data->cur_pts = GST_CLOCK_TIME_NONE;
|
||||
pad_data->cur_dts = GST_CLOCK_TIME_NONE;
|
||||
pad_data->prog_id = -1;
|
||||
pad_data->eos = FALSE;
|
||||
#if 0
|
||||
pad_data->element_index_writer_id = -1;
|
||||
#endif
|
||||
|
||||
if (pad_data->free_func)
|
||||
pad_data->free_func (pad_data->prepare_data);
|
||||
|
@ -325,14 +352,14 @@ mpegtsmux_reset (MpegTsMux * mux, gboolean alloc)
|
|||
mux->streamheader_sent = FALSE;
|
||||
mux->force_key_unit_event = NULL;
|
||||
mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
|
||||
|
||||
#if 0
|
||||
mux->spn_count = 0;
|
||||
|
||||
if (mux->element_index) {
|
||||
gst_object_unref (mux->element_index);
|
||||
mux->element_index = NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
gst_adapter_clear (mux->adapter);
|
||||
gst_adapter_clear (mux->out_adapter);
|
||||
|
||||
|
@ -357,10 +384,10 @@ mpegtsmux_reset (MpegTsMux * mux, gboolean alloc)
|
|||
gst_event_replace (&mux->force_key_unit_event, NULL);
|
||||
gst_buffer_replace (&mux->out_buffer, NULL);
|
||||
|
||||
GST_COLLECT_PADS2_STREAM_LOCK (mux->collect);
|
||||
GST_COLLECT_PADS_STREAM_LOCK (mux->collect);
|
||||
for (walk = mux->collect->data; walk != NULL; walk = g_slist_next (walk))
|
||||
mpegtsmux_pad_reset ((MpegTsPadData *) walk->data);
|
||||
GST_COLLECT_PADS2_STREAM_UNLOCK (mux->collect);
|
||||
GST_COLLECT_PADS_STREAM_UNLOCK (mux->collect);
|
||||
|
||||
if (alloc) {
|
||||
mux->tsmux = tsmux_new ();
|
||||
|
@ -472,6 +499,7 @@ gst_mpegtsmux_get_property (GObject * object, guint prop_id,
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
mpegtsmux_set_index (GstElement * element, GstIndex * index)
|
||||
{
|
||||
|
@ -501,12 +529,12 @@ mpegtsmux_get_index (GstElement * element)
|
|||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
release_buffer_cb (guint8 * data, void *user_data)
|
||||
{
|
||||
GstBuffer *buf = (GstBuffer *) user_data;
|
||||
gst_buffer_unref (buf);
|
||||
stream_data_free (user_data);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
|
@ -522,12 +550,12 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data)
|
|||
GstBuffer *codec_data = NULL;
|
||||
|
||||
pad = ts_data->collect.pad;
|
||||
caps = gst_pad_get_negotiated_caps (pad);
|
||||
caps = gst_pad_get_current_caps (pad);
|
||||
if (caps == NULL)
|
||||
goto not_negotiated;
|
||||
|
||||
GST_DEBUG_OBJECT (pad, "Creating stream with PID 0x%04x for caps %"
|
||||
GST_PTR_FORMAT, caps);
|
||||
GST_PTR_FORMAT, ts_data->pid, caps);
|
||||
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
g_return_val_if_fail (s != NULL, FALSE);
|
||||
|
@ -547,16 +575,6 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data)
|
|||
st = TSMUX_ST_PS_AUDIO_LPCM;
|
||||
} else if (strcmp (mt, "video/x-h264") == 0) {
|
||||
st = TSMUX_ST_VIDEO_H264;
|
||||
/* Codec data contains SPS/PPS which need to go in stream for valid ES */
|
||||
if (codec_data) {
|
||||
GST_DEBUG_OBJECT (pad, "we have additional codec data (%d bytes)",
|
||||
GST_BUFFER_SIZE (codec_data));
|
||||
ts_data->codec_data = gst_buffer_ref (codec_data);
|
||||
ts_data->prepare_func = mpegtsmux_prepare_h264;
|
||||
ts_data->free_func = mpegtsmux_free_h264;
|
||||
} else {
|
||||
ts_data->codec_data = NULL;
|
||||
}
|
||||
} else if (strcmp (mt, "audio/mpeg") == 0) {
|
||||
gint mpegversion;
|
||||
|
||||
|
@ -575,9 +593,10 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data)
|
|||
case 4:
|
||||
{
|
||||
st = TSMUX_ST_AUDIO_AAC;
|
||||
if (codec_data) {
|
||||
GST_DEBUG_OBJECT (pad, "we have additional codec data (%d bytes)",
|
||||
GST_BUFFER_SIZE (codec_data));
|
||||
if (codec_data) { /* TODO - Check stream format - codec data should only come with RAW stream */
|
||||
GST_DEBUG_OBJECT (pad,
|
||||
"we have additional codec data (%" G_GSIZE_FORMAT " bytes)",
|
||||
gst_buffer_get_size (codec_data));
|
||||
ts_data->codec_data = gst_buffer_ref (codec_data);
|
||||
ts_data->prepare_func = mpegtsmux_prepare_aac;
|
||||
} else {
|
||||
|
@ -629,7 +648,7 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data)
|
|||
|
||||
ret = GST_FLOW_OK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
GST_OBJECT_LOCK (mux);
|
||||
if (mux->element_index) {
|
||||
gboolean parsed = FALSE;
|
||||
|
@ -652,6 +671,7 @@ mpegtsmux_create_stream (MpegTsMux * mux, MpegTsPadData * ts_data)
|
|||
}
|
||||
}
|
||||
GST_OBJECT_UNLOCK (mux);
|
||||
#endif
|
||||
|
||||
gst_caps_unref (caps);
|
||||
return ret;
|
||||
|
@ -674,7 +694,7 @@ mpegtsmux_create_streams (MpegTsMux * mux)
|
|||
|
||||
/* Create the streams */
|
||||
while (walk) {
|
||||
GstCollectData2 *c_data = (GstCollectData2 *) walk->data;
|
||||
GstCollectData *c_data = (GstCollectData *) walk->data;
|
||||
MpegTsPadData *ts_data = (MpegTsPadData *) walk->data;
|
||||
gchar *name = NULL;
|
||||
|
||||
|
@ -743,15 +763,14 @@ mpegtsmux_choose_best_stream (MpegTsMux * mux)
|
|||
GSList *walk;
|
||||
|
||||
for (walk = mux->collect->data; walk != NULL; walk = g_slist_next (walk)) {
|
||||
GstCollectData2 *c_data = (GstCollectData2 *) walk->data;
|
||||
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_pads2_pop (mux->collect, c_data);
|
||||
ts_data->queued_buf = buf = gst_collect_pads_pop (mux->collect, c_data);
|
||||
|
||||
if (buf != NULL) {
|
||||
if (ts_data->prepare_func) {
|
||||
|
@ -763,30 +782,40 @@ mpegtsmux_choose_best_stream (MpegTsMux * mux)
|
|||
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));
|
||||
if (GST_BUFFER_PTS (buf) != GST_CLOCK_TIME_NONE) {
|
||||
|
||||
ts_data->cur_pts = ts_data->last_pts =
|
||||
gst_segment_to_running_time (&c_data->segment,
|
||||
GST_FORMAT_TIME, GST_BUFFER_PTS (buf));
|
||||
} else
|
||||
ts_data->cur_pts = GST_CLOCK_TIME_NONE;
|
||||
|
||||
if (GST_BUFFER_DTS (buf) != GST_CLOCK_TIME_NONE) {
|
||||
GstClockTime dts = gst_segment_to_running_time (&c_data->segment,
|
||||
GST_FORMAT_TIME, GST_BUFFER_DTS (buf));
|
||||
if (ts_data->last_dts == GST_CLOCK_TIME_NONE
|
||||
|| ts_data->last_dts < dts) {
|
||||
ts_data->cur_dts = ts_data->last_dts = dts;
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (mux, "Ignoring PTS that has gone backward");
|
||||
GST_WARNING_OBJECT (mux,
|
||||
"Got DTS that is going backward (%" GST_TIME_FORMAT " >= %"
|
||||
GST_TIME_FORMAT "). You should provide valid monotone DTS.",
|
||||
GST_TIME_ARGS (ts_data->last_dts), GST_TIME_ARGS (dts));
|
||||
ts_data->cur_dts = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
} else
|
||||
ts_data->cur_ts = GST_CLOCK_TIME_NONE;
|
||||
ts_data->cur_dts = GST_CLOCK_TIME_NONE;
|
||||
|
||||
GST_DEBUG_OBJECT (mux, "Pulled buffer with ts %" GST_TIME_FORMAT
|
||||
" (uncorrected ts %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
|
||||
" (uncorrected pts %" 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_TIME_ARGS (ts_data->cur_pts),
|
||||
GST_TIME_ARGS (GST_BUFFER_PTS (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) {
|
||||
if (ts_data->last_pts == GST_CLOCK_TIME_NONE) {
|
||||
best = ts_data;
|
||||
}
|
||||
} else {
|
||||
|
@ -798,9 +827,9 @@ mpegtsmux_choose_best_stream (MpegTsMux * mux)
|
|||
/* 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) {
|
||||
if (ts_data->last_pts != GST_CLOCK_TIME_NONE &&
|
||||
best->last_pts != GST_CLOCK_TIME_NONE &&
|
||||
ts_data->last_pts < best->last_pts) {
|
||||
best = ts_data;
|
||||
}
|
||||
} else {
|
||||
|
@ -812,14 +841,15 @@ mpegtsmux_choose_best_stream (MpegTsMux * mux)
|
|||
return best;
|
||||
}
|
||||
|
||||
#define COLLECT_DATA_PAD(collect_data) (((GstCollectData2 *)(collect_data))->pad)
|
||||
#define COLLECT_DATA_PAD(collect_data) (((GstCollectData *)(collect_data))->pad)
|
||||
|
||||
static gboolean
|
||||
mpegtsmux_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
|
||||
mpegtsmux_sink_event (GstCollectPads * pads, GstCollectData * data,
|
||||
GstEvent * event, gpointer user_data)
|
||||
{
|
||||
MpegTsMux *mux = GST_MPEG_TSMUX (user_data);
|
||||
gboolean res = FALSE;
|
||||
gboolean forward = TRUE;
|
||||
GstPad *pad;
|
||||
|
||||
pad = data->pad;
|
||||
|
@ -835,6 +865,7 @@ mpegtsmux_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
|
|||
goto out;
|
||||
|
||||
res = TRUE;
|
||||
forward = FALSE;
|
||||
|
||||
gst_video_event_parse_downstream_force_key_unit (event,
|
||||
×tamp, &stream_time, &running_time, &all_headers, &count);
|
||||
|
@ -861,14 +892,16 @@ mpegtsmux_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
|
|||
}
|
||||
|
||||
out:
|
||||
if (res)
|
||||
if (!forward)
|
||||
gst_event_unref (event);
|
||||
else
|
||||
res = gst_collect_pads_event_default (pads, data, event, FALSE);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mpegtsmux_src_event (GstPad * pad, GstEvent * event)
|
||||
mpegtsmux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||
{
|
||||
MpegTsMux *mux = GST_MPEG_TSMUX (gst_pad_get_parent (pad));
|
||||
gboolean res = TRUE, forward = TRUE;
|
||||
|
@ -879,6 +912,7 @@ mpegtsmux_src_event (GstPad * pad, GstEvent * event)
|
|||
GstIterator *iter;
|
||||
GstIteratorResult iter_ret;
|
||||
GstPad *sinkpad;
|
||||
GValue sinkpad_value = G_VALUE_INIT;
|
||||
GstClockTime running_time;
|
||||
gboolean all_headers, done;
|
||||
guint count;
|
||||
|
@ -906,7 +940,9 @@ mpegtsmux_src_event (GstPad * pad, GstEvent * event)
|
|||
done = FALSE;
|
||||
while (!done) {
|
||||
gboolean res = FALSE, tmp;
|
||||
iter_ret = gst_iterator_next (iter, (gpointer *) & sinkpad);
|
||||
g_value_reset (&sinkpad_value);
|
||||
iter_ret = gst_iterator_next (iter, &sinkpad_value);
|
||||
sinkpad = g_value_get_object (&sinkpad_value);
|
||||
|
||||
switch (iter_ret) {
|
||||
case GST_ITERATOR_DONE:
|
||||
|
@ -928,6 +964,7 @@ mpegtsmux_src_event (GstPad * pad, GstEvent * event)
|
|||
break;
|
||||
}
|
||||
}
|
||||
g_value_reset (&sinkpad_value);
|
||||
gst_iterator_free (iter);
|
||||
break;
|
||||
}
|
||||
|
@ -936,7 +973,7 @@ mpegtsmux_src_event (GstPad * pad, GstEvent * event)
|
|||
}
|
||||
|
||||
if (forward)
|
||||
res = gst_pad_event_default (pad, event);
|
||||
res = gst_pad_event_default (pad, parent, event);
|
||||
else
|
||||
gst_event_unref (event);
|
||||
|
||||
|
@ -993,7 +1030,7 @@ out:
|
|||
}
|
||||
|
||||
static GstFlowReturn
|
||||
mpegtsmux_collected (GstCollectPads2 * pads, MpegTsMux * mux)
|
||||
mpegtsmux_collected (GstCollectPads * pads, MpegTsMux * mux)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
MpegTsPadData *best = NULL;
|
||||
|
@ -1016,7 +1053,9 @@ mpegtsmux_collected (GstCollectPads2 * pads, MpegTsMux * mux)
|
|||
TsMuxProgram *prog = best->prog;
|
||||
GstBuffer *buf = best->queued_buf;
|
||||
gint64 pts = -1;
|
||||
guint64 dts = -1;
|
||||
gboolean delta = TRUE;
|
||||
StreamData *stream_data;
|
||||
|
||||
if (prog == NULL)
|
||||
goto no_program;
|
||||
|
@ -1072,14 +1111,21 @@ mpegtsmux_collected (GstCollectPads2 * pads, MpegTsMux * mux)
|
|||
GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
|
||||
"Chose stream for output (PID: 0x%04x)", 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);
|
||||
if (GST_CLOCK_TIME_IS_VALID (best->cur_pts)) {
|
||||
pts = GSTTIME_TO_MPEGTIME (best->cur_pts);
|
||||
GST_DEBUG_OBJECT (mux, "Buffer has PTS %" GST_TIME_FORMAT " pts %"
|
||||
G_GINT64_FORMAT, GST_TIME_ARGS (best->cur_pts), pts);
|
||||
}
|
||||
|
||||
if (GST_CLOCK_TIME_IS_VALID (best->cur_dts)) {
|
||||
dts = GSTTIME_TO_MPEGTIME (best->cur_dts);
|
||||
GST_DEBUG_OBJECT (mux, "Buffer has DTS %" GST_TIME_FORMAT " dts %"
|
||||
G_GINT64_FORMAT, GST_TIME_ARGS (best->cur_dts), dts);
|
||||
}
|
||||
|
||||
if (best->stream->is_video_stream) {
|
||||
delta = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||
#if 0
|
||||
GST_OBJECT_LOCK (mux);
|
||||
if (mux->element_index && !delta && best->element_index_writer_id != -1) {
|
||||
gst_index_add_association (mux->element_index,
|
||||
|
@ -1088,19 +1134,24 @@ mpegtsmux_collected (GstCollectPads2 * pads, MpegTsMux * mux)
|
|||
pts_format, pts, NULL);
|
||||
}
|
||||
GST_OBJECT_UNLOCK (mux);
|
||||
#endif
|
||||
}
|
||||
GST_DEBUG_OBJECT (mux, "delta: %d", delta);
|
||||
|
||||
tsmux_stream_add_data (best->stream, GST_BUFFER_DATA (buf),
|
||||
GST_BUFFER_SIZE (buf), buf, pts, -1, !delta);
|
||||
stream_data = stream_data_new (buf);
|
||||
tsmux_stream_add_data (best->stream, stream_data->map_info.data,
|
||||
stream_data->map_info.size, stream_data, pts, dts, !delta);
|
||||
|
||||
/* outgoing ts follows ts of PCR program stream */
|
||||
if (prog->pcr_stream == best->stream) {
|
||||
mux->last_ts = best->last_ts;
|
||||
/* prefer DTS if present for PCR as it should be monotone */
|
||||
mux->last_ts =
|
||||
GST_CLOCK_TIME_IS_VALID (best->last_dts) ? best->last_dts : best->
|
||||
last_pts;
|
||||
}
|
||||
|
||||
mux->is_delta = delta;
|
||||
mux->last_size = GST_BUFFER_SIZE (buf);
|
||||
mux->last_size = stream_data->map_info.size;
|
||||
while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
|
||||
if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
|
||||
/* Failed writing data for some reason. Set appropriate error */
|
||||
|
@ -1139,8 +1190,8 @@ no_program:
|
|||
}
|
||||
|
||||
static GstPad *
|
||||
mpegtsmux_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * name)
|
||||
mpegtsmux_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||
const gchar * name, const GstCaps * caps)
|
||||
{
|
||||
MpegTsMux *mux = GST_MPEG_TSMUX (element);
|
||||
gint pid = -1;
|
||||
|
@ -1160,8 +1211,8 @@ mpegtsmux_request_new_pad (GstElement * element,
|
|||
g_free (pad_name);
|
||||
|
||||
pad_data = (MpegTsPadData *)
|
||||
gst_collect_pads2_add_pad_full (mux->collect, pad, sizeof (MpegTsPadData),
|
||||
(GstCollectData2DestroyNotify) (mpegtsmux_pad_reset), TRUE);
|
||||
gst_collect_pads_add_pad_full (mux->collect, pad, sizeof (MpegTsPadData),
|
||||
(GstCollectDataDestroyNotify) (mpegtsmux_pad_reset), TRUE);
|
||||
if (pad_data == NULL)
|
||||
goto pad_failure;
|
||||
|
||||
|
@ -1184,7 +1235,7 @@ could_not_add:
|
|||
{
|
||||
GST_ELEMENT_ERROR (element, STREAM, FAILED,
|
||||
("Internal data stream error."), ("Could not add pad to element"));
|
||||
gst_collect_pads2_remove_pad (mux->collect, pad);
|
||||
gst_collect_pads_remove_pad (mux->collect, pad);
|
||||
gst_object_unref (pad);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1205,7 +1256,7 @@ mpegtsmux_release_pad (GstElement * element, GstPad * pad)
|
|||
GST_DEBUG_OBJECT (mux, "Pad %" GST_PTR_FORMAT " being released", pad);
|
||||
|
||||
if (mux->collect) {
|
||||
gst_collect_pads2_remove_pad (mux->collect, pad);
|
||||
gst_collect_pads_remove_pad (mux->collect, pad);
|
||||
}
|
||||
|
||||
/* chain up */
|
||||
|
@ -1227,7 +1278,7 @@ new_packet_common_init (MpegTsMux * mux, GstBuffer * buf, guint8 * data,
|
|||
|
||||
if (!buf) {
|
||||
hbuf = gst_buffer_new_and_alloc (len);
|
||||
memcpy (GST_BUFFER_DATA (hbuf), data, len);
|
||||
gst_buffer_fill (hbuf, 0, data, len);
|
||||
} else {
|
||||
hbuf = gst_buffer_copy (buf);
|
||||
}
|
||||
|
@ -1239,10 +1290,6 @@ new_packet_common_init (MpegTsMux * mux, GstBuffer * buf, guint8 * data,
|
|||
}
|
||||
|
||||
if (buf) {
|
||||
/* Set the caps on the buffer only after possibly setting the stream headers
|
||||
* into the pad caps above */
|
||||
gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad));
|
||||
|
||||
if (mux->is_delta) {
|
||||
GST_LOG_OBJECT (mux, "marking as delta unit");
|
||||
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||
|
@ -1287,7 +1334,7 @@ mpegtsmux_push_packets (MpegTsMux * mux, gboolean force)
|
|||
buf = gst_adapter_take_buffer (mux->out_adapter, av - (av % align));
|
||||
g_assert (buf);
|
||||
GST_BUFFER_TIMESTAMP (buf) = ts;
|
||||
gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad));
|
||||
|
||||
ret = gst_pad_push (mux->srcpad, buf);
|
||||
av = av % align;
|
||||
}
|
||||
|
@ -1296,19 +1343,22 @@ mpegtsmux_push_packets (MpegTsMux * mux, gboolean force)
|
|||
guint8 *data;
|
||||
guint32 header;
|
||||
gint dummy;
|
||||
GstMapInfo map;
|
||||
|
||||
GST_LOG_OBJECT (mux, "handling %d leftover bytes", av);
|
||||
buf = gst_buffer_new_and_alloc (align);
|
||||
gst_buffer_map (buf, &map, GST_MAP_READ);
|
||||
data = map.data;
|
||||
ts = gst_adapter_prev_timestamp (mux->out_adapter, NULL);
|
||||
gst_adapter_copy (mux->out_adapter, GST_BUFFER_DATA (buf), 0, av);
|
||||
|
||||
gst_adapter_copy (mux->out_adapter, data, 0, av);
|
||||
gst_adapter_clear (mux->out_adapter);
|
||||
GST_BUFFER_TIMESTAMP (buf) = ts;
|
||||
gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad));
|
||||
|
||||
data = GST_BUFFER_DATA (buf) + av;
|
||||
data += av;
|
||||
header = GST_READ_UINT32_BE (data - packet_size);
|
||||
|
||||
dummy = (GST_BUFFER_SIZE (buf) - av) / packet_size;
|
||||
dummy = (map.size - av) / packet_size;
|
||||
GST_LOG_OBJECT (mux, "adding %d null packets", dummy);
|
||||
|
||||
for (; dummy > 0; dummy--) {
|
||||
|
@ -1332,6 +1382,8 @@ mpegtsmux_push_packets (MpegTsMux * mux, gboolean force)
|
|||
data += packet_size;
|
||||
}
|
||||
|
||||
gst_buffer_unmap (buf, &map);
|
||||
|
||||
ret = gst_pad_push (mux->srcpad, buf);
|
||||
}
|
||||
|
||||
|
@ -1341,7 +1393,8 @@ mpegtsmux_push_packets (MpegTsMux * mux, gboolean force)
|
|||
static GstFlowReturn
|
||||
mpegtsmux_collect_packet (MpegTsMux * mux, GstBuffer * buf)
|
||||
{
|
||||
GST_LOG_OBJECT (mux, "collecting packet size %d", GST_BUFFER_SIZE (buf));
|
||||
GST_LOG_OBJECT (mux, "collecting packet size %" G_GSIZE_FORMAT,
|
||||
gst_buffer_get_size (buf));
|
||||
gst_adapter_push (mux->out_adapter, buf);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
|
@ -1352,6 +1405,7 @@ new_packet_m2ts (MpegTsMux * mux, GstBuffer * buf, gint64 new_pcr)
|
|||
{
|
||||
GstBuffer *out_buf;
|
||||
int chunk_bytes;
|
||||
GstMapInfo map;
|
||||
|
||||
GST_LOG_OBJECT (mux, "Have buffer %p with new_pcr=%" G_GINT64_FORMAT,
|
||||
buf, new_pcr);
|
||||
|
@ -1418,12 +1472,14 @@ new_packet_m2ts (MpegTsMux * mux, GstBuffer * buf, gint64 new_pcr)
|
|||
g_assert (out_buf);
|
||||
offset += M2TS_PACKET_LENGTH;
|
||||
|
||||
gst_buffer_set_caps (out_buf, GST_PAD_CAPS (mux->srcpad));
|
||||
GST_BUFFER_TIMESTAMP (out_buf) = ts;
|
||||
|
||||
gst_buffer_map (out_buf, &map, GST_MAP_WRITE);
|
||||
|
||||
/* The header is the bottom 30 bits of the PCR, apparently not
|
||||
* encoded into base + ext as in the packets themselves */
|
||||
GST_WRITE_UINT32_BE (GST_BUFFER_DATA (out_buf), cur_pcr & 0x3FFFFFFF);
|
||||
GST_WRITE_UINT32_BE (map.data, cur_pcr & 0x3FFFFFFF);
|
||||
gst_buffer_unmap (out_buf, &map);
|
||||
|
||||
GST_LOG_OBJECT (mux, "Outputting a packet of length %d PCR %"
|
||||
G_GUINT64_FORMAT, M2TS_PACKET_LENGTH, cur_pcr);
|
||||
|
@ -1434,9 +1490,13 @@ new_packet_m2ts (MpegTsMux * mux, GstBuffer * buf, gint64 new_pcr)
|
|||
if (G_UNLIKELY (!buf))
|
||||
goto exit;
|
||||
|
||||
gst_buffer_map (buf, &map, GST_MAP_WRITE);
|
||||
|
||||
/* Finally, output the passed in packet */
|
||||
/* Only write the bottom 30 bits of the PCR */
|
||||
GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf), new_pcr & 0x3FFFFFFF);
|
||||
GST_WRITE_UINT32_BE (map.data, new_pcr & 0x3FFFFFFF);
|
||||
|
||||
gst_buffer_unmap (buf, &map);
|
||||
|
||||
GST_LOG_OBJECT (mux, "Outputting a packet of length %d PCR %"
|
||||
G_GUINT64_FORMAT, M2TS_PACKET_LENGTH, new_pcr);
|
||||
|
@ -1458,20 +1518,30 @@ new_packet_cb (GstBuffer * buf, void *user_data, gint64 new_pcr)
|
|||
{
|
||||
MpegTsMux *mux = (MpegTsMux *) user_data;
|
||||
gint offset = 0;
|
||||
GstMapInfo map;
|
||||
|
||||
#if 0
|
||||
GST_LOG_OBJECT (mux, "handling packet %d", mux->spn_count);
|
||||
mux->spn_count++;
|
||||
#endif
|
||||
|
||||
offset = GST_BUFFER_DATA (buf) - GST_BUFFER_MALLOCDATA (buf);
|
||||
GST_BUFFER_TIMESTAMP (buf) = mux->last_ts;
|
||||
if (mux->m2ts_mode) {
|
||||
offset = 4;
|
||||
gst_buffer_set_size (buf, NORMAL_TS_PACKET_LENGTH + offset);
|
||||
}
|
||||
|
||||
gst_buffer_map (buf, &map, GST_MAP_READWRITE);
|
||||
|
||||
if (offset) {
|
||||
/* there should be a better way to do this */
|
||||
memmove (map.data + offset, map.data, map.size - offset);
|
||||
}
|
||||
|
||||
GST_BUFFER_PTS (buf) = mux->last_ts;
|
||||
/* do common init (flags and streamheaders) */
|
||||
new_packet_common_init (mux, buf,
|
||||
GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||
new_packet_common_init (mux, buf, map.data + offset, map.size);
|
||||
|
||||
/* all is meant for downstream, including any prefix */
|
||||
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf);
|
||||
GST_BUFFER_SIZE (buf) += offset;
|
||||
|
||||
if (offset)
|
||||
return new_packet_m2ts (mux, buf, new_pcr);
|
||||
else
|
||||
|
@ -1491,11 +1561,8 @@ alloc_packet_cb (GstBuffer ** _buf, void *user_data)
|
|||
if (mux->m2ts_mode == TRUE)
|
||||
offset = 4;
|
||||
|
||||
/* TODO might be even more efficient to avoid later memcpy
|
||||
* if these are subbuffer from a larger buffer or so */
|
||||
buf = gst_buffer_new_and_alloc (NORMAL_TS_PACKET_LENGTH + offset);
|
||||
GST_BUFFER_DATA (buf) += offset;
|
||||
GST_BUFFER_SIZE (buf) -= offset;
|
||||
gst_buffer_set_size (buf, NORMAL_TS_PACKET_LENGTH);
|
||||
|
||||
*_buf = buf;
|
||||
}
|
||||
|
@ -1510,7 +1577,7 @@ mpegtsdemux_set_header_on_caps (MpegTsMux * mux)
|
|||
GstCaps *caps;
|
||||
GList *sh;
|
||||
|
||||
caps = gst_caps_copy (GST_PAD_CAPS (mux->srcpad));
|
||||
caps = gst_caps_make_writable (gst_pad_get_current_caps (mux->srcpad));
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
|
||||
g_value_init (&array, GST_TYPE_ARRAY);
|
||||
|
@ -1518,7 +1585,6 @@ mpegtsdemux_set_header_on_caps (MpegTsMux * mux)
|
|||
sh = mux->streamheader;
|
||||
while (sh) {
|
||||
buf = sh->data;
|
||||
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
|
||||
g_value_init (&value, GST_TYPE_BUFFER);
|
||||
gst_value_take_buffer (&value, buf);
|
||||
gst_value_array_append_value (&array, &value);
|
||||
|
@ -1538,15 +1604,23 @@ mpegtsdemux_set_header_on_caps (MpegTsMux * mux)
|
|||
static void
|
||||
mpegtsdemux_prepare_srcpad (MpegTsMux * mux)
|
||||
{
|
||||
GstSegment seg;
|
||||
/* we are not going to seek */
|
||||
GstEvent *new_seg =
|
||||
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0);
|
||||
GstEvent *new_seg;
|
||||
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);
|
||||
|
||||
seg.rate = 1.0;
|
||||
seg.format = GST_FORMAT_TIME;
|
||||
seg.start = 0;
|
||||
seg.stop = -1;
|
||||
seg.position = 0;
|
||||
|
||||
new_seg = gst_event_new_segment (&seg);
|
||||
|
||||
/* Set caps on src pad from our template and push new segment */
|
||||
gst_pad_set_caps (mux->srcpad, caps);
|
||||
gst_caps_unref (caps);
|
||||
|
@ -1566,12 +1640,12 @@ mpegtsmux_change_state (GstElement * element, GstStateChange transition)
|
|||
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
gst_collect_pads2_start (mux->collect);
|
||||
gst_collect_pads_start (mux->collect);
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
gst_collect_pads2_stop (mux->collect);
|
||||
gst_collect_pads_stop (mux->collect);
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
break;
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
#define __MPEGTSMUX_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstcollectpads2.h>
|
||||
#include <gst/base/gstcollectpads.h>
|
||||
#include <gst/base/gstadapter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
@ -129,7 +129,7 @@ struct MpegTsMux {
|
|||
|
||||
GstPad *srcpad;
|
||||
|
||||
GstCollectPads2 *collect;
|
||||
GstCollectPads *collect;
|
||||
|
||||
TsMux *tsmux;
|
||||
TsMuxProgram *programs[MAX_PROG_NUMBER];
|
||||
|
@ -166,9 +166,11 @@ struct MpegTsMux {
|
|||
gint out_offset;
|
||||
gint last_size;
|
||||
|
||||
#if 0
|
||||
/* SPN/PTS index handling */
|
||||
GstIndex *element_index;
|
||||
gint spn_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct MpegTsMuxClass {
|
||||
|
@ -179,7 +181,7 @@ struct MpegTsMuxClass {
|
|||
|
||||
struct MpegTsPadData {
|
||||
/* parent */
|
||||
GstCollectData2 collect;
|
||||
GstCollectData collect;
|
||||
|
||||
gint pid;
|
||||
TsMuxStream *stream;
|
||||
|
@ -187,12 +189,17 @@ struct MpegTsPadData {
|
|||
/* currently pulled buffer */
|
||||
GstBuffer *queued_buf;
|
||||
/* adjusted TS for the pulled buffer */
|
||||
GstClockTime cur_ts;
|
||||
GstClockTime cur_pts;
|
||||
GstClockTime cur_dts;
|
||||
|
||||
/* most recent valid TS for this stream */
|
||||
GstClockTime last_ts;
|
||||
GstClockTime last_pts;
|
||||
GstClockTime last_dts;
|
||||
|
||||
#if 0
|
||||
/* (optional) index writing */
|
||||
gint element_index_writer_id;
|
||||
#endif
|
||||
|
||||
/* optional codec data available in the caps */
|
||||
GstBuffer *codec_data;
|
||||
|
|
|
@ -93,23 +93,26 @@ GstBuffer *
|
|||
mpegtsmux_prepare_aac (GstBuffer * buf, MpegTsPadData * data, MpegTsMux * mux)
|
||||
{
|
||||
guint8 adts_header[7] = { 0, };
|
||||
GstBuffer *out_buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) + 7);
|
||||
gsize out_size = gst_buffer_get_size (buf) + 7;
|
||||
GstBuffer *out_buf = gst_buffer_new_and_alloc (out_size);
|
||||
gsize out_offset = 0;
|
||||
guint8 rate_idx = 0, channels = 0, obj_type = 0;
|
||||
GstMapInfo codec_data_map;
|
||||
GstMapInfo buf_map;
|
||||
|
||||
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);
|
||||
gst_buffer_copy_into (out_buf, buf,
|
||||
GST_BUFFER_COPY_METADATA | GST_BUFFER_COPY_TIMESTAMPS, 0, 0);
|
||||
|
||||
gst_buffer_map (data->codec_data, &codec_data_map, GST_MAP_READ);
|
||||
|
||||
/* Generate ADTS header */
|
||||
obj_type = (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data)) & 0xC) >> 2;
|
||||
obj_type = (GST_READ_UINT8 (codec_data_map.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;
|
||||
rate_idx = (GST_READ_UINT8 (codec_data_map.data) & 0x3) << 1;
|
||||
rate_idx |= (GST_READ_UINT8 (codec_data_map.data + 1) & 0x80) >> 7;
|
||||
channels = (GST_READ_UINT8 (codec_data_map.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 */
|
||||
|
@ -126,11 +129,11 @@ mpegtsmux_prepare_aac (GstBuffer * buf, MpegTsPadData * data, MpegTsMux * mux)
|
|||
/* 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;
|
||||
adts_header[3] |= (out_size & 0x1800) >> 11;
|
||||
/* frame size continued over full byte */
|
||||
adts_header[4] = (GST_BUFFER_SIZE (out_buf) & 0x1FF8) >> 3;
|
||||
adts_header[4] = (out_size & 0x1FF8) >> 3;
|
||||
/* frame size continued first 3 bits */
|
||||
adts_header[5] = (GST_BUFFER_SIZE (out_buf) & 0x7) << 5;
|
||||
adts_header[5] = (out_size & 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
|
||||
|
@ -138,12 +141,16 @@ mpegtsmux_prepare_aac (GstBuffer * buf, MpegTsPadData * data, MpegTsMux * mux)
|
|||
adts_header[6] = 0xFC;
|
||||
|
||||
/* Insert ADTS header */
|
||||
memcpy (GST_BUFFER_DATA (out_buf) + out_offset, adts_header, 7);
|
||||
gst_buffer_fill (out_buf, out_offset, adts_header, 7);
|
||||
out_offset += 7;
|
||||
|
||||
gst_buffer_map (buf, &buf_map, GST_MAP_READ);
|
||||
|
||||
/* Now copy complete frame */
|
||||
memcpy (GST_BUFFER_DATA (out_buf) + out_offset, GST_BUFFER_DATA (buf),
|
||||
GST_BUFFER_SIZE (buf));
|
||||
gst_buffer_fill (out_buf, out_offset, buf_map.data, buf_map.size);
|
||||
|
||||
gst_buffer_unmap (data->codec_data, &codec_data_map);
|
||||
gst_buffer_unmap (buf, &buf_map);
|
||||
|
||||
return out_buf;
|
||||
}
|
||||
|
|
|
@ -1,293 +0,0 @@
|
|||
/*
|
||||
* Copyright 2006, 2007, 2008, 2009, 2010 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>
|
||||
|
||||
#define GST_CAT_DEFAULT mpegtsmux_debug
|
||||
|
||||
#define SPS_PPS_PERIOD GST_SECOND
|
||||
|
||||
typedef struct PrivDataH264 PrivDataH264;
|
||||
|
||||
struct PrivDataH264
|
||||
{
|
||||
GstBuffer *last_codec_data;
|
||||
GstClockTime last_resync_ts;
|
||||
GstBuffer *cached_es;
|
||||
guint8 nal_length_size;
|
||||
};
|
||||
|
||||
void
|
||||
mpegtsmux_free_h264 (gpointer prepare_data)
|
||||
{
|
||||
PrivDataH264 *h264_data = (PrivDataH264 *) prepare_data;
|
||||
if (h264_data->cached_es) {
|
||||
gst_buffer_unref (h264_data->cached_es);
|
||||
h264_data->cached_es = NULL;
|
||||
}
|
||||
g_free (prepare_data);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
mpegtsmux_process_codec_data_h264 (MpegTsPadData * data, MpegTsMux * mux)
|
||||
{
|
||||
PrivDataH264 *h264_data;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
/* Initialize our private data structure for caching */
|
||||
if (G_UNLIKELY (!data->prepare_data)) {
|
||||
data->prepare_data = g_new0 (PrivDataH264, 1);
|
||||
h264_data = (PrivDataH264 *) data->prepare_data;
|
||||
h264_data->last_resync_ts = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
||||
h264_data = (PrivDataH264 *) data->prepare_data;
|
||||
|
||||
/* Detect a codec data change */
|
||||
if (h264_data->last_codec_data != data->codec_data) {
|
||||
if (h264_data->cached_es) {
|
||||
gst_buffer_unref (h264_data->cached_es);
|
||||
h264_data->cached_es = NULL;
|
||||
}
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
/* Generate the SPS/PPS ES header that will be prepended regularly */
|
||||
if (G_UNLIKELY (!h264_data->cached_es)) {
|
||||
gint offset = 4, i = 0, nb_sps = 0, nb_pps = 0;
|
||||
gsize out_offset = 0;
|
||||
guint8 startcode[4] = { 0x00, 0x00, 0x00, 0x01 };
|
||||
h264_data->last_codec_data = data->codec_data;
|
||||
h264_data->cached_es =
|
||||
gst_buffer_new_and_alloc (GST_BUFFER_SIZE (data->codec_data) * 10);
|
||||
|
||||
/* Get NAL length size */
|
||||
h264_data->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",
|
||||
h264_data->nal_length_size);
|
||||
offset++;
|
||||
|
||||
/* How many 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 (h264_data->cached_es) + out_offset,
|
||||
startcode, 4);
|
||||
out_offset += 4;
|
||||
/* Now push the SPS */
|
||||
memcpy (GST_BUFFER_DATA (h264_data->cached_es) + out_offset,
|
||||
GST_BUFFER_DATA (data->codec_data) + offset, sps_size);
|
||||
|
||||
out_offset += sps_size;
|
||||
offset += sps_size;
|
||||
}
|
||||
|
||||
/* How many PPS */
|
||||
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 (h264_data->cached_es) + out_offset,
|
||||
startcode, 4);
|
||||
out_offset += 4;
|
||||
/* Now push the PPS */
|
||||
memcpy (GST_BUFFER_DATA (h264_data->cached_es) + out_offset,
|
||||
GST_BUFFER_DATA (data->codec_data) + offset, pps_size);
|
||||
|
||||
out_offset += pps_size;
|
||||
offset += pps_size;
|
||||
}
|
||||
GST_BUFFER_SIZE (h264_data->cached_es) = out_offset;
|
||||
GST_DEBUG_OBJECT (mux, "generated a %" G_GSIZE_FORMAT
|
||||
" bytes SPS/PPS header", out_offset);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
GstBuffer *
|
||||
mpegtsmux_prepare_h264 (GstBuffer * buf, MpegTsPadData * data, MpegTsMux * mux)
|
||||
{
|
||||
guint8 startcode[4] = { 0x00, 0x00, 0x00, 0x01 };
|
||||
gsize out_offset = 0, in_offset = 0;
|
||||
GstBuffer *out_buf;
|
||||
gboolean changed;
|
||||
PrivDataH264 *h264_data;
|
||||
GstClockTimeDiff diff = GST_CLOCK_TIME_NONE;
|
||||
|
||||
GST_DEBUG_OBJECT (mux, "Preparing H264 buffer for output");
|
||||
|
||||
changed = mpegtsmux_process_codec_data_h264 (data, mux);
|
||||
h264_data = (PrivDataH264 *) data->prepare_data;
|
||||
|
||||
if (GST_CLOCK_TIME_IS_VALID (h264_data->last_resync_ts) &&
|
||||
GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) {
|
||||
diff = GST_CLOCK_DIFF (h264_data->last_resync_ts,
|
||||
GST_BUFFER_TIMESTAMP (buf));
|
||||
}
|
||||
|
||||
if (changed || (GST_CLOCK_TIME_IS_VALID (diff) && diff > SPS_PPS_PERIOD)) {
|
||||
out_buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) * 2 +
|
||||
GST_BUFFER_SIZE (h264_data->cached_es));
|
||||
h264_data->last_resync_ts = GST_BUFFER_TIMESTAMP (buf);
|
||||
memcpy (GST_BUFFER_DATA (out_buf), GST_BUFFER_DATA (h264_data->cached_es),
|
||||
GST_BUFFER_SIZE (h264_data->cached_es));
|
||||
out_offset = GST_BUFFER_SIZE (h264_data->cached_es);
|
||||
GST_DEBUG_OBJECT (mux, "prepending SPS/PPS information to that packet");
|
||||
} else {
|
||||
out_buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) * 2);
|
||||
}
|
||||
|
||||
/* We want the same metadata */
|
||||
gst_buffer_copy_metadata (out_buf, buf, GST_BUFFER_COPY_ALL);
|
||||
|
||||
while (in_offset < GST_BUFFER_SIZE (buf) &&
|
||||
out_offset < GST_BUFFER_SIZE (out_buf) - 4) {
|
||||
guint32 nal_size = 0;
|
||||
|
||||
switch (h264_data->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",
|
||||
h264_data->nal_length_size);
|
||||
}
|
||||
in_offset += h264_data->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;
|
||||
}
|
||||
|
||||
if (out_offset > GST_BUFFER_SIZE (out_buf)) {
|
||||
GST_WARNING_OBJECT (mux, "Calculated buffer size %" G_GSIZE_FORMAT
|
||||
" is greater than max expected size %u, "
|
||||
"using max expected size (Input might not be in "
|
||||
"avc format", out_offset, GST_BUFFER_SIZE (out_buf));
|
||||
out_offset = GST_BUFFER_SIZE (out_buf);
|
||||
}
|
||||
GST_BUFFER_SIZE (out_buf) = out_offset;
|
||||
|
||||
return out_buf;
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
* Copyright 2006, 2007, 2008, 2009, 2010 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);
|
||||
|
||||
void mpegtsmux_free_h264 (gpointer prepare_data);
|
||||
|
||||
#endif /* __MPEGTSMUX_H264_H__ */
|
|
@ -45,12 +45,12 @@ static guint32 crc_tab[256] = {
|
|||
};
|
||||
|
||||
static guint32
|
||||
calc_crc32 (guint8 *data, guint datalen)
|
||||
calc_crc32 (guint8 * data, guint datalen)
|
||||
{
|
||||
guint i;
|
||||
guint32 crc = 0xffffffff;
|
||||
|
||||
for (i=0; i<datalen; i++) {
|
||||
for (i = 0; i < datalen; i++) {
|
||||
crc = (crc << 8) ^ crc_tab[((crc >> 24) ^ *data++) & 0xff];
|
||||
}
|
||||
|
||||
|
|
|
@ -466,7 +466,7 @@ tsmux_get_buffer (TsMux * mux, GstBuffer ** buf)
|
|||
if (!*buf)
|
||||
return FALSE;
|
||||
|
||||
g_assert (GST_BUFFER_SIZE (*buf) == TSMUX_PACKET_LENGTH);
|
||||
g_assert (gst_buffer_get_size (*buf) == TSMUX_PACKET_LENGTH);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -746,7 +746,7 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
|
|||
gboolean res;
|
||||
gint64 cur_pcr = -1;
|
||||
GstBuffer *buf = NULL;
|
||||
guint8 *data;
|
||||
GstMapInfo map;
|
||||
|
||||
g_return_val_if_fail (mux != NULL, FALSE);
|
||||
g_return_val_if_fail (stream != NULL, FALSE);
|
||||
|
@ -767,7 +767,7 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
|
|||
cur_pcr = (cur_pts - TSMUX_PCR_OFFSET) *
|
||||
(TSMUX_SYS_CLOCK_FREQ / TSMUX_CLOCK_FREQ);
|
||||
|
||||
cur_pcr += CLOCK_BASE * (TSMUX_SYS_CLOCK_FREQ / TSMUX_CLOCK_FREQ);
|
||||
cur_pcr += (gint64) CLOCK_BASE *(TSMUX_SYS_CLOCK_FREQ / TSMUX_CLOCK_FREQ);
|
||||
|
||||
/* Need to decide whether to write a new PCR in this packet */
|
||||
if (stream->last_pcr == -1 ||
|
||||
|
@ -830,14 +830,17 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
|
|||
if (!tsmux_get_buffer (mux, &buf))
|
||||
return FALSE;
|
||||
|
||||
data = GST_BUFFER_DATA (buf);
|
||||
gst_buffer_map (buf, &map, GST_MAP_READ);
|
||||
|
||||
if (!tsmux_write_ts_header (data, pi, &payload_len, &payload_offs))
|
||||
if (!tsmux_write_ts_header (map.data, pi, &payload_len, &payload_offs))
|
||||
goto fail;
|
||||
|
||||
if (!tsmux_stream_get_data (stream, data + payload_offs, payload_len))
|
||||
|
||||
if (!tsmux_stream_get_data (stream, map.data + payload_offs, payload_len))
|
||||
goto fail;
|
||||
|
||||
gst_buffer_unmap (buf, &map);
|
||||
|
||||
res = tsmux_packet_out (mux, buf, cur_pcr);
|
||||
|
||||
/* Reset all dynamic flags */
|
||||
|
@ -848,6 +851,7 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
|
|||
/* ERRORS */
|
||||
fail:
|
||||
{
|
||||
gst_buffer_unmap (buf, &map);
|
||||
if (buf)
|
||||
gst_buffer_unref (buf);
|
||||
return FALSE;
|
||||
|
@ -878,6 +882,7 @@ tsmux_write_section (TsMux * mux, TsMuxSection * section)
|
|||
guint payload_len, payload_offs;
|
||||
TsMuxPacketInfo *pi;
|
||||
GstBuffer *buf = NULL;
|
||||
GstMapInfo map;
|
||||
|
||||
pi = §ion->pi;
|
||||
|
||||
|
@ -887,43 +892,45 @@ tsmux_write_section (TsMux * mux, TsMuxSection * section)
|
|||
payload_remain = pi->stream_avail;
|
||||
|
||||
while (payload_remain > 0) {
|
||||
guint8 *data;
|
||||
|
||||
/* obtain buffer */
|
||||
map.data = NULL;
|
||||
if (!tsmux_get_buffer (mux, &buf))
|
||||
goto fail;
|
||||
|
||||
data = GST_BUFFER_DATA (buf);
|
||||
gst_buffer_map (buf, &map, GST_MAP_WRITE);
|
||||
|
||||
if (pi->packet_start_unit_indicator) {
|
||||
/* Need to write an extra single byte start pointer */
|
||||
pi->stream_avail++;
|
||||
|
||||
if (!tsmux_write_ts_header (data, pi, &payload_len, &payload_offs)) {
|
||||
if (!tsmux_write_ts_header (map.data, pi, &payload_len, &payload_offs)) {
|
||||
pi->stream_avail--;
|
||||
goto fail;
|
||||
}
|
||||
pi->stream_avail--;
|
||||
|
||||
/* Write the pointer byte */
|
||||
data[payload_offs] = 0x00;
|
||||
map.data[payload_offs] = 0x00;
|
||||
|
||||
payload_offs++;
|
||||
payload_len--;
|
||||
pi->packet_start_unit_indicator = FALSE;
|
||||
} else {
|
||||
if (!tsmux_write_ts_header (data, pi, &payload_len, &payload_offs))
|
||||
if (!tsmux_write_ts_header (map.data, pi, &payload_len, &payload_offs))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
TS_DEBUG ("Outputting %d bytes to section. %d remaining after",
|
||||
payload_len, payload_remain - payload_len);
|
||||
|
||||
memcpy (data + payload_offs, cur_in, payload_len);
|
||||
memcpy (map.data + payload_offs, cur_in, payload_len);
|
||||
|
||||
cur_in += payload_len;
|
||||
payload_remain -= payload_len;
|
||||
|
||||
gst_buffer_unmap (buf, &map);
|
||||
|
||||
/* we do not write PCR in section */
|
||||
if (G_UNLIKELY (!tsmux_packet_out (mux, buf, -1))) {
|
||||
/* buffer given away */
|
||||
|
@ -938,6 +945,8 @@ tsmux_write_section (TsMux * mux, TsMuxSection * section)
|
|||
/* ERRORS */
|
||||
fail:
|
||||
{
|
||||
if (map.data && buf)
|
||||
gst_buffer_unmap (buf, &map);
|
||||
if (buf)
|
||||
gst_buffer_unref (buf);
|
||||
return FALSE;
|
||||
|
|
Loading…
Reference in a new issue