static void gst_rtp_speex_pay_init (GstRtpSPEEXPay * rtpspeexpay, GstRtpSPEEXPayClass * klass) { GST_BASE_RTP_PAYLOAD (rtpspeexpay)->clock_rate = 8000; GST_BASE_RTP_PAYLOAD_PT (rtpspeexpay) = 110; /* Create String */ }
static void gst_rtp_mpv_pay_init (GstRTPMPVPay * rtpmpvpay, GstRTPMPVPayClass * klass) { GST_BASE_RTP_PAYLOAD (rtpmpvpay)->clock_rate = 90000; GST_BASE_RTP_PAYLOAD_PT (rtpmpvpay) = GST_RTP_PAYLOAD_MPV; rtpmpvpay->adapter = gst_adapter_new (); }
static GstFlowReturn gst_rtp_sbc_pay_flush_buffers(GstRtpSBCPay *sbcpay) { guint available; guint max_payload; GstBuffer *outbuf; guint8 *payload_data; guint frame_count; guint payload_length; struct rtp_payload *payload; if (sbcpay->frame_length == 0) { GST_ERROR_OBJECT(sbcpay, "Frame length is 0"); return GST_FLOW_ERROR; } available = gst_adapter_available(sbcpay->adapter); max_payload = gst_rtp_buffer_calc_payload_len( GST_BASE_RTP_PAYLOAD_MTU(sbcpay) - RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0); max_payload = MIN(max_payload, available); frame_count = max_payload / sbcpay->frame_length; payload_length = frame_count * sbcpay->frame_length; if (payload_length == 0) /* Nothing to send */ return GST_FLOW_OK; outbuf = gst_rtp_buffer_new_allocate(payload_length + RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0); gst_rtp_buffer_set_payload_type(outbuf, GST_BASE_RTP_PAYLOAD_PT(sbcpay)); payload_data = gst_rtp_buffer_get_payload(outbuf); payload = (struct rtp_payload *) payload_data; memset(payload, 0, sizeof(struct rtp_payload)); payload->frame_count = frame_count; gst_adapter_copy(sbcpay->adapter, payload_data + RTP_SBC_PAYLOAD_HEADER_SIZE, 0, payload_length); gst_adapter_flush(sbcpay->adapter, payload_length); GST_BUFFER_TIMESTAMP(outbuf) = sbcpay->timestamp; GST_DEBUG_OBJECT(sbcpay, "Pushing %d bytes", payload_length); return gst_basertppayload_push(GST_BASE_RTP_PAYLOAD(sbcpay), outbuf); }
static void gst_rtp_gsm_pay_init (GstRTPGSMPay * rtpgsmpay, GstRTPGSMPayClass * klass) { GST_BASE_RTP_PAYLOAD (rtpgsmpay)->clock_rate = 8000; GST_BASE_RTP_PAYLOAD_PT (rtpgsmpay) = GST_RTP_PAYLOAD_GSM; }
static GstFlowReturn gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer) { GstBaseRTPPayload *rtppay; GstAsfPacketInfo *packetinfo; guint8 flags; guint8 *data; guint32 packet_util_size; guint32 packet_offset; guint32 size_left; GstFlowReturn ret = GST_FLOW_OK; rtppay = GST_BASE_RTP_PAYLOAD (rtpasfpay); packetinfo = &rtpasfpay->packetinfo; if (!gst_asf_parse_packet (buffer, packetinfo, TRUE, rtpasfpay->asfinfo.packet_size)) { GST_ERROR_OBJECT (rtpasfpay, "Error while parsing asf packet"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } if (packetinfo->packet_size == 0) packetinfo->packet_size = rtpasfpay->asfinfo.packet_size; GST_LOG_OBJECT (rtpasfpay, "Packet size: %" G_GUINT32_FORMAT ", padding: %" G_GUINT32_FORMAT, packetinfo->packet_size, packetinfo->padding); /* update padding field to 0 */ if (packetinfo->padding > 0) { GstAsfPacketInfo info; /* find padding field offset */ guint offset = packetinfo->err_cor_len + 2 + gst_asf_get_var_size_field_len (packetinfo->packet_field_type) + gst_asf_get_var_size_field_len (packetinfo->seq_field_type); buffer = gst_buffer_make_writable (buffer); switch (packetinfo->padd_field_type) { case ASF_FIELD_TYPE_DWORD: GST_WRITE_UINT32_LE (&(GST_BUFFER_DATA (buffer)[offset]), 0); break; case ASF_FIELD_TYPE_WORD: GST_WRITE_UINT16_LE (&(GST_BUFFER_DATA (buffer)[offset]), 0); break; case ASF_FIELD_TYPE_BYTE: GST_BUFFER_DATA (buffer)[offset] = 0; break; case ASF_FIELD_TYPE_NONE: default: break; } gst_asf_parse_packet (buffer, &info, FALSE, 0); } if (packetinfo->padding != 0) packet_util_size = rtpasfpay->asfinfo.packet_size - packetinfo->padding; else packet_util_size = packetinfo->packet_size; packet_offset = 0; while (packet_util_size > 0) { /* Even if we don't fill completely an output buffer we * push it when we add an fragment. Because it seems that * it is not possible to determine where a asf packet * fragment ends inside a rtp packet payload. * This flag tells us to push the packet. */ gboolean force_push = FALSE; /* we have no output buffer pending, create one */ if (rtpasfpay->current == NULL) { GST_LOG_OBJECT (rtpasfpay, "Creating new output buffer"); rtpasfpay->current = gst_rtp_buffer_new_allocate_len (GST_BASE_RTP_PAYLOAD_MTU (rtpasfpay), 0, 0); rtpasfpay->cur_off = gst_rtp_buffer_get_header_len (rtpasfpay->current); rtpasfpay->has_ts = FALSE; rtpasfpay->marker = FALSE; } data = GST_BUFFER_DATA (rtpasfpay->current) + rtpasfpay->cur_off; size_left = GST_BUFFER_SIZE (rtpasfpay->current) - rtpasfpay->cur_off; GST_DEBUG_OBJECT (rtpasfpay, "Input buffer bytes consumed: %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, packet_offset, GST_BUFFER_SIZE (buffer)); GST_DEBUG_OBJECT (rtpasfpay, "Output rtpbuffer status"); GST_DEBUG_OBJECT (rtpasfpay, "Current offset: %" G_GUINT32_FORMAT, rtpasfpay->cur_off); GST_DEBUG_OBJECT (rtpasfpay, "Size left: %" G_GUINT32_FORMAT, size_left); GST_DEBUG_OBJECT (rtpasfpay, "Has ts: %s", rtpasfpay->has_ts ? "yes" : "no"); if (rtpasfpay->has_ts) { GST_DEBUG_OBJECT (rtpasfpay, "Ts: %" G_GUINT32_FORMAT, rtpasfpay->ts); } flags = 0; if (packetinfo->has_keyframe) { flags = flags | 0x80; } flags = flags | 0x20; /* Relative timestamp is present */ if (!rtpasfpay->has_ts) { /* this is the first asf packet, its send time is the * rtp packet timestamp */ rtpasfpay->has_ts = TRUE; rtpasfpay->ts = packetinfo->send_time; } if (GST_BUFFER_SIZE (rtpasfpay->current) - rtpasfpay->cur_off >= packet_util_size + 8) { /* enough space for the rest of the packet */ if (packet_offset == 0) { flags = flags | 0x40; GST_WRITE_UINT24_BE (data + 1, packet_util_size); } else { GST_WRITE_UINT24_BE (data + 1, packet_offset); force_push = TRUE; } data[0] = flags; GST_WRITE_UINT32_BE (data + 4, (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts); memcpy (data + 8, GST_BUFFER_DATA (buffer) + packet_offset, packet_util_size); /* updating status variables */ rtpasfpay->cur_off += 8 + packet_util_size; size_left -= packet_util_size + 8; packet_offset += packet_util_size; packet_util_size = 0; rtpasfpay->marker = TRUE; } else { /* fragment packet */ data[0] = flags; GST_WRITE_UINT24_BE (data + 1, packet_offset); GST_WRITE_UINT32_BE (data + 4, (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts); memcpy (data + 8, GST_BUFFER_DATA (buffer) + packet_offset, size_left - 8); /* updating status variables */ rtpasfpay->cur_off += size_left; packet_offset += size_left - 8; packet_util_size -= size_left - 8; size_left = 0; force_push = TRUE; } /* there is not enough room for any more buffers */ if (force_push || size_left <= 8) { if (size_left != 0) { /* trim remaining bytes not used */ GstBuffer *aux = gst_buffer_create_sub (rtpasfpay->current, 0, GST_BUFFER_SIZE (rtpasfpay->current) - size_left); gst_buffer_unref (rtpasfpay->current); rtpasfpay->current = aux; } gst_rtp_buffer_set_ssrc (rtpasfpay->current, rtppay->current_ssrc); gst_rtp_buffer_set_marker (rtpasfpay->current, rtpasfpay->marker); gst_rtp_buffer_set_payload_type (rtpasfpay->current, GST_BASE_RTP_PAYLOAD_PT (rtppay)); gst_rtp_buffer_set_seq (rtpasfpay->current, rtppay->seqnum + 1); gst_rtp_buffer_set_timestamp (rtpasfpay->current, packetinfo->send_time); GST_BUFFER_TIMESTAMP (rtpasfpay->current) = GST_BUFFER_TIMESTAMP (buffer); gst_buffer_set_caps (rtpasfpay->current, GST_PAD_CAPS (GST_BASE_RTP_PAYLOAD_SRCPAD (rtppay))); rtppay->seqnum++; rtppay->timestamp = packetinfo->send_time; GST_DEBUG_OBJECT (rtpasfpay, "Pushing rtp buffer"); ret = gst_pad_push (GST_BASE_RTP_PAYLOAD_SRCPAD (rtppay), rtpasfpay->current); rtpasfpay->current = NULL; if (ret != GST_FLOW_OK) { gst_buffer_unref (buffer); return ret; } } } gst_buffer_unref (buffer); return ret; }
/** * gst_basertppayload_set_outcaps: * @payload: a #GstBaseRTPPayload * @fieldname: the first field name or %NULL * @...: field values * * Configure the output caps with the optional parameters. * * Variable arguments should be in the form field name, field type * (as a GType), value(s). The last variable argument should be NULL. * * Returns: %TRUE if the caps could be set. */ gboolean gst_basertppayload_set_outcaps (GstBaseRTPPayload * payload, gchar * fieldname, ...) { GstCaps *srccaps, *peercaps; gboolean res; /* fill in the defaults, there properties cannot be negotiated. */ srccaps = gst_caps_new_simple ("application/x-rtp", "media", G_TYPE_STRING, payload->media, "clock-rate", G_TYPE_INT, payload->clock_rate, "encoding-name", G_TYPE_STRING, payload->encoding_name, NULL); GST_DEBUG_OBJECT (payload, "defaults: %" GST_PTR_FORMAT, srccaps); if (fieldname) { va_list varargs; /* override with custom properties */ va_start (varargs, fieldname); gst_caps_set_simple_valist (srccaps, fieldname, varargs); va_end (varargs); GST_DEBUG_OBJECT (payload, "custom added: %" GST_PTR_FORMAT, srccaps); } /* the peer caps can override some of the defaults */ peercaps = gst_pad_peer_get_caps (payload->srcpad); if (peercaps == NULL) { /* no peer caps, just add the other properties */ gst_caps_set_simple (srccaps, "payload", G_TYPE_INT, GST_BASE_RTP_PAYLOAD_PT (payload), "ssrc", G_TYPE_UINT, payload->current_ssrc, "clock-base", G_TYPE_UINT, payload->ts_base, "seqnum-base", G_TYPE_UINT, payload->seqnum_base, NULL); GST_DEBUG_OBJECT (payload, "no peer caps: %" GST_PTR_FORMAT, srccaps); } else { GstCaps *temp; GstStructure *s, *d; const GValue *value; gint pt; /* peer provides caps we can use to fixate, intersect. This always returns a * writable caps. */ temp = gst_caps_intersect (srccaps, peercaps); gst_caps_unref (srccaps); gst_caps_unref (peercaps); /* now fixate, start by taking the first caps */ gst_caps_truncate (temp); /* get first structure */ s = gst_caps_get_structure (temp, 0); if (gst_structure_get_int (s, "payload", &pt)) { /* use peer pt */ GST_BASE_RTP_PAYLOAD_PT (payload) = pt; GST_LOG_OBJECT (payload, "using peer pt %d", pt); } else { if (gst_structure_has_field (s, "payload")) { /* can only fixate if there is a field */ gst_structure_fixate_field_nearest_int (s, "payload", GST_BASE_RTP_PAYLOAD_PT (payload)); gst_structure_get_int (s, "payload", &pt); GST_LOG_OBJECT (payload, "using peer pt %d", pt); } else { /* no pt field, use the internal pt */ pt = GST_BASE_RTP_PAYLOAD_PT (payload); gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL); GST_LOG_OBJECT (payload, "using internal pt %d", pt); } } if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT)) { value = gst_structure_get_value (s, "ssrc"); payload->current_ssrc = g_value_get_uint (value); GST_LOG_OBJECT (payload, "using peer ssrc %08x", payload->current_ssrc); } else { /* FIXME, fixate_nearest_uint would be even better */ gst_structure_set (s, "ssrc", G_TYPE_UINT, payload->current_ssrc, NULL); GST_LOG_OBJECT (payload, "using internal ssrc %08x", payload->current_ssrc); } if (gst_structure_has_field_typed (s, "clock-base", G_TYPE_UINT)) { value = gst_structure_get_value (s, "clock-base"); payload->ts_base = g_value_get_uint (value); GST_LOG_OBJECT (payload, "using peer clock-base %u", payload->ts_base); } else { /* FIXME, fixate_nearest_uint would be even better */ gst_structure_set (s, "clock-base", G_TYPE_UINT, payload->ts_base, NULL); GST_LOG_OBJECT (payload, "using internal clock-base %u", payload->ts_base); } if (gst_structure_has_field_typed (s, "seqnum-base", G_TYPE_UINT)) { value = gst_structure_get_value (s, "seqnum-base"); payload->seqnum_base = g_value_get_uint (value); GST_LOG_OBJECT (payload, "using peer seqnum-base %u", payload->seqnum_base); } else { /* FIXME, fixate_nearest_uint would be even better */ gst_structure_set (s, "seqnum-base", G_TYPE_UINT, payload->seqnum_base, NULL); GST_LOG_OBJECT (payload, "using internal seqnum-base %u", payload->seqnum_base); } /* make the target caps by copying over all the fixed caps, removing the * unfixed caps. */ srccaps = gst_caps_new_simple (gst_structure_get_name (s), NULL); d = gst_caps_get_structure (srccaps, 0); gst_structure_foreach (s, (GstStructureForeachFunc) copy_fixed, d); gst_caps_unref (temp); GST_DEBUG_OBJECT (payload, "with peer caps: %" GST_PTR_FORMAT, srccaps); } res = gst_pad_set_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload), srccaps); gst_caps_unref (srccaps); return res; }