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; } if (pad_data->prepare_data && pad_data->free_func) { pad_data->free_func (pad_data->prepare_data); pad_data->prepare_data = pad_data->free_func = NULL; } } GST_OBJECT_UNLOCK (pad); gst_collect_pads_remove_pad (mux->collect, pad); }
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 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_pads2_add_pad (mux->collect, pad, sizeof (MpegTsPadData)); if (pad_data == NULL) goto pad_failure; pad_data->eventfunc = pad->eventfunc; gst_pad_set_event_function (pad, mpegtsmux_sink_event); pad_data->pid = pid; pad_data->last_ts = GST_CLOCK_TIME_NONE; pad_data->codec_data = NULL; pad_data->prepare_data = NULL; pad_data->prepare_func = NULL; pad_data->free_func = NULL; pad_data->prog_id = -1; pad_data->prog = 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_pads2_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 gboolean mpegtsmux_sink_event (GstPad * pad, GstEvent * event) { MpegTsMux *mux = GST_MPEG_TSMUX (gst_pad_get_parent (pad)); MpegTsPadData *ts_data; gboolean res = TRUE; gboolean forward = TRUE; ts_data = (MpegTsPadData *) gst_pad_get_element_private (pad); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CUSTOM_DOWNSTREAM: { GstClockTime timestamp, stream_time, running_time; gboolean all_headers; guint count; if (!gst_video_event_is_force_key_unit (event)) goto out; forward = FALSE; gst_video_event_parse_downstream_force_key_unit (event, ×tamp, &stream_time, &running_time, &all_headers, &count); GST_INFO_OBJECT (mux, "have downstream force-key-unit event on pad %s, " "seqnum %d, running-time %" GST_TIME_FORMAT " count %d", gst_pad_get_name (pad), gst_event_get_seqnum (event), GST_TIME_ARGS (running_time), count); if (mux->force_key_unit_event != NULL) { GST_INFO_OBJECT (mux, "skipping downstream force key unit event " "as an upstream force key unit is already queued"); goto out; } if (!all_headers) goto out; mux->pending_key_unit_ts = running_time; gst_event_replace (&mux->force_key_unit_event, event); break; } default: break; } out: if (forward) res = ts_data->eventfunc (pad, event); gst_object_unref (mux); return res; }
static void mpegtsmux_release_pad (GstElement * element, GstPad * pad) { MpegTsMux *mux = GST_MPEG_TSMUX (element); GST_DEBUG_OBJECT (mux, "Pad %" GST_PTR_FORMAT " being released", pad); if (mux->collect) { gst_collect_pads2_remove_pad (mux->collect, pad); } /* chain up */ gst_element_remove_pad (element, pad); }
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 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_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { MpegTsMux *mux = GST_MPEG_TSMUX (object); GSList *walk; 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; case ARG_PROG_MAP: { const GstStructure *s = gst_value_get_structure (value); if (mux->prog_map) { gst_structure_free (mux->prog_map); } if (s) mux->prog_map = gst_structure_copy (s); else mux->prog_map = NULL; break; } case ARG_PAT_INTERVAL: mux->pat_interval = g_value_get_uint (value); if (mux->tsmux) tsmux_set_pat_interval (mux->tsmux, mux->pat_interval); break; case ARG_PMT_INTERVAL: walk = mux->collect->data; mux->pmt_interval = g_value_get_uint (value); while (walk) { MpegTsPadData *ts_data = (MpegTsPadData *) walk->data; tsmux_set_pmt_interval (ts_data->prog, mux->pmt_interval); walk = g_slist_next (walk); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void mpegtsmux_dispose (GObject * object) { MpegTsMux *mux = GST_MPEG_TSMUX (object); if (mux->adapter) { gst_adapter_clear (mux->adapter); g_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; } if (mux->prog_map) { gst_structure_free (mux->prog_map); mux->prog_map = NULL; } if (mux->programs) { g_free (mux->programs); mux->programs = NULL; } if (mux->streamheader) { GstBuffer *buf; GList *sh; sh = mux->streamheader; while (sh) { buf = sh->data; gst_buffer_unref (buf); sh = g_list_next (sh); } g_list_free (mux->streamheader); mux->streamheader = NULL; } GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); }
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_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; case ARG_PROG_MAP: gst_value_set_structure (value, mux->prog_map); break; case ARG_PAT_INTERVAL: g_value_set_uint (value, mux->pat_interval); break; case ARG_PMT_INTERVAL: g_value_set_uint (value, mux->pmt_interval); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean mpegtsmux_src_event (GstPad * pad, GstEvent * event) { MpegTsMux *mux = GST_MPEG_TSMUX (gst_pad_get_parent (pad)); gboolean res = TRUE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CUSTOM_UPSTREAM: { GstIterator *iter; GstIteratorResult iter_ret; GstPad *sinkpad; GstClockTime running_time; gboolean all_headers, done; guint count; if (!gst_video_event_is_force_key_unit (event)) break; gst_video_event_parse_upstream_force_key_unit (event, &running_time, &all_headers, &count); GST_INFO_OBJECT (mux, "received upstream force-key-unit event, " "seqnum %d running_time %" GST_TIME_FORMAT " all_headers %d count %d", gst_event_get_seqnum (event), GST_TIME_ARGS (running_time), all_headers, count); if (!all_headers) break; mux->pending_key_unit_ts = running_time; gst_event_replace (&mux->force_key_unit_event, event); iter = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mux)); done = FALSE; while (!done) { gboolean res = FALSE, tmp; iter_ret = gst_iterator_next (iter, (gpointer *) & sinkpad); switch (iter_ret) { case GST_ITERATOR_DONE: done = TRUE; break; case GST_ITERATOR_OK: GST_INFO_OBJECT (mux, "forwarding to %s", gst_pad_get_name (sinkpad)); tmp = gst_pad_push_event (sinkpad, gst_event_ref (event)); GST_INFO_OBJECT (mux, "result %d", tmp); /* succeed if at least one pad succeeds */ res |= tmp; gst_object_unref (sinkpad); break; case GST_ITERATOR_ERROR: done = TRUE; break; case GST_ITERATOR_RESYNC: break; } } gst_event_unref (event); break; } default: res = gst_pad_event_default (pad, event); break; } gst_object_unref (mux); return res; }