static GstStateChangeReturn mpegts_base_change_state (GstElement * element, GstStateChange transition) { MpegTSBase *base; GstStateChangeReturn ret; base = GST_MPEGTS_BASE (element); switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: mpegts_base_reset (base); break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: mpegts_base_reset (base); if (base->mode != BASE_MODE_PUSHING) base->mode = BASE_MODE_SCANNING; break; default: break; } return ret; }
static gboolean mpegts_base_sink_activate_mode (GstPad * pad, GstObject * parent, GstPadMode mode, gboolean active) { gboolean res; MpegTSBase *base = GST_MPEGTS_BASE (parent); switch (mode) { case GST_PAD_MODE_PUSH: base->mode = BASE_MODE_PUSHING; res = TRUE; break; case GST_PAD_MODE_PULL: if (active) { base->mode = BASE_MODE_SCANNING; /* When working pull-based, we always use offsets for estimation */ base->packetizer->calculate_offset = TRUE; base->packetizer->calculate_skew = FALSE; gst_segment_init (&base->segment, GST_FORMAT_BYTES); res = gst_pad_start_task (pad, (GstTaskFunction) mpegts_base_loop, base, NULL); } else res = gst_pad_stop_task (pad); break; default: res = FALSE; break; } return res; }
static void gst_ts_demux_init (GstTSDemux * demux, GstTSDemuxClass * klass) { demux->need_newsegment = TRUE; demux->program_number = -1; demux->duration = GST_CLOCK_TIME_NONE; GST_MPEGTS_BASE (demux)->stream_size = sizeof (TSDemuxStream); }
static void mpegts_parse_init (MpegTSParse2 * parse, MpegTSParse2Class * klass) { parse->need_sync_program_pads = FALSE; parse->program_numbers = g_strdup (""); parse->pads_to_add = NULL; parse->pads_to_remove = NULL; GST_MPEGTS_BASE (parse)->program_size = sizeof (MpegTSParseProgram); }
static gboolean mpegts_base_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = TRUE; gboolean hard; MpegTSBase *base = GST_MPEGTS_BASE (parent); GST_DEBUG_OBJECT (base, "Got event %s", gst_event_type_get_name (GST_EVENT_TYPE (event))); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEGMENT: gst_event_copy_segment (event, &base->segment); GST_DEBUG_OBJECT (base, "Received segment %" GST_SEGMENT_FORMAT, &base->segment); /* Check if we need to switch PCR/PTS handling */ if (base->segment.format == GST_FORMAT_TIME) { base->packetizer->calculate_offset = FALSE; base->packetizer->calculate_skew = TRUE; } else { base->packetizer->calculate_offset = TRUE; base->packetizer->calculate_skew = FALSE; } res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event); break; case GST_EVENT_STREAM_START: gst_event_unref (event); break; case GST_EVENT_EOS: res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event); res = gst_mpegts_base_handle_eos (base); break; case GST_EVENT_CAPS: /* FIXME, do something */ gst_event_unref (event); break; case GST_EVENT_FLUSH_STOP: res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event); hard = (base->mode != BASE_MODE_SEEKING); mpegts_packetizer_flush (base->packetizer, hard); mpegts_base_flush (base, hard); gst_segment_init (&base->segment, GST_FORMAT_UNDEFINED); base->seen_pat = FALSE; break; default: res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event); } /* Always return TRUE for sticky events */ if (GST_EVENT_IS_STICKY (event)) res = TRUE; return res; }
static void mpegts_base_finalize (GObject * object) { MpegTSBase *base = GST_MPEGTS_BASE (object); if (base->pat) { g_ptr_array_unref (base->pat); base->pat = NULL; } g_hash_table_destroy (base->programs); if (G_OBJECT_CLASS (parent_class)->finalize) G_OBJECT_CLASS (parent_class)->finalize (object); }
static void mpegts_base_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { MpegTSBase *base = GST_MPEGTS_BASE (object); switch (prop_id) { case PROP_PARSE_PRIVATE_SECTIONS: g_value_set_boolean (value, base->parse_private_sections); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } }
static void mpegts_base_dispose (GObject * object) { MpegTSBase *base = GST_MPEGTS_BASE (object); if (!base->disposed) { g_object_unref (base->packetizer); base->disposed = TRUE; g_free (base->known_psi); g_free (base->is_pes); } if (G_OBJECT_CLASS (parent_class)->dispose) G_OBJECT_CLASS (parent_class)->dispose (object); }
static void mpegts_parse_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { MpegTSParse2 *parse = (MpegTSParse2 *) object; switch (prop_id) { case PROP_SET_TIMESTAMPS: parse->set_timestamps = g_value_get_boolean (value); break; case PROP_SMOOTHING_LATENCY: parse->smoothing_latency = GST_USECOND * g_value_get_uint (value); mpegts_packetizer_set_pcr_discont_threshold (GST_MPEGTS_BASE (parse)->packetizer, parse->smoothing_latency); break; case PROP_PCR_PID: parse->pcr_pid = parse->user_pcr_pid = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } }
static GstFlowReturn mpegts_base_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn res = GST_FLOW_OK; MpegTSBase *base; MpegTSPacketizerPacketReturn pret; MpegTSPacketizer2 *packetizer; MpegTSPacketizerPacket packet; MpegTSBaseClass *klass; base = GST_MPEGTS_BASE (parent); klass = GST_MPEGTS_BASE_GET_CLASS (base); packetizer = base->packetizer; if (klass->input_done) gst_buffer_ref (buf); if (GST_BUFFER_IS_DISCONT (buf)) { GST_DEBUG_OBJECT (base, "Got DISCONT buffer, flushing"); res = mpegts_base_drain (base); if (G_UNLIKELY (res != GST_FLOW_OK)) return res; mpegts_base_flush (base, FALSE); /* In the case of discontinuities in push-mode with TIME segment * we want to drop all previous observations (hard:TRUE) from * the packetizer */ if (base->mode == BASE_MODE_PUSHING && base->segment.format == GST_FORMAT_TIME) mpegts_packetizer_flush (base->packetizer, TRUE); else mpegts_packetizer_flush (base->packetizer, FALSE); } mpegts_packetizer_push (base->packetizer, buf); while (res == GST_FLOW_OK) { pret = mpegts_packetizer_next_packet (base->packetizer, &packet); /* If we don't have enough data, return */ if (G_UNLIKELY (pret == PACKET_NEED_MORE)) break; if (G_UNLIKELY (pret == PACKET_BAD)) { /* bad header, skip the packet */ GST_DEBUG_OBJECT (base, "bad packet, skipping"); goto next; } if (klass->inspect_packet) klass->inspect_packet (base, &packet); /* If it's a known PES, push it */ if (MPEGTS_BIT_IS_SET (base->is_pes, packet.pid)) { /* push the packet downstream */ if (base->push_data) res = klass->push (base, &packet, NULL); } else if (packet.payload && MPEGTS_BIT_IS_SET (base->known_psi, packet.pid)) { /* base PSI data */ GList *others, *tmp; GstMpegtsSection *section; section = mpegts_packetizer_push_section (packetizer, &packet, &others); if (section) mpegts_base_handle_psi (base, section); if (G_UNLIKELY (others)) { for (tmp = others; tmp; tmp = tmp->next) mpegts_base_handle_psi (base, (GstMpegtsSection *) tmp->data); g_list_free (others); } /* we need to push section packet downstream */ if (base->push_section) res = klass->push (base, &packet, section); } else if (packet.payload && packet.pid != 0x1fff) GST_LOG ("PID 0x%04x Saw packet on a pid we don't handle", packet.pid); next: mpegts_packetizer_clear_packet (base->packetizer, &packet); } if (klass->input_done) { if (res == GST_FLOW_OK) res = klass->input_done (base, buf); else gst_buffer_unref (buf); } return res; }
g_return_val_if_fail (template != NULL, NULL); g_return_val_if_fail (GST_IS_MPEGTS_PARSE (element), NULL); g_return_val_if_fail (padname != NULL, NULL); sscanf (padname + 8, "%d", &program_num); GST_DEBUG_OBJECT (element, "padname:%s, program:%d", padname, program_num); parse = GST_MPEGTS_PARSE (element); tspad = mpegts_parse_create_tspad (parse, padname); tspad->program_number = program_num; /* Find if the program is already active */ parseprogram = (MpegTSParseProgram *) mpegts_base_get_program (GST_MPEGTS_BASE (parse), program_num); if (parseprogram) { tspad->program = parseprogram; parseprogram->tspad = tspad; } pad = tspad->pad; parse->srcpads = g_list_append (parse->srcpads, pad); base->push_data = TRUE; base->push_section = TRUE; gst_pad_set_active (pad, TRUE); stream_id = gst_pad_create_stream_id (pad, element, padname + 8);
static GstFlowReturn mpegts_base_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn res = GST_FLOW_OK; MpegTSBase *base; MpegTSPacketizerPacketReturn pret; MpegTSPacketizer2 *packetizer; MpegTSPacketizerPacket packet; MpegTSBaseClass *klass; base = GST_MPEGTS_BASE (parent); klass = GST_MPEGTS_BASE_GET_CLASS (base); packetizer = base->packetizer; if (G_UNLIKELY (base->queried_latency == FALSE)) { query_upstream_latency (base); } if (klass->input_done) gst_buffer_ref (buf); mpegts_packetizer_push (base->packetizer, buf); while (res == GST_FLOW_OK) { pret = mpegts_packetizer_next_packet (base->packetizer, &packet); /* If we don't have enough data, return */ if (G_UNLIKELY (pret == PACKET_NEED_MORE)) break; if (G_UNLIKELY (pret == PACKET_BAD)) { /* bad header, skip the packet */ GST_DEBUG_OBJECT (base, "bad packet, skipping"); goto next; } /* If it's a known PES, push it */ if (MPEGTS_BIT_IS_SET (base->is_pes, packet.pid)) { /* push the packet downstream */ if (base->push_data) res = klass->push (base, &packet, NULL); } else if (packet.payload && MPEGTS_BIT_IS_SET (base->known_psi, packet.pid)) { /* base PSI data */ GList *others, *tmp; GstMpegTsSection *section; section = mpegts_packetizer_push_section (packetizer, &packet, &others); if (section) mpegts_base_handle_psi (base, section); if (G_UNLIKELY (others)) { for (tmp = others; tmp; tmp = tmp->next) mpegts_base_handle_psi (base, (GstMpegTsSection *) tmp->data); g_list_free (others); } /* we need to push section packet downstream */ if (base->push_section) res = klass->push (base, &packet, section); } else if (packet.payload && packet.pid != 0x1fff) GST_LOG ("PID 0x%04x Saw packet on a pid we don't handle", packet.pid); next: mpegts_packetizer_clear_packet (base->packetizer, &packet); } if (klass->input_done) { if (res == GST_FLOW_OK) res = klass->input_done (base, buf); else gst_buffer_unref (buf); } return res; }