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; }
gboolean mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad, GstEvent * event) { MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); GstFlowReturn ret = GST_FLOW_ERROR; gdouble rate; gboolean flush; GstFormat format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; GstEvent *flush_event = NULL; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); if (format != GST_FORMAT_TIME) return FALSE; if (GST_EVENT_SEQNUM (event) == base->last_seek_seqnum) { GST_DEBUG_OBJECT (base, "Skipping already handled seek"); return TRUE; } if (base->mode == BASE_MODE_PUSHING) { /* First try if upstream supports seeking in TIME format */ if (gst_pad_push_event (base->sinkpad, gst_event_ref (event))) { GST_DEBUG ("upstream handled SEEK event"); return TRUE; } /* If the subclass can seek, do that */ if (klass->seek) { ret = klass->seek (base, event); if (G_UNLIKELY (ret != GST_FLOW_OK)) GST_WARNING ("seeking failed %s", gst_flow_get_name (ret)); else { GstEvent *new_seek; if (GST_CLOCK_TIME_IS_VALID (base->seek_offset)) { base->mode = BASE_MODE_SEEKING; new_seek = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, GST_SEEK_TYPE_SET, base->seek_offset, GST_SEEK_TYPE_NONE, -1); gst_event_set_seqnum (new_seek, GST_EVENT_SEQNUM (event)); if (!gst_pad_push_event (base->sinkpad, new_seek)) ret = GST_FLOW_ERROR; else base->last_seek_seqnum = GST_EVENT_SEQNUM (event); } base->mode = BASE_MODE_PUSHING; } } else { GST_WARNING ("subclass has no seek implementation"); } return ret == GST_FLOW_OK; } if (!klass->seek) { GST_WARNING ("subclass has no seek implementation"); return FALSE; } if (rate <= 0.0) { GST_WARNING ("Negative rate not supported"); return FALSE; } GST_DEBUG ("seek event, rate: %f start: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); flush = flags & GST_SEEK_FLAG_FLUSH; /* stop streaming, either by flushing or by pausing the task */ base->mode = BASE_MODE_SEEKING; if (flush) { GST_DEBUG_OBJECT (base, "sending flush start"); flush_event = gst_event_new_flush_start (); gst_event_set_seqnum (flush_event, GST_EVENT_SEQNUM (event)); gst_pad_push_event (base->sinkpad, gst_event_ref (flush_event)); GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, flush_event); } else gst_pad_pause_task (base->sinkpad); /* wait for streaming to finish */ GST_PAD_STREAM_LOCK (base->sinkpad); if (flush) { /* send a FLUSH_STOP for the sinkpad, since we need data for seeking */ GST_DEBUG_OBJECT (base, "sending flush stop"); flush_event = gst_event_new_flush_stop (TRUE); gst_event_set_seqnum (flush_event, GST_EVENT_SEQNUM (event)); /* ref for it to be reused later */ gst_pad_push_event (base->sinkpad, gst_event_ref (flush_event)); /* And actually flush our pending data but allow to preserve some info * to perform the seek */ mpegts_base_flush (base, FALSE); mpegts_packetizer_flush (base->packetizer, FALSE); } if (flags & (GST_SEEK_FLAG_SEGMENT)) { GST_WARNING ("seek flags 0x%x are not supported", (int) flags); goto done; } /* If the subclass can seek, do that */ ret = klass->seek (base, event); if (G_UNLIKELY (ret != GST_FLOW_OK)) GST_WARNING ("seeking failed %s", gst_flow_get_name (ret)); else base->last_seek_seqnum = GST_EVENT_SEQNUM (event); if (flush_event) { /* if we sent a FLUSH_START, we now send a FLUSH_STOP */ GST_DEBUG_OBJECT (base, "sending flush stop"); GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, flush_event); flush_event = NULL; } done: if (flush_event) gst_event_unref (flush_event); gst_pad_start_task (base->sinkpad, (GstTaskFunction) mpegts_base_loop, base, NULL); GST_PAD_STREAM_UNLOCK (base->sinkpad); return ret == GST_FLOW_OK; }
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; }