}
static GstFlowReturn
-gst_base_ts_mux_create_streams (GstBaseTsMux * mux)
+gst_base_ts_mux_create_pad_stream (GstBaseTsMux * mux, GstPad * pad)
{
+ GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (pad);
+ gchar *name = NULL;
+ gchar *pcr_name;
GstFlowReturn ret = GST_FLOW_OK;
- GList *walk = GST_ELEMENT (mux)->sinkpads;
- /* Create the streams */
- while (walk) {
- GstPad *pad = GST_PAD (walk->data);
- GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (walk->data);
- gchar *name = NULL;
- gchar *pcr_name;
-
- walk = g_list_next (walk);
-
- if (ts_pad->prog_id == -1) {
- name = GST_PAD_NAME (pad);
- if (mux->prog_map != NULL && gst_structure_has_field (mux->prog_map,
- name)) {
- gint idx;
- gboolean ret = gst_structure_get_int (mux->prog_map, name, &idx);
- if (!ret) {
- GST_ELEMENT_ERROR (mux, STREAM, MUX,
- ("Reading program map failed. Assuming default"), (NULL));
- idx = DEFAULT_PROG_ID;
- }
- if (idx < 0) {
- GST_DEBUG_OBJECT (mux, "Program number %d associate with pad %s less "
- "than zero; DEFAULT_PROGRAM = %d is used instead",
- idx, name, DEFAULT_PROG_ID);
- idx = DEFAULT_PROG_ID;
- }
- ts_pad->prog_id = idx;
- } else {
- ts_pad->prog_id = DEFAULT_PROG_ID;
+ if (ts_pad->prog_id == -1) {
+ name = GST_PAD_NAME (pad);
+ if (mux->prog_map != NULL && gst_structure_has_field (mux->prog_map, name)) {
+ gint idx;
+ gboolean ret = gst_structure_get_int (mux->prog_map, name, &idx);
+ if (!ret) {
+ GST_ELEMENT_ERROR (mux, STREAM, MUX,
+ ("Reading program map failed. Assuming default"), (NULL));
+ idx = DEFAULT_PROG_ID;
+ }
+ if (idx < 0) {
+ GST_DEBUG_OBJECT (mux, "Program number %d associate with pad %s less "
+ "than zero; DEFAULT_PROGRAM = %d is used instead",
+ idx, name, DEFAULT_PROG_ID);
+ idx = DEFAULT_PROG_ID;
}
+ ts_pad->prog_id = idx;
+ } else {
+ ts_pad->prog_id = DEFAULT_PROG_ID;
}
+ }
- ts_pad->prog =
- (TsMuxProgram *) g_hash_table_lookup (mux->programs,
- GINT_TO_POINTER (ts_pad->prog_id));
- if (ts_pad->prog == NULL) {
- ts_pad->prog = tsmux_program_new (mux->tsmux, ts_pad->prog_id);
- if (ts_pad->prog == NULL)
- goto no_program;
- tsmux_set_pmt_interval (ts_pad->prog, mux->pmt_interval);
- tsmux_program_set_scte35_pid (ts_pad->prog, mux->scte35_pid);
- tsmux_program_set_scte35_interval (ts_pad->prog,
- mux->scte35_null_interval);
- g_hash_table_insert (mux->programs, GINT_TO_POINTER (ts_pad->prog_id),
- ts_pad->prog);
- }
+ ts_pad->prog =
+ (TsMuxProgram *) g_hash_table_lookup (mux->programs,
+ GINT_TO_POINTER (ts_pad->prog_id));
+ if (ts_pad->prog == NULL) {
+ ts_pad->prog = tsmux_program_new (mux->tsmux, ts_pad->prog_id);
+ if (ts_pad->prog == NULL)
+ goto no_program;
+ tsmux_set_pmt_interval (ts_pad->prog, mux->pmt_interval);
+ tsmux_program_set_scte35_pid (ts_pad->prog, mux->scte35_pid);
+ tsmux_program_set_scte35_interval (ts_pad->prog, mux->scte35_null_interval);
+ g_hash_table_insert (mux->programs, GINT_TO_POINTER (ts_pad->prog_id),
+ ts_pad->prog);
+ }
- if (ts_pad->stream == NULL) {
- ret = gst_base_ts_mux_create_stream (mux, ts_pad);
- if (ret != GST_FLOW_OK)
- goto no_stream;
- }
+ if (ts_pad->stream == NULL) {
+ ret = gst_base_ts_mux_create_stream (mux, ts_pad);
+ if (ret != GST_FLOW_OK)
+ goto no_stream;
+ }
- if (ts_pad->prog->pcr_stream == NULL) {
- /* Take the first stream of the program for the PCR */
- GST_DEBUG_OBJECT (ts_pad,
- "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
- ts_pad->pid, ts_pad->prog_id);
+ if (ts_pad->prog->pcr_stream == NULL) {
+ /* Take the first stream of the program for the PCR */
+ GST_DEBUG_OBJECT (ts_pad,
+ "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
+ ts_pad->pid, ts_pad->prog_id);
- tsmux_program_set_pcr_stream (ts_pad->prog, ts_pad->stream);
- }
+ tsmux_program_set_pcr_stream (ts_pad->prog, ts_pad->stream);
+ }
- /* Check for user-specified PCR PID */
- pcr_name = g_strdup_printf ("PCR_%d", ts_pad->prog->pgm_number);
- if (mux->prog_map && gst_structure_has_field (mux->prog_map, pcr_name)) {
- const gchar *sink_name =
- gst_structure_get_string (mux->prog_map, pcr_name);
+ /* Check for user-specified PCR PID */
+ pcr_name = g_strdup_printf ("PCR_%d", ts_pad->prog->pgm_number);
+ if (mux->prog_map && gst_structure_has_field (mux->prog_map, pcr_name)) {
+ const gchar *sink_name = gst_structure_get_string (mux->prog_map, pcr_name);
- if (!g_strcmp0 (name, sink_name)) {
- GST_DEBUG_OBJECT (mux, "User specified stream (pid=%d) as PCR for "
- "program (prog_id = %d)", ts_pad->pid, ts_pad->prog->pgm_number);
- tsmux_program_set_pcr_stream (ts_pad->prog, ts_pad->stream);
- }
+ if (!g_strcmp0 (name, sink_name)) {
+ GST_DEBUG_OBJECT (mux, "User specified stream (pid=%d) as PCR for "
+ "program (prog_id = %d)", ts_pad->pid, ts_pad->prog->pgm_number);
+ tsmux_program_set_pcr_stream (ts_pad->prog, ts_pad->stream);
}
- g_free (pcr_name);
}
+ g_free (pcr_name);
- return GST_FLOW_OK;
+ return ret;
/* ERRORS */
no_program:
}
}
+static GstFlowReturn
+gst_base_ts_mux_create_streams (GstBaseTsMux * mux)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GList *walk = GST_ELEMENT (mux)->sinkpads;
+
+ /* Create the streams */
+ while (walk) {
+ GstPad *pad = GST_PAD (walk->data);
+
+ ret = gst_base_ts_mux_create_pad_stream (mux, pad);
+ if (ret != GST_FLOW_OK)
+ return ret;
+ walk = g_list_next (walk);
+ }
+
+ return GST_FLOW_OK;
+}
+
static void
new_packet_common_init (GstBaseTsMux * mux, GstBuffer * buf, guint8 * data,
guint len)
}
prog = best->prog;
- if (prog == NULL)
- goto no_program;
+ if (prog == NULL) {
+ GList *cur;
+
+ gst_base_ts_mux_create_pad_stream (mux, GST_PAD (best));
+ tsmux_resend_pat (mux->tsmux);
+ tsmux_resend_si (mux->tsmux);
+ prog = best->prog;
+ g_assert_nonnull (prog);
+
+ /* output PMT for each program */
+ for (cur = mux->tsmux->programs; cur; cur = cur->next) {
+ TsMuxProgram *program = (TsMuxProgram *) cur->data;
+
+ tsmux_resend_pmt (program);
+ }
+ }
g_assert (buf != NULL);
{
return mux->last_flow_ret;
}
-no_program:
- {
- if (buf)
- gst_buffer_unref (buf);
- GST_ELEMENT_ERROR (mux, STREAM, MUX,
- ("Stream on pad %" GST_PTR_FORMAT
- " is not associated with any program", best), (NULL));
- return GST_FLOW_ERROR;
- }
}
/* GstElement implementation */
}
}
+static void
+gst_base_ts_mux_release_pad (GstElement * element, GstPad * pad)
+{
+ GstBaseTsMux *mux = GST_BASE_TS_MUX (element);
+
+ if (mux->tsmux) {
+ GList *cur;
+ GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (pad);
+ gint pid = ts_pad->pid;
+
+ if (ts_pad->prog->pcr_stream == ts_pad->stream) {
+ tsmux_stream_pcr_unref (ts_pad->prog->pcr_stream);
+ ts_pad->prog->pcr_stream = NULL;
+ }
+ if (tsmux_remove_stream (mux->tsmux, pid, ts_pad->prog)) {
+ g_hash_table_remove (mux->programs, GINT_TO_POINTER (ts_pad->prog_id));
+ }
+ tsmux_resend_pat (mux->tsmux);
+ tsmux_resend_si (mux->tsmux);
+
+ /* output PMT for each program */
+ for (cur = mux->tsmux->programs; cur; cur = cur->next) {
+ TsMuxProgram *program = (TsMuxProgram *) cur->data;
+
+ tsmux_resend_pmt (program);
+ }
+ }
+
+ gst_element_remove_pad (element, pad);
+}
+
static gboolean
gst_base_ts_mux_send_event (GstElement * element, GstEvent * event)
{
gobject_class->constructed = gst_base_ts_mux_constructed;
gstelement_class->request_new_pad = gst_base_ts_mux_request_new_pad;
+ gstelement_class->release_pad = gst_base_ts_mux_release_pad;
gstelement_class->send_event = gst_base_ts_mux_send_event;
gstagg_class->update_src_caps = gst_base_ts_mux_update_src_caps;
}
static void
-check_tsmux_pad (GstStaticPadTemplate * srctemplate,
+check_tsmux_pad_given_muxer (GstElement * mux,
const gchar * src_caps_string, gint pes_id, gint pmt_id,
- const gchar * sinkname, CheckOutputBuffersFunc check_func, guint n_bufs,
- gssize input_buf_size, guint alignment)
+ CheckOutputBuffersFunc check_func, guint n_bufs, gssize input_buf_size)
{
GstClockTime ts;
- GstElement *mux;
GstBuffer *inbuffer, *outbuffer;
GstCaps *caps;
gint num_buffers;
gint i;
gint pmt_pid = -1, el_pid = -1, pcr_pid = -1, packets = 0;
- gchar *padname;
GstQuery *drain;
- mux = setup_tsmux (srctemplate, sinkname, &padname);
-
- if (alignment != 0)
- g_object_set (mux, "alignment", alignment, NULL);
-
- fail_unless (gst_element_set_state (mux,
- GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
- "could not set to playing");
-
caps = gst_caps_from_string (src_caps_string);
gst_check_setup_events (mysrcpad, mux, caps, GST_FORMAT_TIME);
gst_caps_unref (caps);
g_list_free (buffers);
buffers = NULL;
+}
+
+static void
+check_tsmux_pad (GstStaticPadTemplate * srctemplate,
+ const gchar * src_caps_string, gint pes_id, gint pmt_id,
+ const gchar * sinkname, CheckOutputBuffersFunc check_func, guint n_bufs,
+ gssize input_buf_size, guint alignment)
+{
+ gchar *padname;
+ GstElement *mux;
+
+ mux = setup_tsmux (srctemplate, sinkname, &padname);
+
+ if (alignment != 0)
+ g_object_set (mux, "alignment", alignment, NULL);
+
+ fail_unless (gst_element_set_state (mux,
+ GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+ "could not set to playing");
+
+ check_tsmux_pad_given_muxer (mux, src_caps_string, pes_id, pmt_id,
+ check_func, n_bufs, input_buf_size);
cleanup_tsmux (mux, padname);
g_free (padname);
}
+GST_START_TEST (test_reappearing_pad)
+{
+ gchar *padname;
+ GstElement *mux;
+ GstPad *pad;
+
+ mux = gst_check_setup_element ("mpegtsmux");
+ mysrcpad = setup_src_pad (mux, &video_src_template, "sink_%d", &padname);
+ mysinkpad = gst_check_setup_sink_pad (mux, &sink_template);
+ gst_pad_set_active (mysrcpad, TRUE);
+ gst_pad_set_active (mysinkpad, TRUE);
+
+ fail_unless (gst_element_set_state (mux,
+ GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+ "could not set to playing");
+
+ check_tsmux_pad_given_muxer (mux, VIDEO_CAPS_STRING, 0xE0, 0x1b, NULL, 1, 1);
+
+ pad = gst_element_get_static_pad (mux, padname);
+ gst_pad_set_active (mysrcpad, FALSE);
+ gst_object_unref (pad);
+ teardown_src_pad (mux, padname);
+ gst_element_release_request_pad (mux, pad);
+ g_free (padname);
+
+ mysrcpad = setup_src_pad (mux, &video_src_template, "sink_%d", &padname);
+ gst_pad_set_active (mysrcpad, TRUE);
+
+ check_tsmux_pad_given_muxer (mux, VIDEO_CAPS_STRING, 0xE0, 0x1b, NULL, 1, 1);
+
+ cleanup_tsmux (mux, padname);
+ g_free (padname);
+}
+
+GST_END_TEST;
GST_START_TEST (test_video)
{
tcase_add_test (tc_chain, test_multiple_state_change);
tcase_add_test (tc_chain, test_align);
tcase_add_test (tc_chain, test_keyframe_flag_propagation);
+ tcase_add_test (tc_chain, test_reappearing_pad);
return s;
}