/* chain function * this function does the actual processing */ static GstFlowReturn gst_kate_enc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstKateEnc *ke = GST_KATE_ENC (parent); GstFlowReturn rflow; GST_DEBUG_OBJECT (ke, "got packet, %" G_GSIZE_FORMAT " bytes", gst_buffer_get_size (buf)); /* first push headers if we haven't done that yet */ rflow = gst_kate_enc_flush_headers (ke); if (G_LIKELY (rflow == GST_FLOW_OK)) { /* flush any packet we had waiting */ rflow = gst_kate_enc_flush_waiting (ke, GST_BUFFER_TIMESTAMP (buf)); if (G_LIKELY (rflow == GST_FLOW_OK)) { if (ke->format == GST_KATE_FORMAT_SPU) { /* encode a kate_bitmap */ rflow = gst_kate_enc_chain_spu (ke, buf); } else { /* encode text */ rflow = gst_kate_enc_chain_text (ke, buf); } } } gst_buffer_unref (buf); return rflow; }
/* chain function * this function does the actual processing */ static GstFlowReturn gst_kate_enc_chain (GstPad * pad, GstBuffer * buf) { GstKateEnc *ke = GST_KATE_ENC (gst_pad_get_parent (pad)); GstFlowReturn rflow = GST_FLOW_OK; GstCaps *caps; const gchar *mime_type = NULL; GST_DEBUG_OBJECT (ke, "got packet, %u bytes", GST_BUFFER_SIZE (buf)); /* get the type of the data we're being sent */ caps = GST_PAD_CAPS (pad); if (G_UNLIKELY (caps == NULL)) { GST_WARNING_OBJECT (ke, "No input caps set"); rflow = GST_FLOW_NOT_NEGOTIATED; } else { const GstStructure *structure = gst_caps_get_structure (caps, 0); if (structure) mime_type = gst_structure_get_name (structure); if (mime_type) { GST_LOG_OBJECT (ke, "Packet has MIME type %s", mime_type); /* first push headers if we haven't done that yet */ rflow = gst_kate_enc_flush_headers (ke); if (G_LIKELY (rflow == GST_FLOW_OK)) { /* flush any packet we had waiting */ rflow = gst_kate_enc_flush_waiting (ke, GST_BUFFER_TIMESTAMP (buf)); if (G_LIKELY (rflow == GST_FLOW_OK)) { if (!strcmp (mime_type, GST_KATE_SPU_MIME_TYPE)) { /* encode a kate_bitmap */ rflow = gst_kate_enc_chain_spu (ke, buf); } else { /* encode text */ rflow = gst_kate_enc_chain_text (ke, buf, mime_type); } } } } else { GST_WARNING_OBJECT (ke, "Packet has no MIME type, ignored"); } } gst_buffer_unref (buf); gst_object_unref (ke); GST_LOG_OBJECT (ke, "Leaving chain function"); return rflow; }
static gboolean gst_kate_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstKateEnc *ke = GST_KATE_ENC (parent); const GstStructure *structure; gboolean ret; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); ret = gst_kate_enc_setcaps (ke, caps); gst_event_unref (event); break; } case GST_EVENT_SEGMENT:{ GstSegment seg; GST_LOG_OBJECT (ke, "Got newsegment event"); gst_event_copy_segment (event, &seg); if (!ke->headers_sent) { if (ke->pending_segment) gst_event_unref (ke->pending_segment); ke->pending_segment = event; event = NULL; } if (ke->initialized) { GST_LOG_OBJECT (ke, "ensuring all headers are in"); if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) { GST_WARNING_OBJECT (ke, "Failed to flush headers"); } else { if (seg.format != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (seg.start)) { GST_WARNING_OBJECT (ke, "No time in newsegment event %p, format %d, timestamp %" G_GINT64_FORMAT, event, (int) seg.format, seg.start); /* to be safe, we'd need to generate a keepalive anyway, but we'd have to guess at the timestamp to use; a good guess would be the last known timestamp plus the keepalive time, but if we then get a packet with a timestamp less than this, it would fail to encode, which would be Bad. If we don't encode a keepalive, we run the risk of stalling the pipeline and hanging, which is Very Bad. Oh dear. We can't exit(-1), can we ? */ } else { float t = seg.start / (double) GST_SECOND; if (ke->delayed_spu && t - ke->delayed_start / (double) GST_SECOND >= ke->default_spu_duration) { if (G_UNLIKELY (gst_kate_enc_flush_waiting (ke, seg.start) != GST_FLOW_OK)) { GST_WARNING_OBJECT (ke, "Failed to encode delayed packet"); /* continue with new segment handling anyway */ } } GST_LOG_OBJECT (ke, "ts %f, last %f (min %f)", t, ke->last_timestamp / (double) GST_SECOND, ke->keepalive_min_time); if (ke->keepalive_min_time > 0.0f && t - ke->last_timestamp / (double) GST_SECOND >= ke->keepalive_min_time) { /* we only generate a keepalive if there is no SPU waiting, as it would mean out of sequence start times - and granulepos */ if (!ke->delayed_spu) { gst_kate_enc_generate_keepalive (ke, seg.start); } } } } } if (event) ret = gst_pad_push_event (ke->srcpad, event); else ret = TRUE; break; } case GST_EVENT_CUSTOM_DOWNSTREAM: GST_LOG_OBJECT (ke, "Got custom downstream event"); /* adapted from the dvdsubdec element */ structure = gst_event_get_structure (event); if (structure != NULL && gst_structure_has_name (structure, "application/x-gst-dvd")) { if (ke->initialized) { GST_LOG_OBJECT (ke, "ensuring all headers are in"); if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) { GST_WARNING_OBJECT (ke, "Failed to flush headers"); } else { const gchar *event_name = gst_structure_get_string (structure, "event"); if (event_name) { if (!strcmp (event_name, "dvd-spu-clut-change")) { gchar name[16]; int idx; gboolean found; gint value; GST_INFO_OBJECT (ke, "New CLUT received"); for (idx = 0; idx < 16; ++idx) { g_snprintf (name, sizeof (name), "clut%02d", idx); found = gst_structure_get_int (structure, name, &value); if (found) { ke->spu_clut[idx] = value; } else { GST_WARNING_OBJECT (ke, "DVD CLUT event did not contain %s field", name); } } } else if (!strcmp (event_name, "dvd-lang-codes")) { /* we can't know which stream corresponds to us */ } } else { GST_WARNING_OBJECT (ke, "custom downstream event with no name"); } } } } ret = gst_pad_push_event (ke->srcpad, event); break; case GST_EVENT_TAG: GST_LOG_OBJECT (ke, "Got tag event"); if (ke->tags) { GstTagList *list; gst_event_parse_tag (event, &list); gst_tag_list_insert (ke->tags, list, gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (ke))); } else { g_assert_not_reached (); } ret = gst_pad_event_default (pad, parent, event); break; case GST_EVENT_EOS: GST_INFO_OBJECT (ke, "Got EOS event"); if (ke->initialized) { GST_LOG_OBJECT (ke, "ensuring all headers are in"); if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) { GST_WARNING_OBJECT (ke, "Failed to flush headers"); } else { kate_packet kp; int ret; GstClockTime delayed_end = ke->delayed_start + ke->default_spu_duration * GST_SECOND; if (G_UNLIKELY (gst_kate_enc_flush_waiting (ke, delayed_end) != GST_FLOW_OK)) { GST_WARNING_OBJECT (ke, "Failed to encode delayed packet"); /* continue with EOS handling anyway */ } ret = kate_encode_finish (&ke->k, -1, &kp); if (ret < 0) { GST_WARNING_OBJECT (ke, "Failed to encode EOS packet: %s", gst_kate_util_get_error_message (ret)); } else { kate_int64_t granpos = kate_encode_get_granule (&ke->k); GST_LOG_OBJECT (ke, "EOS packet encoded"); if (gst_kate_enc_push_and_free_kate_packet (ke, &kp, granpos, ke->latest_end_time, 0, FALSE)) { GST_WARNING_OBJECT (ke, "Failed to push EOS packet"); } } } } ret = gst_pad_event_default (pad, parent, event); break; default: GST_LOG_OBJECT (ke, "Got unhandled event"); ret = gst_pad_event_default (pad, parent, event); break; } return ret; }