static void gst_rtp_qcelp_depay_init (GstRtpQCELPDepay * rtpqcelpdepay, GstRtpQCELPDepayClass * klass) { GstBaseRTPDepayload *depayload; depayload = GST_BASE_RTP_DEPAYLOAD (rtpqcelpdepay); }
static gboolean gst_base_rtp_depayload_setcaps (GstPad * pad, GstCaps * caps) { GstBaseRTPDepayload *filter; GstBaseRTPDepayloadClass *bclass; GstBaseRTPDepayloadPrivate *priv; gboolean res; GstStructure *caps_struct; const GValue *value; filter = GST_BASE_RTP_DEPAYLOAD (gst_pad_get_parent (pad)); priv = filter->priv; bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter); GST_DEBUG_OBJECT (filter, "Set caps"); caps_struct = gst_caps_get_structure (caps, 0); /* get other values for newsegment */ value = gst_structure_get_value (caps_struct, "npt-start"); if (value && G_VALUE_HOLDS_UINT64 (value)) priv->npt_start = g_value_get_uint64 (value); else priv->npt_start = 0; GST_DEBUG_OBJECT (filter, "NPT start %" G_GUINT64_FORMAT, priv->npt_start); value = gst_structure_get_value (caps_struct, "npt-stop"); if (value && G_VALUE_HOLDS_UINT64 (value)) priv->npt_stop = g_value_get_uint64 (value); else priv->npt_stop = -1; GST_DEBUG_OBJECT (filter, "NPT stop %" G_GUINT64_FORMAT, priv->npt_stop); value = gst_structure_get_value (caps_struct, "play-speed"); if (value && G_VALUE_HOLDS_DOUBLE (value)) priv->play_speed = g_value_get_double (value); else priv->play_speed = 1.0; value = gst_structure_get_value (caps_struct, "play-scale"); if (value && G_VALUE_HOLDS_DOUBLE (value)) priv->play_scale = g_value_get_double (value); else priv->play_scale = 1.0; if (bclass->set_caps) res = bclass->set_caps (filter, caps); else res = TRUE; priv->negotiated = res; gst_object_unref (filter); return res; }
static void gst_base_rtp_depayload_finalize (GObject * object) { GstBaseRTPDepayload *filter = GST_BASE_RTP_DEPAYLOAD (object); g_queue_free (filter->queue); G_OBJECT_CLASS (parent_class)->finalize (object); }
static void gst_rtp_amr_depay_init (GstRtpAMRDepay * rtpamrdepay, GstRtpAMRDepayClass * klass) { GstBaseRTPDepayload *depayload; depayload = GST_BASE_RTP_DEPAYLOAD (rtpamrdepay); gst_pad_use_fixed_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload)); }
static void gst_dtmf_src_generate_tone (GstRtpDTMFDepay * rtpdtmfdepay, GstRTPDTMFPayload payload, GstBuffer * buffer) { gint16 *p; gint tone_size; double i = 0; double amplitude, f1, f2; double volume_factor; DTMF_KEY key = DTMF_KEYS[payload.event]; guint32 clock_rate = 8000 /* default */ ; GstBaseRTPDepayload *depayload = GST_BASE_RTP_DEPAYLOAD (rtpdtmfdepay); gint volume; clock_rate = depayload->clock_rate; /* Create a buffer for the tone */ tone_size = (payload.duration * SAMPLE_SIZE * CHANNELS) / 8; GST_BUFFER_SIZE (buffer) = tone_size; GST_BUFFER_MALLOCDATA (buffer) = g_malloc (tone_size); GST_BUFFER_DATA (buffer) = GST_BUFFER_MALLOCDATA (buffer); GST_BUFFER_DURATION (buffer) = payload.duration * GST_SECOND / clock_rate; volume = payload.volume; p = (gint16 *) GST_BUFFER_MALLOCDATA (buffer); volume_factor = pow (10, (-volume) / 20); /* * For each sample point we calculate 'x' as the * the amplitude value. */ for (i = 0; i < (tone_size / (SAMPLE_SIZE / 8)); i++) { /* * We add the fundamental frequencies together. */ f1 = sin (2 * M_PI * key.low_frequency * (rtpdtmfdepay->sample / clock_rate)); f2 = sin (2 * M_PI * key.high_frequency * (rtpdtmfdepay->sample / clock_rate)); amplitude = (f1 + f2) / 2; /* Adjust the volume */ amplitude *= volume_factor; /* Make the [-1:1] interval into a [-32767:32767] interval */ amplitude *= 32767; /* Store it in the data buffer */ *(p++) = (gint16) amplitude; (rtpdtmfdepay->sample)++; } }
static void gst_rtp_ilbc_depay_init (GstRTPiLBCDepay * rtpilbcdepay, GstRTPiLBCDepayClass * klass) { GstBaseRTPDepayload *depayload; depayload = GST_BASE_RTP_DEPAYLOAD (rtpilbcdepay); /* Set default mode */ rtpilbcdepay->mode = DEFAULT_MODE; }
static void gst_base_rtp_depayload_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstBaseRTPDepayload *filter; filter = GST_BASE_RTP_DEPAYLOAD (object); switch (prop_id) { case PROP_QUEUE_DELAY: g_value_set_uint (value, filter->queue_delay); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static GstStateChangeReturn gst_base_rtp_depayload_change_state (GstElement * element, GstStateChange transition) { GstBaseRTPDepayload *filter; GstBaseRTPDepayloadPrivate *priv; GstStateChangeReturn ret; filter = GST_BASE_RTP_DEPAYLOAD (element); priv = filter->priv; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: filter->need_newsegment = TRUE; priv->npt_start = 0; priv->npt_stop = -1; priv->play_speed = 1.0; priv->play_scale = 1.0; priv->next_seqnum = -1; priv->negotiated = FALSE; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: break; case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } return ret; }
static void flush_packets (GstRtpQCELPDepay * depay) { guint i, size; GST_DEBUG_OBJECT (depay, "flushing packets"); size = depay->packets->len; for (i = 0; i < size; i++) { GstBuffer *outbuf; outbuf = g_ptr_array_index (depay->packets, i); g_ptr_array_index (depay->packets, i) = NULL; gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (depay), outbuf); } /* and reset interleaving state */ depay->interleaved = FALSE; depay->bundling = 0; }
static gboolean gst_base_rtp_depayload_handle_sink_event (GstPad * pad, GstEvent * event) { GstBaseRTPDepayload *filter; gboolean res = TRUE; filter = GST_BASE_RTP_DEPAYLOAD (GST_OBJECT_PARENT (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_STOP: res = gst_pad_push_event (filter->srcpad, event); gst_segment_init (&filter->segment, GST_FORMAT_UNDEFINED); filter->need_newsegment = TRUE; filter->priv->next_seqnum = -1; break; case GST_EVENT_NEWSEGMENT: { gboolean update; gdouble rate; GstFormat fmt; gint64 start, stop, position; gst_event_parse_new_segment (event, &update, &rate, &fmt, &start, &stop, &position); gst_segment_set_newsegment (&filter->segment, update, rate, fmt, start, stop, position); /* don't pass the event downstream, we generate our own segment including * the NTP time and other things we receive in caps */ gst_event_unref (event); break; } case GST_EVENT_CUSTOM_DOWNSTREAM: { GstBaseRTPDepayloadClass *bclass; bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter); if (gst_event_has_name (event, "GstRTPPacketLost")) { /* we get this event from the jitterbuffer when it considers a packet as * being lost. We send it to our packet_lost vmethod. The default * implementation will make time progress by pushing out a NEWSEGMENT * update event. Subclasses can override and to one of the following: * - Adjust timestamp/duration to something more accurate before * calling the parent (default) packet_lost method. * - do some more advanced error concealing on the already received * (fragmented) packets. * - ignore the packet lost. */ if (bclass->packet_lost) res = bclass->packet_lost (filter, event); } gst_event_unref (event); break; } default: /* pass other events forward */ res = gst_pad_push_event (filter->srcpad, event); break; } return res; }
static GstFlowReturn gst_base_rtp_depayload_chain (GstPad * pad, GstBuffer * in) { GstBaseRTPDepayload *filter; GstBaseRTPDepayloadPrivate *priv; GstBaseRTPDepayloadClass *bclass; GstFlowReturn ret = GST_FLOW_OK; GstBuffer *out_buf; GstClockTime timestamp; guint16 seqnum; guint32 rtptime; gboolean reset_seq, discont; gint gap; filter = GST_BASE_RTP_DEPAYLOAD (GST_OBJECT_PARENT (pad)); priv = filter->priv; /* we must have a setcaps first */ if (G_UNLIKELY (!priv->negotiated)) goto not_negotiated; /* we must validate, it's possible that this element is plugged right after a * network receiver and we don't want to operate on invalid data */ if (G_UNLIKELY (!gst_rtp_buffer_validate (in))) goto invalid_buffer; priv->discont = GST_BUFFER_IS_DISCONT (in); timestamp = GST_BUFFER_TIMESTAMP (in); /* convert to running_time and save the timestamp, this is the timestamp * we put on outgoing buffers. */ timestamp = gst_segment_to_running_time (&filter->segment, GST_FORMAT_TIME, timestamp); priv->timestamp = timestamp; priv->duration = GST_BUFFER_DURATION (in); seqnum = gst_rtp_buffer_get_seq (in); rtptime = gst_rtp_buffer_get_timestamp (in); reset_seq = TRUE; discont = FALSE; GST_LOG_OBJECT (filter, "discont %d, seqnum %u, rtptime %u, timestamp %" GST_TIME_FORMAT, priv->discont, seqnum, rtptime, GST_TIME_ARGS (timestamp)); /* Check seqnum. This is a very simple check that makes sure that the seqnums * are striclty increasing, dropping anything that is out of the ordinary. We * can only do this when the next_seqnum is known. */ if (G_LIKELY (priv->next_seqnum != -1)) { gap = gst_rtp_buffer_compare_seqnum (seqnum, priv->next_seqnum); /* if we have no gap, all is fine */ if (G_UNLIKELY (gap != 0)) { GST_LOG_OBJECT (filter, "got packet %u, expected %u, gap %d", seqnum, priv->next_seqnum, gap); if (gap < 0) { /* seqnum > next_seqnum, we are missing some packets, this is always a * DISCONT. */ GST_LOG_OBJECT (filter, "%d missing packets", gap); discont = TRUE; } else { /* seqnum < next_seqnum, we have seen this packet before or the sender * could be restarted. If the packet is not too old, we throw it away as * a duplicate, otherwise we mark discont and continue. 100 misordered * packets is a good threshold. See also RFC 4737. */ if (gap < 100) goto dropping; GST_LOG_OBJECT (filter, "%d > 100, packet too old, sender likely restarted", gap); discont = TRUE; } } } priv->next_seqnum = (seqnum + 1) & 0xffff; if (G_UNLIKELY (discont && !priv->discont)) { GST_LOG_OBJECT (filter, "mark DISCONT on input buffer"); /* we detected a seqnum discont but the buffer was not flagged with a discont, * set the discont flag so that the subclass can throw away old data. */ priv->discont = TRUE; GST_BUFFER_FLAG_SET (in, GST_BUFFER_FLAG_DISCONT); } bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter); if (G_UNLIKELY (bclass->process == NULL)) goto no_process; /* let's send it out to processing */ out_buf = bclass->process (filter, in); if (out_buf) { /* we pass rtptime as backward compatibility, in reality, the incomming * buffer timestamp is always applied to the outgoing packet. */ ret = gst_base_rtp_depayload_push_ts (filter, rtptime, out_buf); } gst_buffer_unref (in); return ret; /* ERRORS */ not_negotiated: { /* this is not fatal but should be filtered earlier */ GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION, (NULL), ("Not RTP format was negotiated")); gst_buffer_unref (in); return GST_FLOW_NOT_NEGOTIATED; } invalid_buffer: { /* this is not fatal but should be filtered earlier */ GST_ELEMENT_WARNING (filter, STREAM, DECODE, (NULL), ("Received invalid RTP payload, dropping")); gst_buffer_unref (in); return GST_FLOW_OK; } dropping: { GST_WARNING_OBJECT (filter, "%d <= 100, dropping old packet", gap); gst_buffer_unref (in); return GST_FLOW_OK; } no_process: { /* this is not fatal but should be filtered earlier */ GST_ELEMENT_ERROR (filter, STREAM, NOT_IMPLEMENTED, (NULL), ("The subclass does not have a process method")); gst_buffer_unref (in); return GST_FLOW_ERROR; } }
static gboolean gst_rtp_celt_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) { GstStructure *structure; GstRtpCELTDepay *rtpceltdepay; gint clock_rate, nb_channels, frame_size; GstBuffer *buf; guint8 *data; const gchar *params; GstCaps *srccaps; gboolean res; rtpceltdepay = GST_RTP_CELT_DEPAY (depayload); structure = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (structure, "clock-rate", &clock_rate)) goto no_clockrate; depayload->clock_rate = clock_rate; if (!(params = gst_structure_get_string (structure, "encoding-params"))) nb_channels = 1; else { nb_channels = atoi (params); } if (!(params = gst_structure_get_string (structure, "frame-size"))) frame_size = 480; else { frame_size = atoi (params); } /* construct minimal header and comment packet for the decoder */ buf = gst_buffer_new_and_alloc (60); data = GST_BUFFER_DATA (buf); memcpy (data, "CELT ", 8); data += 8; memcpy (data, "1.1.12", 7); data += 20; GST_WRITE_UINT32_LE (data, 0x80000006); /* version */ data += 4; GST_WRITE_UINT32_LE (data, 56); /* header_size */ data += 4; GST_WRITE_UINT32_LE (data, clock_rate); /* rate */ data += 4; GST_WRITE_UINT32_LE (data, nb_channels); /* channels */ data += 4; GST_WRITE_UINT32_LE (data, frame_size); /* frame-size */ data += 4; GST_WRITE_UINT32_LE (data, -1); /* overlap */ data += 4; GST_WRITE_UINT32_LE (data, -1); /* bytes_per_packet */ data += 4; GST_WRITE_UINT32_LE (data, 0); /* extra headers */ srccaps = gst_caps_new_simple ("audio/x-celt", NULL); res = gst_pad_set_caps (depayload->srcpad, srccaps); gst_caps_unref (srccaps); gst_buffer_set_caps (buf, GST_PAD_CAPS (depayload->srcpad)); gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (rtpceltdepay), buf); buf = gst_buffer_new_and_alloc (sizeof (gst_rtp_celt_comment)); memcpy (GST_BUFFER_DATA (buf), gst_rtp_celt_comment, sizeof (gst_rtp_celt_comment)); gst_buffer_set_caps (buf, GST_PAD_CAPS (depayload->srcpad)); gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (rtpceltdepay), buf); return res; /* ERRORS */ no_clockrate: { GST_DEBUG_OBJECT (depayload, "no clock-rate specified"); return FALSE; } }