static GstFlowReturn gst_dtls_enc_push (GstDtlsEnc * self, GstBuffer * buffer) { GstDtlsBase *base = GST_DTLS_BASE (self); GstEvent *segment_event, *caps_event; gchar *stream_id; stream_id = gst_pad_get_stream_id (base->srcpad); if (stream_id == NULL) { stream_id = gst_pad_get_stream_id (base->sinkpad); if (stream_id == NULL) { stream_id = gst_pad_create_stream_id (base->srcpad, GST_ELEMENT (base), NULL); } gst_pad_push_event (base->srcpad, gst_event_new_stream_start (stream_id)); } g_free (stream_id); caps_event = gst_pad_get_sticky_event (base->srcpad, GST_EVENT_CAPS, 0); if (caps_event == NULL) { GstCaps *caps = gst_caps_from_string ("application/x-dtls"); caps_event = gst_event_new_caps (caps); gst_caps_unref (caps); gst_pad_push_event (base->srcpad, caps_event); } else { gst_event_unref (caps_event); } segment_event = gst_pad_get_sticky_event (base->srcpad, GST_EVENT_SEGMENT, 0); if (segment_event == NULL) { GstSegment *segment = gst_segment_new (); gst_segment_init (segment, GST_FORMAT_BYTES); segment_event = gst_event_new_segment (segment); gst_segment_free (segment); gst_pad_push_event (base->srcpad, segment_event); } else { gst_event_unref (segment_event); } GST_OBJECT_LOCK (self); if (self->src_buffer && self->running_thread == g_thread_self ()) { g_assert (gst_buffer_get_size (buffer) != 181); gst_buffer_copy_into (buffer, self->src_buffer, GST_BUFFER_COPY_METADATA, 0, -1); } GST_OBJECT_UNLOCK (self); return gst_pad_push (base->srcpad, buffer); }
/* convert the PacketLost event from a jitterbuffer to a GAP event. * subclasses can override this. */ static gboolean gst_rtp_base_depayload_packet_lost (GstRTPBaseDepayload * filter, GstEvent * event) { GstClockTime timestamp, duration; GstEvent *sevent; const GstStructure *s; s = gst_event_get_structure (event); /* first start by parsing the timestamp and duration */ timestamp = -1; duration = -1; if (!gst_structure_get_clock_time (s, "timestamp", ×tamp) || !gst_structure_get_clock_time (s, "duration", &duration)) { GST_ERROR_OBJECT (filter, "Packet loss event without timestamp or duration"); return FALSE; } sevent = gst_pad_get_sticky_event (filter->srcpad, GST_EVENT_SEGMENT, 0); if (G_UNLIKELY (!sevent)) { /* Typically happens if lost event arrives before first buffer */ GST_DEBUG_OBJECT (filter, "Ignore packet loss because segment event missing"); return FALSE; } gst_event_unref (sevent); /* send GAP event */ sevent = gst_event_new_gap (timestamp, duration); return gst_pad_push_event (filter->srcpad, sevent); }
static gboolean prepare_src_pad (MpegTSBase * base, MpegTSParse2 * parse) { GstEvent *event; gchar *stream_id; GstCaps *caps; if (!parse->first) return TRUE; /* If there's no packet_size yet, we can't set caps yet */ if (G_UNLIKELY (base->packetizer->packet_size == 0)) return FALSE; stream_id = gst_pad_create_stream_id (parse->srcpad, GST_ELEMENT_CAST (base), "multi-program"); event = gst_pad_get_sticky_event (parse->parent.sinkpad, GST_EVENT_STREAM_START, 0); if (event) { if (gst_event_parse_group_id (event, &parse->group_id)) parse->have_group_id = TRUE; else parse->have_group_id = FALSE; gst_event_unref (event); } else if (!parse->have_group_id) { parse->have_group_id = TRUE; parse->group_id = gst_util_group_id_next (); } event = gst_event_new_stream_start (stream_id); if (parse->have_group_id) gst_event_set_group_id (event, parse->group_id); gst_pad_push_event (parse->srcpad, event); g_free (stream_id); caps = gst_caps_new_simple ("video/mpegts", "systemstream", G_TYPE_BOOLEAN, TRUE, "packetsize", G_TYPE_INT, base->packetizer->packet_size, NULL); gst_pad_set_caps (parse->srcpad, caps); gst_caps_unref (caps); /* If setting output timestamps, ensure that the output segment is TIME */ if (parse->set_timestamps == FALSE || base->segment.format == GST_FORMAT_TIME) gst_pad_push_event (parse->srcpad, gst_event_new_segment (&base->segment)); else { GstSegment seg; gst_segment_init (&seg, GST_FORMAT_TIME); GST_DEBUG_OBJECT (parse, "Generating time output segment %" GST_SEGMENT_FORMAT, &seg); gst_pad_push_event (parse->srcpad, gst_event_new_segment (&seg)); } parse->first = FALSE; return TRUE; }
void InbandTextTrackPrivateGStreamer::notifyTrackOfStreamChanged() { GRefPtr<GstEvent> event = adoptGRef(gst_pad_get_sticky_event(m_pad.get(), GST_EVENT_STREAM_START, 0)); if (!event) return; const gchar* streamId; gst_event_parse_stream_start(event.get(), &streamId); INFO_MEDIA_MESSAGE("Track %d got stream start for stream %s.", m_index, streamId); m_streamId = streamId; }
static void input_selector_check_eos (gint present) { GstEvent *eos; eos = gst_pad_get_sticky_event (output_pad, GST_EVENT_EOS, 0); if (present) { fail_unless (eos != NULL); gst_event_unref (eos); } else { fail_unless (eos == NULL); } }
static void gst_type_find_element_have_type (GstTypeFindElement * typefind, guint probability, GstCaps * caps) { GstEvent *event; g_assert (caps != NULL); GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", probability=%u", caps, probability); /* Do nothing if downstream is pulling from us */ if (GST_PAD_MODE (typefind->src) == GST_PAD_MODE_PULL) return; GST_OBJECT_LOCK (typefind); /* Now actually send the CAPS event downstream. * * Try to directly send the CAPS event downstream that we created in * gst_type_find_element_emit_have_type() if it is still there, instead * of creating a new one. No need to create an equivalent one, replacing * it in the sticky event list and possibly causing renegotiation */ event = gst_pad_get_sticky_event (typefind->src, GST_EVENT_CAPS, 0); if (event) { GstCaps *event_caps; gst_event_parse_caps (event, &event_caps); if (caps != event_caps) { gst_event_unref (event); event = gst_event_new_caps (caps); } } else { event = gst_event_new_caps (caps); } GST_OBJECT_UNLOCK (typefind); gst_pad_push_event (typefind->src, event); }
void InbandTextTrackPrivateGStreamer::notifyTrackOfTagsChanged() { m_tagTimerHandler = 0; if (!m_pad) return; String label; String language; GRefPtr<GstEvent> event; for (guint i = 0; (event = adoptGRef(gst_pad_get_sticky_event(m_pad.get(), GST_EVENT_TAG, i))); ++i) { GstTagList* tags = 0; gst_event_parse_tag(event.get(), &tags); ASSERT(tags); gchar* tagValue; if (gst_tag_list_get_string(tags, GST_TAG_TITLE, &tagValue)) { INFO_MEDIA_MESSAGE("Text track %d got title %s.", m_index, tagValue); label = tagValue; g_free(tagValue); } if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &tagValue)) { INFO_MEDIA_MESSAGE("Text track %d got language %s.", m_index, tagValue); language = tagValue; g_free(tagValue); } } if (m_label != label) { m_label = label; client()->labelChanged(this, m_label); } if (m_language != language) { m_language = language; client()->languageChanged(this, m_language); } }
static void gst_srtp_dec_push_early_events (GstSrtpDec * filter, GstPad * pad, GstPad * otherpad, gboolean is_rtcp) { GstEvent *otherev, *ev; ev = gst_pad_get_sticky_event (pad, GST_EVENT_STREAM_START, 0); if (ev) { gst_event_unref (ev); } else { gchar *new_stream_id; otherev = gst_pad_get_sticky_event (otherpad, GST_EVENT_STREAM_START, 0); if (otherev) { const gchar *other_stream_id; gst_event_parse_stream_start (otherev, &other_stream_id); new_stream_id = g_strdup_printf ("%s/%s", other_stream_id, is_rtcp ? "rtcp" : "rtp"); gst_event_unref (otherev); } else { new_stream_id = gst_pad_create_stream_id (pad, GST_ELEMENT (filter), is_rtcp ? "rtcp" : "rtp"); } ev = gst_event_new_stream_start (new_stream_id); g_free (new_stream_id); gst_pad_push_event (pad, ev); } ev = gst_pad_get_sticky_event (pad, GST_EVENT_CAPS, 0); if (ev) { gst_event_unref (ev); } else { GstCaps *caps; if (is_rtcp) caps = gst_caps_new_empty_simple ("application/x-rtcp"); else caps = gst_caps_new_empty_simple ("application/x-rtp"); gst_pad_set_caps (pad, caps); gst_caps_unref (caps); } ev = gst_pad_get_sticky_event (pad, GST_EVENT_SEGMENT, 0); if (ev) { gst_event_unref (ev); } else { ev = gst_pad_get_sticky_event (otherpad, GST_EVENT_SEGMENT, 0); if (ev) gst_pad_push_event (pad, ev); } if (is_rtcp) filter->rtcp_has_segment = TRUE; else filter->rtp_has_segment = TRUE; }
static GstMultipartPad * gst_multipart_find_pad_by_mime (GstMultipartDemux * demux, gchar * mime, gboolean * created) { GSList *walk; walk = demux->srcpads; while (walk) { GstMultipartPad *pad = (GstMultipartPad *) walk->data; if (!strcmp (pad->mime, mime)) { if (created) { *created = FALSE; } return pad; } walk = walk->next; } /* pad not found, create it */ { GstPad *pad; GstMultipartPad *mppad; gchar *name; const gchar *capsname; GstCaps *caps; gchar *stream_id; GstEvent *event; mppad = g_new0 (GstMultipartPad, 1); GST_DEBUG_OBJECT (demux, "creating pad with mime: %s", mime); name = g_strdup_printf ("src_%u", demux->numpads); pad = gst_pad_new_from_static_template (&multipart_demux_src_template_factory, name); g_free (name); mppad->pad = pad; mppad->mime = g_strdup (mime); mppad->last_ret = GST_FLOW_OK; mppad->last_ts = GST_CLOCK_TIME_NONE; mppad->discont = TRUE; demux->srcpads = g_slist_prepend (demux->srcpads, mppad); demux->numpads++; gst_pad_use_fixed_caps (pad); gst_pad_set_active (pad, TRUE); /* prepare and send stream-start */ if (!demux->have_group_id) { event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0); if (event) { demux->have_group_id = gst_event_parse_group_id (event, &demux->group_id); gst_event_unref (event); } else if (!demux->have_group_id) { demux->have_group_id = TRUE; demux->group_id = gst_util_group_id_next (); } } stream_id = gst_pad_create_stream_id (pad, GST_ELEMENT_CAST (demux), demux->mime_type); event = gst_event_new_stream_start (stream_id); if (demux->have_group_id) gst_event_set_group_id (event, demux->group_id); gst_pad_store_sticky_event (pad, event); g_free (stream_id); gst_event_unref (event); /* take the mime type, convert it to the caps name */ capsname = gst_multipart_demux_get_gstname (demux, mime); caps = gst_caps_from_string (capsname); GST_DEBUG_OBJECT (demux, "caps for pad: %s", capsname); gst_pad_set_caps (pad, caps); gst_element_add_pad (GST_ELEMENT_CAST (demux), pad); gst_caps_unref (caps); if (created) { *created = TRUE; } if (demux->singleStream) { gst_element_no_more_pads (GST_ELEMENT_CAST (demux)); } return mppad; } }
static GstFlowReturn gst_real_audio_demux_parse_header (GstRealAudioDemux * demux) { const guint8 *data; gchar *codec_name = NULL; GstCaps *caps = NULL; GstEvent *event; gchar *stream_id; guint avail; g_assert (demux->ra_version == 4 || demux->ra_version == 3); avail = gst_adapter_available (demux->adapter); if (avail < 16) return GST_FLOW_OK; if (!gst_real_audio_demux_get_data_offset_from_header (demux)) return GST_FLOW_ERROR; /* shouldn't happen */ GST_DEBUG_OBJECT (demux, "data_offset = %u", demux->data_offset); if (avail + 6 < demux->data_offset) { GST_DEBUG_OBJECT (demux, "Need %u bytes, but only %u available now", demux->data_offset - 6, avail); return GST_FLOW_OK; } data = gst_adapter_map (demux->adapter, demux->data_offset - 6); g_assert (data); switch (demux->ra_version) { case 3: demux->fourcc = GST_RM_AUD_14_4; demux->packet_size = 20; demux->sample_rate = 8000; demux->channels = 1; demux->sample_width = 16; demux->flavour = 1; demux->leaf_size = 0; demux->height = 0; break; case 4: demux->flavour = GST_READ_UINT16_BE (data + 16); /* demux->frame_size = GST_READ_UINT32_BE (data + 36); */ demux->leaf_size = GST_READ_UINT16_BE (data + 38); demux->height = GST_READ_UINT16_BE (data + 34); demux->packet_size = GST_READ_UINT32_BE (data + 18); demux->sample_rate = GST_READ_UINT16_BE (data + 42); demux->sample_width = GST_READ_UINT16_BE (data + 46); demux->channels = GST_READ_UINT16_BE (data + 48); demux->fourcc = GST_READ_UINT32_LE (data + 56); demux->pending_tags = gst_rm_utils_read_tags (data + 63, demux->data_offset - 63, gst_rm_utils_read_string8); if (demux->pending_tags) gst_tag_list_set_scope (demux->pending_tags, GST_TAG_SCOPE_GLOBAL); break; default: g_assert_not_reached (); #if 0 case 5: demux->flavour = GST_READ_UINT16_BE (data + 16); /* demux->frame_size = GST_READ_UINT32_BE (data + 36); */ demux->leaf_size = GST_READ_UINT16_BE (data + 38); demux->height = GST_READ_UINT16_BE (data + 34); demux->sample_rate = GST_READ_UINT16_BE (data + 48); demux->sample_width = GST_READ_UINT16_BE (data + 52); demux->n_channels = GST_READ_UINT16_BE (data + 54); demux->fourcc = RMDEMUX_FOURCC_GET (data + 60); break; #endif } GST_INFO_OBJECT (demux, "packet_size = %u", demux->packet_size); GST_INFO_OBJECT (demux, "sample_rate = %u", demux->sample_rate); GST_INFO_OBJECT (demux, "sample_width = %u", demux->sample_width); GST_INFO_OBJECT (demux, "channels = %u", demux->channels); GST_INFO_OBJECT (demux, "fourcc = '%" GST_FOURCC_FORMAT "' (%08X)", GST_FOURCC_ARGS (demux->fourcc), demux->fourcc); switch (demux->fourcc) { case GST_RM_AUD_14_4: caps = gst_caps_new_simple ("audio/x-pn-realaudio", "raversion", G_TYPE_INT, 1, NULL); demux->byterate_num = 1000; demux->byterate_denom = 1; break; case GST_RM_AUD_28_8: /* FIXME: needs descrambling */ caps = gst_caps_new_simple ("audio/x-pn-realaudio", "raversion", G_TYPE_INT, 2, NULL); break; case GST_RM_AUD_DNET: caps = gst_caps_new_simple ("audio/x-ac3", "rate", G_TYPE_INT, demux->sample_rate, NULL); if (demux->packet_size == 0 || demux->sample_rate == 0) goto broken_file; demux->byterate_num = demux->packet_size * demux->sample_rate; demux->byterate_denom = 1536; break; /* Sipro/ACELP.NET Voice Codec (MIME unknown) */ case GST_RM_AUD_SIPR: caps = gst_caps_new_empty_simple ("audio/x-sipro"); break; default: GST_WARNING_OBJECT (demux, "unknown fourcc %08X", demux->fourcc); break; } if (caps == NULL) goto unknown_fourcc; gst_caps_set_simple (caps, "flavor", G_TYPE_INT, demux->flavour, "rate", G_TYPE_INT, demux->sample_rate, "channels", G_TYPE_INT, demux->channels, "width", G_TYPE_INT, demux->sample_width, "leaf_size", G_TYPE_INT, demux->leaf_size, "packet_size", G_TYPE_INT, demux->packet_size, "height", G_TYPE_INT, demux->height, NULL); GST_INFO_OBJECT (demux, "Adding source pad, caps %" GST_PTR_FORMAT, caps); demux->srcpad = gst_pad_new_from_static_template (&src_template, "src"); gst_pad_set_event_function (demux->srcpad, GST_DEBUG_FUNCPTR (gst_real_audio_demux_src_event)); gst_pad_set_query_function (demux->srcpad, GST_DEBUG_FUNCPTR (gst_real_audio_demux_src_query)); gst_pad_set_active (demux->srcpad, TRUE); gst_pad_use_fixed_caps (demux->srcpad); stream_id = gst_pad_create_stream_id (demux->srcpad, GST_ELEMENT_CAST (demux), NULL); event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0); if (event) { if (gst_event_parse_group_id (event, &demux->group_id)) demux->have_group_id = TRUE; else demux->have_group_id = FALSE; gst_event_unref (event); } else if (!demux->have_group_id) { demux->have_group_id = TRUE; demux->group_id = gst_util_group_id_next (); } event = gst_event_new_stream_start (stream_id); if (demux->have_group_id) gst_event_set_group_id (event, demux->group_id); gst_pad_push_event (demux->srcpad, event); g_free (stream_id); gst_pad_set_caps (demux->srcpad, caps); codec_name = gst_pb_utils_get_codec_description (caps); gst_caps_unref (caps); gst_element_add_pad (GST_ELEMENT (demux), demux->srcpad); if (demux->byterate_num > 0 && demux->byterate_denom > 0) { GstFormat bformat = GST_FORMAT_BYTES; gint64 size_bytes = 0; GST_INFO_OBJECT (demux, "byte rate = %u/%u = %u bytes/sec", demux->byterate_num, demux->byterate_denom, demux->byterate_num / demux->byterate_denom); if (gst_pad_peer_query_duration (demux->sinkpad, bformat, &size_bytes)) { demux->duration = gst_real_demux_get_timestamp_from_offset (demux, size_bytes); demux->upstream_size = size_bytes; GST_INFO_OBJECT (demux, "upstream_size = %" G_GUINT64_FORMAT, demux->upstream_size); GST_INFO_OBJECT (demux, "duration = %" GST_TIME_FORMAT, GST_TIME_ARGS (demux->duration)); } } demux->need_newsegment = TRUE; if (codec_name) { if (demux->pending_tags == NULL) { demux->pending_tags = gst_tag_list_new_empty (); gst_tag_list_set_scope (demux->pending_tags, GST_TAG_SCOPE_GLOBAL); } gst_tag_list_add (demux->pending_tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, codec_name, NULL); g_free (codec_name); } gst_adapter_unmap (demux->adapter); gst_adapter_flush (demux->adapter, demux->data_offset - 6); demux->state = REAL_AUDIO_DEMUX_STATE_DATA; demux->need_newsegment = TRUE; return GST_FLOW_OK; /* ERRORS */ unknown_fourcc: { GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE, (NULL), ("Unknown fourcc '%" GST_FOURCC_FORMAT "'", GST_FOURCC_ARGS (demux->fourcc))); return GST_FLOW_ERROR; } broken_file: { GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE, (NULL), ("Broken file - invalid sample_rate or other header value")); return GST_FLOW_ERROR; } }
static void _audiodecoder_flush_events (gboolean send_buffers) { GstSegment segment; GstBuffer *buffer; guint64 i; GList *events_iter; GstMessage *msg; setup_audiodecodertester (); gst_pad_set_active (mysrcpad, TRUE); gst_element_set_state (dec, GST_STATE_PLAYING); gst_pad_set_active (mysinkpad, TRUE); send_startup_events (); /* push a new segment */ gst_segment_init (&segment, GST_FORMAT_TIME); fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment))); if (send_buffers) { /* push buffers, the data is actually a number so we can track them */ for (i = 0; i < NUM_BUFFERS; i++) { if (i % 10 == 0) { GstTagList *tags; tags = gst_tag_list_new (GST_TAG_TRACK_NUMBER, i, NULL); fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_tag (tags))); } else { buffer = create_test_buffer (i); fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK); } } } else { /* push sticky event */ GstTagList *tags; tags = gst_tag_list_new (GST_TAG_TRACK_NUMBER, 0, NULL); fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_tag (tags))); } msg = gst_message_new_element (GST_OBJECT (mysrcpad), gst_structure_new_empty ("test")); fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_sink_message ("test", msg))); gst_message_unref (msg); fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ())); events_iter = events; /* make sure the usual events have been received */ { GstEvent *sstart = events_iter->data; fail_unless (GST_EVENT_TYPE (sstart) == GST_EVENT_STREAM_START); events_iter = g_list_next (events_iter); } if (send_buffers) { { GstEvent *caps_event = events_iter->data; fail_unless (GST_EVENT_TYPE (caps_event) == GST_EVENT_CAPS); events_iter = g_list_next (events_iter); } { GstEvent *segment_event = events_iter->data; fail_unless (GST_EVENT_TYPE (segment_event) == GST_EVENT_SEGMENT); events_iter = g_list_next (events_iter); } for (int i=0; i< NUM_BUFFERS / 10; i++) { GstEvent *tag_event = events_iter->data; fail_unless (GST_EVENT_TYPE (tag_event) == GST_EVENT_TAG); events_iter = g_list_next (events_iter); } } { GstEvent *eos_event = events_iter->data; fail_unless (GST_EVENT_TYPE (eos_event) == GST_EVENT_EOS); events_iter = g_list_next (events_iter); } /* check that EOS was received */ fail_unless (GST_PAD_IS_EOS (mysrcpad)); fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_flush_start ())); fail_unless (GST_PAD_IS_EOS (mysrcpad)); /* Check that we have tags */ { GstEvent *tags = gst_pad_get_sticky_event (mysrcpad, GST_EVENT_TAG, 0); fail_unless (tags != NULL); gst_event_unref (tags); } /* Check that we still have a segment set */ { GstEvent *segment = gst_pad_get_sticky_event (mysrcpad, GST_EVENT_SEGMENT, 0); fail_unless (segment != NULL); gst_event_unref (segment); } fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_flush_stop (TRUE))); fail_if (GST_PAD_IS_EOS (mysrcpad)); /* Check that the segment was flushed on FLUSH_STOP */ { GstEvent *segment = gst_pad_get_sticky_event (mysrcpad, GST_EVENT_SEGMENT, 0); fail_unless (segment == NULL); } /* Check the tags were not lost on FLUSH_STOP */ { GstEvent *tags = gst_pad_get_sticky_event (mysrcpad, GST_EVENT_TAG, 0); fail_unless (tags != NULL); gst_event_unref (tags); } g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); buffers = NULL; gst_element_set_state (dec, GST_STATE_NULL); cleanup_audiodecodertest (); }
static GstFlowReturn gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; GstRtpPtDemux *rtpdemux; guint8 pt; GstPad *srcpad; GstCaps *caps; GstRTPBuffer rtp = { NULL }; rtpdemux = GST_RTP_PT_DEMUX (parent); if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp)) goto invalid_buffer; pt = gst_rtp_buffer_get_payload_type (&rtp); gst_rtp_buffer_unmap (&rtp); GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt); srcpad = find_pad_for_pt (rtpdemux, pt); if (srcpad == NULL) { /* new PT, create a src pad */ GstRtpPtDemuxPad *rtpdemuxpad; GstElementClass *klass; GstPadTemplate *templ; gchar *padname; caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt); if (!caps) goto no_caps; klass = GST_ELEMENT_GET_CLASS (rtpdemux); templ = gst_element_class_get_pad_template (klass, "src_%u"); padname = g_strdup_printf ("src_%u", pt); srcpad = gst_pad_new_from_template (templ, padname); gst_pad_use_fixed_caps (srcpad); g_free (padname); gst_pad_set_event_function (srcpad, gst_rtp_pt_demux_src_event); GST_DEBUG ("Adding pt=%d to the list.", pt); rtpdemuxpad = g_slice_new0 (GstRtpPtDemuxPad); rtpdemuxpad->pt = pt; rtpdemuxpad->newcaps = FALSE; rtpdemuxpad->pad = srcpad; gst_object_ref (srcpad); GST_OBJECT_LOCK (rtpdemux); rtpdemux->srcpads = g_slist_append (rtpdemux->srcpads, rtpdemuxpad); GST_OBJECT_UNLOCK (rtpdemux); gst_pad_set_active (srcpad, TRUE); /* First push the stream-start event, it must always come first */ gst_pad_push_event (srcpad, gst_pad_get_sticky_event (rtpdemux->sink, GST_EVENT_STREAM_START, 0)); /* Then caps event is sent */ caps = gst_caps_make_writable (caps); gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL); gst_pad_set_caps (srcpad, caps); gst_caps_unref (caps); /* First sticky events on sink pad are forwarded to the new src pad */ gst_pad_sticky_events_foreach (rtpdemux->sink, forward_sticky_events, srcpad); gst_element_add_pad (GST_ELEMENT_CAST (rtpdemux), srcpad); GST_DEBUG ("emitting new-payload-type for pt %d", pt); g_signal_emit (G_OBJECT (rtpdemux), gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad); } if (pt != rtpdemux->last_pt) { gint emit_pt = pt; /* our own signal with an extra flag that this is the only pad */ rtpdemux->last_pt = pt; GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt); g_signal_emit (G_OBJECT (rtpdemux), gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt); } while (need_caps_for_pt (rtpdemux, pt)) { GST_DEBUG ("need new caps for %d", pt); caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt); if (!caps) goto no_caps; clear_newcaps_for_pt (rtpdemux, pt); caps = gst_caps_make_writable (caps); gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL); gst_pad_set_caps (srcpad, caps); gst_caps_unref (caps); } /* push to srcpad */ ret = gst_pad_push (srcpad, buf); gst_object_unref (srcpad); return ret; /* ERRORS */ invalid_buffer: { /* this is fatal and should be filtered earlier */ GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL), ("Dropping invalid RTP payload")); gst_buffer_unref (buf); return GST_FLOW_ERROR; } no_caps: { GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL), ("Could not get caps for payload")); gst_buffer_unref (buf); if (srcpad) gst_object_unref (srcpad); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_cc_extractor_handle_meta (GstCCExtractor * filter, GstBuffer * buf, GstVideoCaptionMeta * meta) { GstBuffer *outbuf = NULL; GstEvent *event; gchar *captionid; GstFlowReturn flow; GST_DEBUG_OBJECT (filter, "Handling meta"); /* Check if the meta type matches the configured one */ if (filter->captionpad != NULL && meta->caption_type != filter->caption_type) { GST_ERROR_OBJECT (filter, "GstVideoCaptionMeta type changed, Not handled currently"); flow = GST_FLOW_NOT_NEGOTIATED; goto out; } if (filter->captionpad == NULL) { GstCaps *caption_caps = NULL; GstEvent *stream_event; GST_DEBUG_OBJECT (filter, "Creating new caption pad"); switch (meta->caption_type) { case GST_VIDEO_CAPTION_TYPE_CEA608_RAW: caption_caps = gst_caps_from_string ("closedcaption/x-cea-608,format=(string)raw"); break; case GST_VIDEO_CAPTION_TYPE_CEA608_IN_CEA708_RAW: caption_caps = gst_caps_from_string ("closedcaption/x-cea-608,format=(string)cc_data"); break; case GST_VIDEO_CAPTION_TYPE_CEA708_RAW: caption_caps = gst_caps_from_string ("closedcaption/x-cea-708,format=(string)cc_data"); break; case GST_VIDEO_CAPTION_TYPE_CEA708_CDP: caption_caps = gst_caps_from_string ("closedcaption/x-cea-708,format=(string)cdp"); break; default: break; } if (caption_caps == NULL) { GST_ERROR_OBJECT (filter, "Unknown/invalid caption type"); return GST_FLOW_NOT_NEGOTIATED; } /* Create the caption pad and set the caps */ filter->captionpad = gst_pad_new_from_static_template (&captiontemplate, "caption"); gst_pad_set_iterate_internal_links_function (filter->sinkpad, GST_DEBUG_FUNCPTR (gst_cc_extractor_iterate_internal_links)); gst_pad_set_active (filter->captionpad, TRUE); gst_element_add_pad (GST_ELEMENT (filter), filter->captionpad); gst_flow_combiner_add_pad (filter->combiner, filter->captionpad); captionid = gst_pad_create_stream_id (filter->captionpad, (GstElement *) filter, "caption"); stream_event = gst_event_new_stream_start (captionid); g_free (captionid); /* FIXME : Create a proper stream-id */ if ((event = gst_pad_get_sticky_event (filter->srcpad, GST_EVENT_STREAM_START, 0))) { guint group_id; if (gst_event_parse_group_id (event, &group_id)) gst_event_set_group_id (stream_event, group_id); gst_event_unref (event); } gst_pad_push_event (filter->captionpad, stream_event); gst_pad_set_caps (filter->captionpad, caption_caps); gst_caps_unref (caption_caps); /* Carry over sticky events */ if ((event = gst_pad_get_sticky_event (filter->srcpad, GST_EVENT_SEGMENT, 0))) gst_pad_push_event (filter->captionpad, event); if ((event = gst_pad_get_sticky_event (filter->srcpad, GST_EVENT_TAG, 0))) gst_pad_push_event (filter->captionpad, event); filter->caption_type = meta->caption_type; } GST_DEBUG_OBJECT (filter, "Creating new buffer of size %" G_GSIZE_FORMAT " bytes", meta->size); /* Extract caption data into new buffer with identical buffer timestamps */ outbuf = gst_buffer_new_allocate (NULL, meta->size, NULL); gst_buffer_fill (outbuf, 0, meta->data, meta->size); GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf); GST_BUFFER_DTS (outbuf) = GST_BUFFER_DTS (buf); GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf); /* We don't really care about the flow return */ flow = gst_pad_push (filter->captionpad, outbuf); out: /* Set flow return on pad and return combined value */ return gst_flow_combiner_update_pad_flow (filter->combiner, filter->captionpad, flow); }