static GstEvent * add_ssrc_and_ref (GstEvent * event, guint32 ssrc) { /* Set the ssrc on the output caps */ switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; GstCaps *newcaps; GstStructure *s; gst_event_parse_caps (event, &caps); newcaps = gst_caps_copy (caps); s = gst_caps_get_structure (newcaps, 0); gst_structure_set (s, "ssrc", G_TYPE_UINT, ssrc, NULL); event = gst_event_new_caps (newcaps); gst_caps_unref (newcaps); break; } default: gst_event_ref (event); break; } return event; }
static void gst_type_find_element_emit_have_type (GstTypeFindElement * typefind, guint probability, GstCaps * caps) { GstEvent *event; /* Update caps field immediatly so that caps queries and properties can be * honored in all "have-type" signal handlers. */ GST_OBJECT_LOCK (typefind); if (typefind->caps) gst_caps_unref (typefind->caps); typefind->caps = gst_caps_ref (caps); GST_OBJECT_UNLOCK (typefind); /* Only store the caps event at this point. We give signal handlers * the chance to look at the caps before they are sent downstream. * They are only forwarded downstream later in the default signal * handler after all application signal handlers */ event = gst_event_new_caps (caps); gst_pad_store_sticky_event (typefind->src, event); gst_event_unref (event); g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, probability, caps); }
/* prepare the source pad for output */ static gboolean mpegpsdemux_prepare_srcpad (MpegPsMux * mux) { GstSegment segment; GValue val = { 0, }; GList *headers, *l; GstCaps *caps; caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2, "systemstream", G_TYPE_BOOLEAN, TRUE, NULL); headers = psmux_get_stream_headers (mux->psmux); g_value_init (&val, GST_TYPE_ARRAY); for (l = headers; l != NULL; l = l->next) { GValue buf_val = { 0, }; g_value_init (&buf_val, GST_TYPE_BUFFER); gst_value_take_buffer (&buf_val, GST_BUFFER (l->data)); l->data = NULL; gst_value_array_append_value (&val, &buf_val); g_value_unset (&buf_val); } gst_caps_set_value (caps, "streamheader", &val); g_value_unset (&val); g_list_free (headers); /* Set caps on src pad and push new segment */ gst_pad_push_event (mux->srcpad, gst_event_new_caps (caps)); gst_caps_unref (caps); gst_segment_init (&segment, GST_FORMAT_BYTES); gst_pad_push_event (mux->srcpad, gst_event_new_segment (&segment)); return TRUE; }
static gboolean gst_dvd_sub_parse_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstDvdSubParse *parse; gboolean ret; parse = GST_DVD_SUB_PARSE (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_unref (event); caps = gst_static_pad_template_get_caps (&src_template); gst_pad_push_event (parse->srcpad, gst_event_new_caps (caps)); gst_caps_unref (caps); ret = TRUE; break; } case GST_EVENT_FLUSH_STOP: gst_dvd_sub_parse_reset (parse); /* fall-through */ default: ret = gst_pad_event_default (pad, parent, event); break; } return ret; }
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); }
static gboolean gst_vtenc_negotiate_downstream (GstVTEnc * self, CMSampleBufferRef sbuf) { gboolean result; GstCaps *caps; GstStructure *s; if (self->caps_width == self->negotiated_width && self->caps_height == self->negotiated_height && self->caps_fps_n == self->negotiated_fps_n && self->caps_fps_d == self->negotiated_fps_d) { return TRUE; } caps = gst_pad_get_pad_template_caps (self->srcpad); caps = gst_caps_make_writable (caps); s = gst_caps_get_structure (caps, 0); gst_structure_set (s, "width", G_TYPE_INT, self->negotiated_width, "height", G_TYPE_INT, self->negotiated_height, "framerate", GST_TYPE_FRACTION, self->negotiated_fps_n, self->negotiated_fps_d, NULL); if (self->details->format_id == kVTFormatH264) { CMFormatDescriptionRef fmt; CFDictionaryRef atoms; CFStringRef avccKey; CFDataRef avcc; gpointer codec_data; gsize codec_data_size; GstBuffer *codec_data_buf; fmt = CMSampleBufferGetFormatDescription (sbuf); atoms = CMFormatDescriptionGetExtension (fmt, kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms); avccKey = CFStringCreateWithCString (NULL, "avcC", kCFStringEncodingUTF8); avcc = CFDictionaryGetValue (atoms, avccKey); CFRelease (avccKey); codec_data_size = CFDataGetLength (avcc); codec_data = g_malloc (codec_data_size); CFDataGetBytes (avcc, CFRangeMake (0, codec_data_size), codec_data); codec_data_buf = gst_buffer_new_wrapped (codec_data, codec_data_size); gst_structure_set (s, "codec_data", GST_TYPE_BUFFER, codec_data_buf, NULL); gst_buffer_unref (codec_data_buf); } result = gst_pad_push_event (self->srcpad, gst_event_new_caps (caps)); gst_caps_unref (caps); self->caps_width = self->negotiated_width; self->caps_height = self->negotiated_height; self->caps_fps_n = self->negotiated_fps_n; self->caps_fps_d = self->negotiated_fps_d; return result; }
static void gst_decklink_src_send_initial_events (GstDecklinkSrc * src) { GstSegment segment; GstEvent *event; guint group_id; guint32 audio_id, video_id; gchar stream_id[9]; /* stream-start */ audio_id = g_random_int (); video_id = g_random_int (); while (video_id == audio_id) video_id = g_random_int (); group_id = gst_util_group_id_next (); g_snprintf (stream_id, sizeof (stream_id), "%08x", audio_id); event = gst_event_new_stream_start (stream_id); gst_event_set_group_id (event, group_id); gst_pad_push_event (src->audiosrcpad, event); g_snprintf (stream_id, sizeof (stream_id), "%08x", video_id); event = gst_event_new_stream_start (stream_id); gst_event_set_group_id (event, group_id); gst_pad_push_event (src->videosrcpad, event); /* segment */ gst_segment_init (&segment, GST_FORMAT_TIME); event = gst_event_new_segment (&segment); gst_pad_push_event (src->videosrcpad, gst_event_ref (event)); gst_pad_push_event (src->audiosrcpad, event); /* caps */ gst_pad_push_event (src->audiosrcpad, gst_event_new_caps (gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "S16LE", "channels", G_TYPE_INT, 2, "rate", G_TYPE_INT, 48000, "layout", G_TYPE_STRING, "interleaved", NULL))); gst_pad_push_event (src->videosrcpad, gst_event_new_caps (gst_decklink_mode_get_caps (src->mode))); }
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); }
static void mpegts_demuxer_add_pad(MpegTSDemuxer *demuxer, GstPad *pad, GstCaps *caps) { GstEvent *caps_event = NULL; gst_pad_set_query_function (pad, mpegts_demuxer_src_query); gst_pad_set_event_function (pad, mpegts_demuxer_src_event); gst_pad_set_active(pad, TRUE); gst_pad_use_fixed_caps (pad); caps_event = gst_event_new_caps(caps); if (caps_event) gst_pad_push_event (pad, caps_event); gst_caps_unref (caps); gst_element_add_pad(GST_ELEMENT(demuxer), pad); }
static void gst_check_setup_events_textoverlay (GstPad * srcpad, GstElement * element, GstCaps * caps, GstFormat format, const gchar * stream_id) { GstSegment segment; gst_segment_init (&segment, format); fail_unless (gst_pad_push_event (srcpad, gst_event_new_stream_start (stream_id))); if (caps) fail_unless (gst_pad_push_event (srcpad, gst_event_new_caps (caps))); fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&segment))); }
static gboolean gst_app_sink_setcaps (GstBaseSink * sink, GstCaps * caps) { GstAppSink *appsink = GST_APP_SINK_CAST (sink); GstAppSinkPrivate *priv = appsink->priv; g_mutex_lock (priv->mutex); GST_DEBUG_OBJECT (appsink, "receiving CAPS"); g_queue_push_tail (priv->queue, gst_event_new_caps (caps)); gst_caps_replace (&priv->preroll_caps, caps); g_mutex_unlock (priv->mutex); return TRUE; }
static inline void _push_mandatory_events (GstAggregator * self) { GstAggregatorPrivate *priv = self->priv; if (g_atomic_int_get (&self->priv->send_stream_start)) { gchar s_id[32]; GST_INFO_OBJECT (self, "pushing stream start"); /* stream-start (FIXME: create id based on input ids) */ g_snprintf (s_id, sizeof (s_id), "agg-%08x", g_random_int ()); if (!gst_pad_push_event (self->srcpad, gst_event_new_stream_start (s_id))) { GST_WARNING_OBJECT (self->srcpad, "Sending stream start event failed"); } g_atomic_int_set (&self->priv->send_stream_start, FALSE); } if (self->priv->srccaps) { GST_INFO_OBJECT (self, "pushing caps: %" GST_PTR_FORMAT, self->priv->srccaps); if (!gst_pad_push_event (self->srcpad, gst_event_new_caps (self->priv->srccaps))) { GST_WARNING_OBJECT (self->srcpad, "Sending caps event failed"); } gst_caps_unref (self->priv->srccaps); self->priv->srccaps = NULL; } if (g_atomic_int_get (&self->priv->send_segment)) { if (!g_atomic_int_get (&self->priv->flush_seeking)) { GstEvent *segev = gst_event_new_segment (&self->segment); if (!self->priv->seqnum) self->priv->seqnum = gst_event_get_seqnum (segev); else gst_event_set_seqnum (segev, self->priv->seqnum); GST_DEBUG_OBJECT (self, "pushing segment %" GST_PTR_FORMAT, segev); gst_pad_push_event (self->srcpad, segev); g_atomic_int_set (&self->priv->send_segment, FALSE); } } if (priv->tags && priv->tags_changed) { gst_pad_push_event (self->srcpad, gst_event_new_tag (gst_tag_list_ref (priv->tags))); priv->tags_changed = FALSE; } }
static gboolean gst_vtdec_negotiate_downstream (GstVTDec * self) { gboolean result; GstCaps *caps; if (!gst_pad_check_reconfigure (self->srcpad)) return TRUE; caps = gst_video_info_to_caps (&self->vinfo); result = gst_pad_push_event (self->srcpad, gst_event_new_caps (caps)); gst_caps_unref (caps); return result; }
static void send_startup_events (void) { GstCaps *caps; fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("randomvalue"))); /* push caps */ caps = gst_caps_new_simple ("audio/x-test-custom", "channels", G_TYPE_INT, 2, "rate", G_TYPE_INT, 44100, NULL); fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_caps (caps))); }
static void send_startup_events (void) { GstCaps *caps; fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("randomvalue"))); /* push caps */ caps = gst_caps_new_simple ("video/x-test-custom", "width", G_TYPE_INT, TEST_VIDEO_WIDTH, "height", G_TYPE_INT, TEST_VIDEO_HEIGHT, "framerate", GST_TYPE_FRACTION, TEST_VIDEO_FPS_N, TEST_VIDEO_FPS_D, NULL); fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_caps (caps))); gst_caps_unref (caps); }
static void send_startup_events (void) { GstCaps *caps; fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("randomvalue"))); /* push caps */ caps = gst_caps_new_simple ("audio/x-raw", "rate", G_TYPE_INT, TEST_AUDIO_RATE, "channels", G_TYPE_INT, TEST_AUDIO_CHANNELS, "format", G_TYPE_STRING, "S16LE", "layout", G_TYPE_STRING, "interleaved", NULL); fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_caps (caps))); gst_caps_unref (caps); }
static gboolean gst_fluid_dec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res; GstFluidDec *fluiddec = GST_FLUID_DEC (parent); GST_DEBUG_OBJECT (pad, "%s event received", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, GST_AUDIO_NE (F32), "rate", G_TYPE_INT, FLUID_DEC_RATE, "channels", G_TYPE_INT, 2, "layout", G_TYPE_STRING, "interleaved", NULL); fluid_synth_set_sample_rate (fluiddec->synth, FLUID_DEC_RATE); res = gst_pad_push_event (fluiddec->srcpad, gst_event_new_caps (caps)); gst_caps_unref (caps); break; } case GST_EVENT_SEGMENT: gst_event_copy_segment (event, &fluiddec->segment); GST_DEBUG_OBJECT (fluiddec, "configured segment %" GST_SEGMENT_FORMAT, &fluiddec->segment); res = gst_pad_event_default (pad, parent, event); break; case GST_EVENT_FLUSH_STOP: gst_fluid_dec_reset (fluiddec); res = gst_pad_event_default (pad, parent, event); break; case GST_EVENT_EOS: /* FIXME, push last samples */ res = gst_pad_event_default (pad, parent, event); break; default: res = gst_pad_event_default (pad, parent, event); break; } return res; }
static gpointer push_buffer (gpointer user_data) { GstFlowReturn flow; GstCaps *caps; TestData *test_data = (TestData *) user_data; gst_pad_push_event (test_data->pad, gst_event_new_stream_start ("test")); caps = gst_caps_new_empty_simple ("foo/x-bar"); gst_pad_push_event (test_data->pad, gst_event_new_caps (caps)); gst_caps_unref (caps); flow = gst_pad_push (test_data->pad, test_data->buffer); fail_unless (flow == GST_FLOW_OK, "got flow %s instead of OK", gst_flow_get_name (flow)); return NULL; }
/** * @brief This function handles sink events. */ static gboolean gst_tensor_aggregator_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstTensorAggregator *self; self = GST_TENSOR_AGGREGATOR (parent); GST_DEBUG_OBJECT (self, "Received %s event: %" GST_PTR_FORMAT, GST_EVENT_TYPE_NAME (event), event); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *in_caps; GstCaps *out_caps; gst_event_parse_caps (event, &in_caps); silent_debug_caps (in_caps, "in-caps"); if (gst_tensor_aggregator_parse_caps (self, in_caps)) { out_caps = gst_tensor_caps_from_config (&self->out_config); silent_debug_caps (out_caps, "out-caps"); gst_pad_set_caps (self->srcpad, out_caps); gst_event_unref (event); event = gst_event_new_caps (out_caps); gst_caps_unref (out_caps); return gst_pad_push_event (self->srcpad, event); } break; } case GST_EVENT_FLUSH_STOP: gst_tensor_aggregator_reset (self); break; default: break; } return gst_pad_event_default (pad, parent, event); }
static gpointer push_abuffers (gpointer data) { GstSegment segment; GstPad *pad = data; gint i, j, k; GstClockTime timestamp = 0; GstAudioInfo info; GstCaps *caps; guint buf_size = 1000; if (audiodelay) g_usleep (2000); if (early_video) timestamp = 50 * GST_MSECOND; gst_pad_send_event (pad, gst_event_new_stream_start ("test")); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S8, buf_size, channels, NULL); caps = gst_audio_info_to_caps (&info); gst_pad_send_event (pad, gst_event_new_caps (caps)); gst_caps_unref (caps); gst_segment_init (&segment, GST_FORMAT_TIME); gst_pad_send_event (pad, gst_event_new_segment (&segment)); for (i = 0; i < n_abuffers; i++) { GstBuffer *buf = gst_buffer_new_and_alloc (channels * buf_size); if (per_channel) { GstMapInfo map; guint8 *in_data; gst_buffer_map (buf, &map, GST_MAP_WRITE); in_data = map.data; for (j = 0; j < buf_size; j++) { for (k = 0; k < channels; k++) { in_data[j * channels + k] = fill_value_per_channel[k]; } } gst_buffer_unmap (buf, &map); } else { gst_buffer_memset (buf, 0, fill_value, channels * buf_size); } GST_BUFFER_TIMESTAMP (buf) = timestamp; timestamp += 1 * GST_SECOND; if (audio_drift) timestamp += 50 * GST_MSECOND; else if (i == 4 && audio_nondiscont) timestamp += 30 * GST_MSECOND; GST_BUFFER_DURATION (buf) = timestamp - GST_BUFFER_TIMESTAMP (buf); fail_unless (gst_pad_chain (pad, buf) == GST_FLOW_OK); } gst_pad_send_event (pad, gst_event_new_eos ()); return NULL; }
static void src_task_loop (GstPad * pad) { GstDtlsEnc *self = GST_DTLS_ENC (GST_PAD_PARENT (pad)); GstFlowReturn ret; GstBuffer *buffer; gboolean check_connection_timeout = FALSE; GST_TRACE_OBJECT (self, "src loop: acquiring lock"); g_mutex_lock (&self->queue_lock); GST_TRACE_OBJECT (self, "src loop: acquired lock"); if (self->flushing) { GST_LOG_OBJECT (self, "src task loop entered on inactive pad"); GST_TRACE_OBJECT (self, "src loop: releasing lock"); g_mutex_unlock (&self->queue_lock); return; } while (g_queue_is_empty (&self->queue)) { GST_TRACE_OBJECT (self, "src loop: queue empty, waiting for add"); g_cond_wait (&self->queue_cond_add, &self->queue_lock); GST_TRACE_OBJECT (self, "src loop: add signaled"); if (self->flushing) { GST_LOG_OBJECT (self, "pad inactive, task returning"); GST_TRACE_OBJECT (self, "src loop: releasing lock"); g_mutex_unlock (&self->queue_lock); return; } } GST_TRACE_OBJECT (self, "src loop: queue has element"); buffer = g_queue_pop_head (&self->queue); g_mutex_unlock (&self->queue_lock); if (self->send_initial_events) { GstSegment segment; gchar s_id[32]; GstCaps *caps; self->send_initial_events = FALSE; g_snprintf (s_id, sizeof (s_id), "dtlsenc-%08x", g_random_int ()); gst_pad_push_event (self->src, gst_event_new_stream_start (s_id)); caps = gst_caps_new_empty_simple ("application/x-dtls"); gst_pad_push_event (self->src, gst_event_new_caps (caps)); gst_caps_unref (caps); gst_segment_init (&segment, GST_FORMAT_BYTES); gst_pad_push_event (self->src, gst_event_new_segment (&segment)); check_connection_timeout = TRUE; } GST_TRACE_OBJECT (self, "src loop: releasing lock"); ret = gst_pad_push (self->src, buffer); if (check_connection_timeout) gst_dtls_connection_check_timeout (self->connection); if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_WARNING_OBJECT (self, "failed to push buffer on src pad: %s", gst_flow_get_name (ret)); } }
static gboolean gst_raw_base_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps) { gboolean ret = FALSE; GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse); GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (parse); g_assert (klass->set_config_from_caps); g_assert (klass->get_caps_from_config); g_assert (klass->get_config_frame_size); GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (raw_base_parse); GST_DEBUG_OBJECT (parse, "getting config from new sink caps"); /* Convert the new sink caps to sink caps config. This also * readies the config. */ ret = klass->set_config_from_caps (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_SINKCAPS, caps); if (!ret) { GST_ERROR_OBJECT (raw_base_parse, "could not get config from sink caps"); goto done; } /* If the sink caps config is currently active, push caps downstream, * set the minimum frame size (to guarantee that input buffers hold * complete frames), and update the src_caps_set flag. If the sink * caps config isn't the currently active config, just exit, since in * that case, the caps will always be pushed downstream in handle_frame. */ if (gst_raw_base_parse_is_using_sink_caps (raw_base_parse)) { GstCaps *new_src_caps; gsize frame_size; GST_DEBUG_OBJECT (parse, "sink caps config is the current one; trying to push new caps downstream"); /* Convert back to caps. The caps may have changed, for example * audio/x-unaligned-raw may have been replaced with audio/x-raw. * (Also, this keeps the behavior in sync with that of the block * in handle_frame that pushes caps downstream if not done already.) */ if (!klass->get_caps_from_config (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT, &new_src_caps)) { GST_ERROR_OBJECT (raw_base_parse, "could not get src caps from current config"); goto done; } GST_DEBUG_OBJECT (raw_base_parse, "got new sink caps; updating src caps to %" GST_PTR_FORMAT, (gpointer) new_src_caps); frame_size = klass->get_config_frame_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT); gst_base_parse_set_min_frame_size (parse, frame_size); raw_base_parse->src_caps_set = TRUE; GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); /* Push caps outside of the lock */ gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (raw_base_parse), gst_event_new_caps (new_src_caps) ); gst_caps_unref (new_src_caps); } else { GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); } ret = TRUE; done: return ret; }
static void src_task_loop(GstPad *pad) { GstErDtlsEnc *self = GST_ER_DTLS_ENC(GST_PAD_PARENT(pad)); GstFlowReturn ret; GstPad *peer; gboolean peer_is_active; if (!gst_pad_is_active(pad)) { GST_LOG_OBJECT(self, "src task loop entered on inactive pad"); return; } GST_TRACE_OBJECT(self, "src loop: acquiring lock"); g_mutex_lock(&self->queue_lock); GST_TRACE_OBJECT(self, "src loop: acquired lock"); while (!self->queue->len) { GST_TRACE_OBJECT(self, "src loop: queue empty, waiting for add"); g_cond_wait(&self->queue_cond_add, &self->queue_lock); GST_TRACE_OBJECT(self, "src loop: add signaled"); if (!gst_pad_is_active(pad)) { GST_LOG_OBJECT(self, "pad inactive, task returning"); GST_TRACE_OBJECT(self, "src loop: releasing lock"); g_mutex_unlock(&self->queue_lock); return; } } GST_TRACE_OBJECT(self, "src loop: queue has element"); peer = gst_pad_get_peer(pad); peer_is_active = gst_pad_is_active(peer); gst_object_unref(peer); if (peer_is_active) { GstBuffer *buffer; gboolean start_connection_timeout = FALSE; if (self->send_initial_events) { GstSegment segment; gchar s_id[32]; GstCaps *caps; g_snprintf (s_id, sizeof (s_id), "erdtlsenc-%08x", g_random_int ()); gst_pad_push_event (self->src, gst_event_new_stream_start (s_id)); caps = gst_caps_new_empty_simple ("application/x-dtls"); gst_pad_push_event (self->src, gst_event_new_caps (caps)); gst_caps_unref (caps); gst_segment_init (&segment, GST_FORMAT_BYTES); gst_pad_push_event (self->src, gst_event_new_segment (&segment)); self->send_initial_events = FALSE; start_connection_timeout = TRUE; } buffer = g_ptr_array_remove_index(self->queue, 0); GST_TRACE_OBJECT(self, "src loop: releasing lock"); g_mutex_unlock(&self->queue_lock); ret = gst_pad_push(self->src, buffer); if (start_connection_timeout) er_dtls_connection_start_timeout (self->connection); if (G_UNLIKELY(ret != GST_FLOW_OK)) { GST_WARNING_OBJECT(self, "failed to push buffer on src pad: %s", gst_flow_get_name(ret)); } } else { g_warn_if_reached(); GST_TRACE_OBJECT(self, "src loop: releasing lock"); g_mutex_unlock(&self->queue_lock); } }
static GstFlowReturn gst_raw_base_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) { gsize in_size, out_size; guint frame_size; guint num_out_frames; gsize units_n, units_d; guint64 buffer_duration; GstFlowReturn flow_ret = GST_FLOW_OK; GstEvent *new_caps_event = NULL; GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (parse); GstRawBaseParseClass *klass = GST_RAW_BASE_PARSE_GET_CLASS (parse); g_assert (klass->is_config_ready); g_assert (klass->get_caps_from_config); g_assert (klass->get_config_frame_size); g_assert (klass->get_units_per_second); /* We never skip any bytes this way. Instead, subclass takes care * of skipping any overhead (necessary, since the way it needs to * be skipped is completely subclass specific). */ *skipsize = 0; /* The operations below access the current config. Protect * against race conditions by using the object lock. */ GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (raw_base_parse); /* If the source pad caps haven't been set yet, or need to be * set again, do so now, BEFORE any buffers are pushed out */ if (G_UNLIKELY (!raw_base_parse->src_caps_set)) { GstCaps *new_src_caps; if (G_UNLIKELY (!klass->is_config_ready (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT))) { /* The current configuration is not ready. No caps can be * generated out of it. * The most likely reason for this is that the sink caps config * is the current one and no valid sink caps have been pushed * by upstream. Report the problem and exit. */ if (gst_raw_base_parse_is_using_sink_caps (raw_base_parse)) { goto config_not_ready; } else { /* This should not be reached if the property config is active */ g_assert_not_reached (); } } GST_DEBUG_OBJECT (parse, "setting src caps since this has not been done yet"); /* Convert the current config to a caps structure to * inform downstream about the new format */ if (!klass->get_caps_from_config (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT, &new_src_caps)) { GST_ERROR_OBJECT (raw_base_parse, "could not get src caps from current config"); flow_ret = GST_FLOW_NOT_NEGOTIATED; goto error_locked; } new_caps_event = gst_event_new_caps (new_src_caps); gst_caps_unref (new_src_caps); raw_base_parse->src_caps_set = TRUE; } frame_size = klass->get_config_frame_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT); in_size = gst_buffer_get_size (frame->buffer); /* gst_base_parse_set_min_frame_size() is called when the current * configuration changes and the change affects the frame size. This * means that a buffer must contain at least as many bytes as indicated * by the frame size. If there are fewer inside an error occurred; * either something in the parser went wrong, or the min frame size * wasn't updated properly. */ g_assert (in_size >= frame_size); /* Determine how many complete frames would fit in the input buffer. * Then check if this amount exceeds the maximum number of frames * as indicated by the subclass. */ num_out_frames = (in_size / frame_size); if (klass->get_max_frames_per_buffer) { guint max_num_out_frames = klass->get_max_frames_per_buffer (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT); num_out_frames = MIN (num_out_frames, max_num_out_frames); } /* Ensure that the size of the buffers that get pushed downstream * is always an integer multiple of the frame size to prevent cases * where downstream gets buffers with incomplete frames. */ out_size = num_out_frames * frame_size; /* Set the overhead size to ensure that timestamping excludes these * extra overhead bytes. */ frame->overhead = klass->get_overhead_size ? klass->get_overhead_size (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT) : 0; g_assert (out_size >= (guint) (frame->overhead)); out_size -= frame->overhead; GST_LOG_OBJECT (raw_base_parse, "%" G_GSIZE_FORMAT " bytes input %" G_GSIZE_FORMAT " bytes output (%u frame(s)) %d bytes overhead", in_size, out_size, num_out_frames, frame->overhead); /* Calculate buffer duration */ klass->get_units_per_second (raw_base_parse, GST_FORMAT_BYTES, GST_RAW_BASE_PARSE_CONFIG_CURRENT, &units_n, &units_d); if (units_n == 0 || units_d == 0) buffer_duration = GST_CLOCK_TIME_NONE; else buffer_duration = gst_util_uint64_scale (out_size, GST_SECOND * units_d, units_n); if (klass->process) { GstBuffer *processed_data = NULL; if (!klass->process (raw_base_parse, GST_RAW_BASE_PARSE_CONFIG_CURRENT, frame->buffer, in_size, out_size, &processed_data)) goto process_error; frame->out_buffer = processed_data; } else { frame->out_buffer = NULL; } /* Set the duration of the output buffer, or if none exists, of * the input buffer. Do this after the process() call, since in * case out_buffer is set, the subclass has created a new buffer. * Instead of requiring subclasses to set the duration (which * anyway must always be buffer_duration), let's do it here. */ if (frame->out_buffer != NULL) GST_BUFFER_DURATION (frame->out_buffer) = buffer_duration; else GST_BUFFER_DURATION (frame->buffer) = buffer_duration; /* Access to the current config is not needed in subsequent * operations, so the lock can be released */ GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); /* If any new caps have to be pushed downstrean, do so * *before* the frame is finished */ if (G_UNLIKELY (new_caps_event != NULL)) { gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (raw_base_parse), new_caps_event); new_caps_event = NULL; } gst_base_parse_finish_frame (parse, frame, out_size + frame->overhead); return flow_ret; config_not_ready: GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); GST_ELEMENT_ERROR (parse, STREAM, FORMAT, ("sink caps config is the current config, and it is not ready -" "upstream may not have pushed a caps event yet"), (NULL)); flow_ret = GST_FLOW_ERROR; goto error_end; process_error: GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); GST_ELEMENT_ERROR (parse, STREAM, DECODE, ("could not process data"), (NULL)); flow_ret = GST_FLOW_ERROR; goto error_end; error_locked: GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (raw_base_parse); goto error_end; error_end: frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP; if (new_caps_event != NULL) gst_event_unref (new_caps_event); return flow_ret; }