static gboolean gst_rtp_h263p_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps) { gboolean res; GstCaps *peercaps; gchar *encoding_name = NULL; g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE); peercaps = gst_pad_peer_get_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload)); if (peercaps) { GstCaps *intersect = gst_caps_intersect (peercaps, gst_pad_get_pad_template_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload))); gst_caps_unref (peercaps); if (!gst_caps_is_empty (intersect)) { GstStructure *s = gst_caps_get_structure (intersect, 0); encoding_name = g_strdup (gst_structure_get_string (s, "encoding-name")); } gst_caps_unref (intersect); } if (!encoding_name) encoding_name = g_strdup ("H263-1998"); gst_basertppayload_set_options (payload, "video", TRUE, (gchar *) encoding_name, 90000); res = gst_basertppayload_set_outcaps (payload, NULL); g_free (encoding_name); return res; }
static GstCaps * gst_rtp_h263p_pay_sink_getcaps (GstBaseRTPPayload * payload, GstPad * pad) { GstRtpH263PPay *rtph263ppay; GstCaps *caps = NULL; GstCaps *peercaps = NULL; GstCaps *intersect = NULL; guint i; rtph263ppay = GST_RTP_H263P_PAY (payload); peercaps = gst_pad_peer_get_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload)); if (!peercaps) return gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_RTP_PAYLOAD_SINKPAD (payload))); intersect = gst_caps_intersect (peercaps, gst_pad_get_pad_template_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload))); gst_caps_unref (peercaps); if (gst_caps_is_empty (intersect)) return intersect; caps = gst_caps_new_empty (); for (i = 0; i < gst_caps_get_size (intersect); i++) { GstStructure *s = gst_caps_get_structure (intersect, i); const gchar *encoding_name = gst_structure_get_string (s, "encoding-name"); if (!strcmp (encoding_name, "H263-2000")) { const gchar *profile_str = gst_structure_get_string (s, "profile"); const gchar *level_str = gst_structure_get_string (s, "level"); int profile = 0; int level = 0; if (profile_str && level_str) { gboolean i = FALSE, j = FALSE, l = FALSE, t = FALSE, f = FALSE, v = FALSE; GstStructure *new_s = gst_structure_new ("video/x-h263", "variant", G_TYPE_STRING, "itu", NULL); profile = atoi (profile_str); level = atoi (level_str); /* These profiles are defined in the H.263 Annex X */ switch (profile) { case 0: /* The Baseline Profile (Profile 0) */ break; case 1: /* H.320 Coding Efficiency Version 2 Backward-Compatibility Profile * (Profile 1) * Baseline + Annexes I, J, L.4 and T */ i = j = l = t = TRUE; break; case 2: /* Version 1 Backward-Compatibility Profile (Profile 2) * Baseline + Annex F */ i = j = l = t = f = TRUE; break; case 3: /* Version 2 Interactive and Streaming Wireless Profile * Baseline + Annexes I, J, T */ i = j = t = TRUE; break; case 4: /* Version 3 Interactive and Streaming Wireless Profile (Profile 4) * Baseline + Annexes I, J, T, V, W.6.3.8, */ /* Missing W.6.3.8 */ i = j = t = v = TRUE; break; case 5: /* Conversational High Compression Profile (Profile 5) * Baseline + Annexes F, I, J, L.4, T, D, U */ /* Missing D, U */ f = i = j = l = t = TRUE; break; case 6: /* Conversational Internet Profile (Profile 6) * Baseline + Annexes F, I, J, L.4, T, D, U and * K with arbitratry slice ordering */ /* Missing D, U, K with arbitratry slice ordering */ f = i = j = l = t = TRUE; break; case 7: /* Conversational Interlace Profile (Profile 7) * Baseline + Annexes F, I, J, L.4, T, D, U, W.6.3.11 */ /* Missing D, U, W.6.3.11 */ f = i = j = l = t = TRUE; break; case 8: /* High Latency Profile (Profile 8) * Baseline + Annexes F, I, J, L.4, T, D, U, P.5, O.1.1 and * K with arbitratry slice ordering */ /* Missing D, U, P.5, O.1.1 */ f = i = j = l = t = TRUE; break; } if (f || i || j || t || l || v) { GValue list = { 0 }; GValue vstr = { 0 }; g_value_init (&list, GST_TYPE_LIST); g_value_init (&vstr, G_TYPE_STRING); g_value_set_static_string (&vstr, "h263"); gst_value_list_append_value (&list, &vstr); g_value_set_static_string (&vstr, "h263p"); gst_value_list_append_value (&list, &vstr); if (l || v) { g_value_set_static_string (&vstr, "h263pp"); gst_value_list_append_value (&list, &vstr); } g_value_unset (&vstr); gst_structure_set_value (new_s, "h263version", &list); g_value_unset (&list); } else { gst_structure_set (new_s, "h263version", G_TYPE_STRING, "h263", NULL); } if (!f) gst_structure_set (new_s, "annex-f", G_TYPE_BOOLEAN, FALSE, NULL); if (!i) gst_structure_set (new_s, "annex-i", G_TYPE_BOOLEAN, FALSE, NULL); if (!j) gst_structure_set (new_s, "annex-j", G_TYPE_BOOLEAN, FALSE, NULL); if (!t) gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL); if (!l) gst_structure_set (new_s, "annex-l", G_TYPE_BOOLEAN, FALSE, NULL); if (!v) gst_structure_set (new_s, "annex-v", G_TYPE_BOOLEAN, FALSE, NULL); if (level <= 10 || level == 45) { gst_structure_set (new_s, "width", GST_TYPE_INT_RANGE, 1, 176, "height", GST_TYPE_INT_RANGE, 1, 144, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 2002, NULL); gst_caps_merge_structure (caps, new_s); } else if (level <= 20) { GstStructure *s_copy = gst_structure_copy (new_s); gst_structure_set (new_s, "width", GST_TYPE_INT_RANGE, 1, 352, "height", GST_TYPE_INT_RANGE, 1, 288, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 2002, NULL); gst_caps_merge_structure (caps, new_s); gst_structure_set (s_copy, "width", GST_TYPE_INT_RANGE, 1, 176, "height", GST_TYPE_INT_RANGE, 1, 144, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001, NULL); gst_caps_merge_structure (caps, s_copy); } else if (level <= 40) { gst_structure_set (new_s, "width", GST_TYPE_INT_RANGE, 1, 352, "height", GST_TYPE_INT_RANGE, 1, 288, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 30000, 1001, NULL); gst_caps_merge_structure (caps, new_s); } else if (level <= 50) { GstStructure *s_copy = gst_structure_copy (new_s); gst_structure_set (new_s, "width", GST_TYPE_INT_RANGE, 1, 352, "height", GST_TYPE_INT_RANGE, 1, 288, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL); gst_caps_merge_structure (caps, new_s); gst_structure_set (s_copy, "width", GST_TYPE_INT_RANGE, 1, 352, "height", GST_TYPE_INT_RANGE, 1, 240, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL); gst_caps_merge_structure (caps, s_copy); } else if (level <= 60) { GstStructure *s_copy = gst_structure_copy (new_s); gst_structure_set (new_s, "width", GST_TYPE_INT_RANGE, 1, 720, "height", GST_TYPE_INT_RANGE, 1, 288, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL); gst_caps_merge_structure (caps, new_s); gst_structure_set (s_copy, "width", GST_TYPE_INT_RANGE, 1, 720, "height", GST_TYPE_INT_RANGE, 1, 240, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL); gst_caps_merge_structure (caps, s_copy); } else if (level <= 70) { GstStructure *s_copy = gst_structure_copy (new_s); gst_structure_set (new_s, "width", GST_TYPE_INT_RANGE, 1, 720, "height", GST_TYPE_INT_RANGE, 1, 576, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 50, 1, NULL); gst_caps_merge_structure (caps, new_s); gst_structure_set (s_copy, "width", GST_TYPE_INT_RANGE, 1, 720, "height", GST_TYPE_INT_RANGE, 1, 480, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60000, 1001, NULL); gst_caps_merge_structure (caps, s_copy); } else { gst_caps_merge_structure (caps, new_s); } } else { GstStructure *new_s = gst_structure_new ("video/x-h263", "variant", G_TYPE_STRING, "itu", "h263version", G_TYPE_STRING, "h263", NULL); GST_DEBUG_OBJECT (rtph263ppay, "No profile or level specified" " for H263-2000, defaulting to baseline H263"); gst_caps_merge_structure (caps, new_s); } } else { gboolean f = FALSE, i = FALSE, j = FALSE, t = FALSE; /* FIXME: ffmpeg support the Appendix K too, how do we express it ? * guint k; */ const gchar *str; GstStructure *new_s = gst_structure_new ("video/x-h263", "variant", G_TYPE_STRING, "itu", NULL); gboolean added = FALSE; str = gst_structure_get_string (s, "f"); if (str && !strcmp (str, "1")) f = TRUE; str = gst_structure_get_string (s, "i"); if (str && !strcmp (str, "1")) i = TRUE; str = gst_structure_get_string (s, "j"); if (str && !strcmp (str, "1")) j = TRUE; str = gst_structure_get_string (s, "t"); if (str && !strcmp (str, "1")) t = TRUE; if (f || i || j || t) { GValue list = { 0 }; GValue vstr = { 0 }; g_value_init (&list, GST_TYPE_LIST); g_value_init (&vstr, G_TYPE_STRING); g_value_set_static_string (&vstr, "h263"); gst_value_list_append_value (&list, &vstr); g_value_set_static_string (&vstr, "h263p"); gst_value_list_append_value (&list, &vstr); g_value_unset (&vstr); gst_structure_set_value (new_s, "h263version", &list); g_value_unset (&list); } else { gst_structure_set (new_s, "h263version", G_TYPE_STRING, "h263", NULL); } if (!f) gst_structure_set (new_s, "annex-f", G_TYPE_BOOLEAN, FALSE, NULL); if (!i) gst_structure_set (new_s, "annex-i", G_TYPE_BOOLEAN, FALSE, NULL); if (!j) gst_structure_set (new_s, "annex-j", G_TYPE_BOOLEAN, FALSE, NULL); if (!t) gst_structure_set (new_s, "annex-t", G_TYPE_BOOLEAN, FALSE, NULL); str = gst_structure_get_string (s, "custom"); if (str) { unsigned int xmax, ymax, mpi; if (sscanf (str, "%u,%u,%u", &xmax, &ymax, &mpi) == 3) { if (xmax % 4 && ymax % 4 && mpi >= 1 && mpi <= 32) { caps_append (caps, new_s, xmax, ymax, mpi); added = TRUE; } else { GST_WARNING_OBJECT (rtph263ppay, "Invalid custom framesize/MPI" " %u x %u at %u, ignoring", xmax, ymax, mpi); } } else { GST_WARNING_OBJECT (rtph263ppay, "Invalid custom framesize/MPI: %s," " ignoring", str); } } str = gst_structure_get_string (s, "16cif"); if (str) { int mpi = atoi (str); caps_append (caps, new_s, 1408, 1152, mpi); added = TRUE; } str = gst_structure_get_string (s, "4cif"); if (str) { int mpi = atoi (str); caps_append (caps, new_s, 704, 576, mpi); added = TRUE; } str = gst_structure_get_string (s, "cif"); if (str) { int mpi = atoi (str); caps_append (caps, new_s, 352, 288, mpi); added = TRUE; } str = gst_structure_get_string (s, "qcif"); if (str) { int mpi = atoi (str); caps_append (caps, new_s, 176, 144, mpi); added = TRUE; } str = gst_structure_get_string (s, "sqcif"); if (str) { int mpi = atoi (str); caps_append (caps, new_s, 128, 96, mpi); added = TRUE; } if (added) gst_structure_free (new_s); else gst_caps_merge_structure (caps, new_s); } } gst_caps_unref (intersect); return caps; }
static GstCaps * gst_rtp_h264_pay_getcaps (GstBaseRTPPayload * payload, GstPad * pad) { GstCaps *template_caps; GstCaps *allowed_caps; GstCaps *caps, *icaps; gboolean append_unrestricted; guint i; allowed_caps = gst_pad_peer_get_caps_reffed (GST_BASE_RTP_PAYLOAD_SRCPAD (payload)); if (allowed_caps == NULL) return NULL; template_caps = gst_static_pad_template_get_caps (&gst_rtp_h264_pay_sink_template); if (gst_caps_is_any (allowed_caps)) { caps = gst_caps_ref (template_caps); goto done; } if (gst_caps_is_empty (allowed_caps)) { caps = gst_caps_ref (allowed_caps); goto done; } caps = gst_caps_new_empty (); append_unrestricted = FALSE; for (i = 0; i < gst_caps_get_size (allowed_caps); i++) { GstStructure *s = gst_caps_get_structure (allowed_caps, i); GstStructure *new_s = gst_structure_new ("video/x-h264", NULL); const gchar *profile_level_id; profile_level_id = gst_structure_get_string (s, "profile-level-id"); if (profile_level_id && strlen (profile_level_id) == 6) { const gchar *profile; const gchar *level; long int spsint; guint8 sps[3]; spsint = strtol (profile_level_id, NULL, 16); sps[0] = spsint >> 16; sps[1] = spsint >> 8; sps[2] = spsint; profile = gst_codec_utils_h264_get_profile (sps, 3); level = gst_codec_utils_h264_get_level (sps, 3); if (profile && level) { GST_LOG_OBJECT (payload, "In caps, have profile %s and level %s", profile, level); if (!strcmp (profile, "constrained-baseline")) gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL); else { GValue val = { 0, }; GValue profiles = { 0, }; g_value_init (&profiles, GST_TYPE_LIST); g_value_init (&val, G_TYPE_STRING); g_value_set_static_string (&val, profile); gst_value_list_append_value (&profiles, &val); g_value_set_static_string (&val, "constrained-baseline"); gst_value_list_append_value (&profiles, &val); gst_structure_take_value (new_s, "profile", &profiles); } if (!strcmp (level, "1")) gst_structure_set (new_s, "level", G_TYPE_STRING, level, NULL); else { GValue levels = { 0, }; GValue val = { 0, }; int j; g_value_init (&levels, GST_TYPE_LIST); g_value_init (&val, G_TYPE_STRING); for (j = 0; all_levels[j]; j++) { g_value_set_static_string (&val, all_levels[j]); gst_value_list_prepend_value (&levels, &val); if (!strcmp (level, all_levels[j])) break; } gst_structure_take_value (new_s, "level", &levels); } } else { /* Invalid profile-level-id means baseline */ gst_structure_set (new_s, "profile", G_TYPE_STRING, "constrained-baseline", NULL); } } else { /* No profile-level-id means baseline or unrestricted */ gst_structure_set (new_s, "profile", G_TYPE_STRING, "constrained-baseline", NULL); append_unrestricted = TRUE; } gst_caps_merge_structure (caps, new_s); }
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; }