gboolean gst_rtp_dtmf_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps) { GstCaps *filtercaps, *srccaps; GstStructure *structure = gst_caps_get_structure (caps, 0); gint clock_rate = 8000; /* default */ gst_structure_get_int (structure, "clock-rate", &clock_rate); filter->clock_rate = clock_rate; filtercaps = gst_pad_get_pad_template_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter)); filtercaps = gst_caps_make_writable (filtercaps); gst_caps_set_simple (filtercaps, "rate", G_TYPE_INT, clock_rate, NULL); srccaps = gst_pad_peer_query_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter), filtercaps); gst_caps_unref (filtercaps); gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter), srccaps); gst_caps_unref (srccaps); return TRUE; }
static void gst_rtp_pcmu_depay_init (GstRtpPcmuDepay * rtppcmudepay) { GstRTPBaseDepayload *depayload; depayload = GST_RTP_BASE_DEPAYLOAD (rtppcmudepay); gst_pad_use_fixed_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload)); }
static gboolean gst_rtp_vp8_depay_set_caps (GstRTPBaseDepayload * depayload, GstCaps * caps) { GstCaps *srccaps = gst_caps_new_simple ("video/x-vp8", "framerate", GST_TYPE_FRACTION, 0, 1, NULL); gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps); gst_caps_unref (srccaps); return TRUE; }
static GstFlowReturn gst_rtp_vraw_depay_negotiate_pool (GstRtpVRawDepay * depay, GstCaps * caps, GstVideoInfo * info) { GstQuery *query; GstBufferPool *pool = NULL; guint size, min, max; GstStructure *config; /* find a pool for the negotiated caps now */ query = gst_query_new_allocation (caps, TRUE); if (!gst_pad_peer_query (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), query)) { /* not a problem, we use the defaults of query */ GST_DEBUG_OBJECT (depay, "could not get downstream ALLOCATION hints"); } if (gst_query_get_n_allocation_pools (query) > 0) { /* we got configuration from our peer, parse them */ gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); } else { GST_DEBUG_OBJECT (depay, "didn't get downstream pool hints"); size = info->size; min = max = 0; } if (pool == NULL) { /* we did not get a pool, make one ourselves then */ pool = gst_video_buffer_pool_new (); } if (depay->pool) gst_object_unref (depay->pool); depay->pool = pool; config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, caps, size, min, max); if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) { /* just set the metadata, if the pool can support it we will transparently use * it through the video info API. We could also see if the pool support this * metadata and only activate it then. */ gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); } gst_buffer_pool_set_config (pool, config); /* and activate */ gst_buffer_pool_set_active (pool, TRUE); gst_query_unref (query); return GST_FLOW_OK; }
static gboolean gst_rtp_qcelp_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) { GstCaps *srccaps; gboolean res; srccaps = gst_caps_new_simple ("audio/qcelp", "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL); res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps); gst_caps_unref (srccaps); return res; }
static gboolean gst_rtp_g729_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) { GstStructure *structure; GstCaps *srccaps; GstRtpG729Depay *rtpg729depay; const gchar *params; gint clock_rate, channels; gboolean ret; rtpg729depay = GST_RTP_G729_DEPAY (depayload); structure = gst_caps_get_structure (caps, 0); if (!(params = gst_structure_get_string (structure, "encoding-params"))) channels = 1; else { channels = atoi (params); } if (!gst_structure_get_int (structure, "clock-rate", &clock_rate)) clock_rate = 8000; if (channels != 1) goto wrong_channels; if (clock_rate != 8000) goto wrong_clock_rate; depayload->clock_rate = clock_rate; srccaps = gst_caps_new_simple ("audio/G729", "channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, clock_rate, NULL); ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps); gst_caps_unref (srccaps); return ret; /* ERRORS */ wrong_channels: { GST_DEBUG_OBJECT (rtpg729depay, "expected 1 channel, got %d", channels); return FALSE; } wrong_clock_rate: { GST_DEBUG_OBJECT (rtpg729depay, "expected 8000 clock-rate, got %d", clock_rate); return FALSE; } }
static gboolean gst_rtp_opus_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) { GstCaps *srccaps; GstStructure *s; gboolean ret; const gchar *sprop_stereo, *sprop_maxcapturerate; srccaps = gst_caps_new_simple ("audio/x-opus", "channel-mapping-family", G_TYPE_INT, 0, NULL); s = gst_caps_get_structure (caps, 0); if ((sprop_stereo = gst_structure_get_string (s, "sprop-stereo"))) { if (strcmp (sprop_stereo, "0") == 0) gst_caps_set_simple (srccaps, "channels", G_TYPE_INT, 1, NULL); else if (strcmp (sprop_stereo, "1") == 0) gst_caps_set_simple (srccaps, "channels", G_TYPE_INT, 2, NULL); else GST_WARNING_OBJECT (depayload, "Unknown sprop-stereo value '%s'", sprop_stereo); } if ((sprop_maxcapturerate = gst_structure_get_string (s, "sprop-maxcapturerate"))) { gulong rate; gchar *tailptr; rate = strtoul (sprop_maxcapturerate, &tailptr, 10); if (rate > INT_MAX || *tailptr != '\0') { GST_WARNING_OBJECT (depayload, "Failed to parse sprop-maxcapturerate value '%s'", sprop_maxcapturerate); } else { gst_caps_set_simple (srccaps, "rate", G_TYPE_INT, rate, NULL); } } ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps); GST_DEBUG_OBJECT (depayload, "set caps on source: %" GST_PTR_FORMAT " (ret=%d)", srccaps, ret); gst_caps_unref (srccaps); depayload->clock_rate = 48000; return ret; }
static gboolean gst_rtp_opus_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) { GstCaps *srccaps; gboolean ret; srccaps = gst_caps_new_empty_simple ("audio/x-opus"); ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps); GST_DEBUG_OBJECT (depayload, "set caps on source: %" GST_PTR_FORMAT " (ret=%d)", srccaps, ret); gst_caps_unref (srccaps); depayload->clock_rate = 48000; return ret; }
static gboolean gst_rtp_gsm_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) { GstCaps *srccaps; gboolean ret; GstStructure *structure; gint clock_rate; structure = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (structure, "clock-rate", &clock_rate)) clock_rate = 8000; /* default */ depayload->clock_rate = clock_rate; srccaps = gst_caps_new_simple ("audio/x-gsm", "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, clock_rate, NULL); ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps); gst_caps_unref (srccaps); return ret; }
gboolean gst_rtp_dtmf_depay_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps) { GstCaps *srccaps; GstStructure *structure = gst_caps_get_structure (caps, 0); gint clock_rate = 8000; /* default */ gst_structure_get_int (structure, "clock-rate", &clock_rate); filter->clock_rate = clock_rate; srccaps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, "endianness", G_TYPE_INT, G_BYTE_ORDER, "signed", G_TYPE_BOOLEAN, TRUE, "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, clock_rate, NULL); gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (filter), srccaps); gst_caps_unref (srccaps); return TRUE; }
static gboolean gst_rtp_ilbc_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) { GstRTPiLBCDepay *rtpilbcdepay = GST_RTP_ILBC_DEPAY (depayload); GstCaps *srccaps; GstStructure *structure; const gchar *mode_str = NULL; gint mode, clock_rate; gboolean ret; structure = gst_caps_get_structure (caps, 0); mode = rtpilbcdepay->mode; if (!gst_structure_get_int (structure, "clock-rate", &clock_rate)) clock_rate = 8000; depayload->clock_rate = clock_rate; /* parse mode, if we can */ mode_str = gst_structure_get_string (structure, "mode"); if (mode_str) { mode = strtol (mode_str, NULL, 10); if (mode != 20 && mode != 30) mode = rtpilbcdepay->mode; } rtpilbcdepay->mode = mode; srccaps = gst_caps_new_simple ("audio/x-iLBC", "mode", G_TYPE_INT, rtpilbcdepay->mode, NULL); ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps); GST_DEBUG ("set caps on source: %" GST_PTR_FORMAT " (ret=%d)", srccaps, ret); gst_caps_unref (srccaps); return ret; }
static gboolean gst_rtp_bv_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) { GstRTPBVDepay *rtpbvdepay = GST_RTP_BV_DEPAY (depayload); GstCaps *srccaps; GstStructure *structure; const gchar *mode_str = NULL; gint mode, clock_rate, expected_rate; gboolean ret; structure = gst_caps_get_structure (caps, 0); mode_str = gst_structure_get_string (structure, "encoding-name"); if (!mode_str) goto no_mode; if (!strcmp (mode_str, "BV16")) { mode = 16; expected_rate = 8000; } else if (!strcmp (mode_str, "BV32")) { mode = 32; expected_rate = 16000; } else goto invalid_mode; if (!gst_structure_get_int (structure, "clock-rate", &clock_rate)) clock_rate = expected_rate; else if (clock_rate != expected_rate) goto wrong_rate; depayload->clock_rate = clock_rate; rtpbvdepay->mode = mode; srccaps = gst_caps_new_simple ("audio/x-bv", "mode", G_TYPE_INT, rtpbvdepay->mode, NULL); ret = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps); GST_DEBUG ("set caps on source: %" GST_PTR_FORMAT " (ret=%d)", srccaps, ret); gst_caps_unref (srccaps); return ret; /* ERRORS */ no_mode: { GST_ERROR_OBJECT (rtpbvdepay, "did not receive an encoding-name"); return FALSE; } invalid_mode: { GST_ERROR_OBJECT (rtpbvdepay, "invalid encoding-name, expected BV16 or BV32, got %s", mode_str); return FALSE; } wrong_rate: { GST_ERROR_OBJECT (rtpbvdepay, "invalid clock-rate, expected %d, got %d", expected_rate, clock_rate); return FALSE; } }
static GstBuffer * gst_rtp_vp9_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp) { GstRtpVP9Depay *self = GST_RTP_VP9_DEPAY (depay); GstBuffer *payload; guint8 *data; guint hdrsize = 1; guint size; gint spatial_layer = 0; gboolean i_bit, p_bit, l_bit, f_bit, b_bit, e_bit, v_bit; if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (rtp->buffer))) { GST_LOG_OBJECT (self, "Discontinuity, flushing adapter"); gst_adapter_clear (self->adapter); self->started = FALSE; } size = gst_rtp_buffer_get_payload_len (rtp); /* Mandatory with at least one header and one vp9 byte */ if (G_UNLIKELY (size < hdrsize + 1)) goto too_small; data = gst_rtp_buffer_get_payload (rtp); i_bit = (data[0] & 0x80) != 0; p_bit = (data[0] & 0x40) != 0; l_bit = (data[0] & 0x20) != 0; f_bit = (data[0] & 0x10) != 0; b_bit = (data[0] & 0x08) != 0; e_bit = (data[0] & 0x04) != 0; v_bit = (data[0] & 0x02) != 0; if (G_UNLIKELY (!self->started)) { /* Check if this is the start of a VP9 layer frame, otherwise bail */ if (!b_bit) goto done; self->started = TRUE; } GST_TRACE_OBJECT (self, "IPLFBEV : %d%d%d%d%d%d%d", i_bit, p_bit, l_bit, f_bit, b_bit, e_bit, v_bit); /* Check I optional header Picture ID */ if (i_bit) { hdrsize++; if (G_UNLIKELY (size < hdrsize + 1)) goto too_small; /* Check M for 15 bits PictureID */ if ((data[1] & 0x80) != 0) { hdrsize++; if (G_UNLIKELY (size < hdrsize + 1)) goto too_small; } } /* flexible-mode not implemented */ g_assert (!f_bit); /* Check L optional header layer indices */ if (l_bit) { hdrsize++; /* Check TL0PICIDX temporal layer zero index (non-flexible mode) */ if (!f_bit) hdrsize++; } /* Check V optional Scalability Structure */ if (v_bit) { guint n_s, y_bit, g_bit; guint8 *ss = &data[hdrsize]; guint sssize = 1; if (G_UNLIKELY (size < hdrsize + sssize + 1)) goto too_small; n_s = (ss[0] & 0xe0) >> 5; y_bit = (ss[0] & 0x10) != 0; g_bit = (ss[0] & 0x08) != 0; GST_TRACE_OBJECT (self, "SS header: N_S=%u, Y=%u, G=%u", n_s, y_bit, g_bit); sssize += y_bit ? (n_s + 1) * 4 : 0; if (G_UNLIKELY (size < hdrsize + sssize + 1)) goto too_small; if (y_bit) { guint i; for (i = 0; i <= n_s; i++) { /* For now, simply use the last layer specified for width and height */ self->ss_width = ss[1 + i * 4] * 256 + ss[2 + i * 4]; self->ss_height = ss[3 + i * 4] * 256 + ss[4 + i * 4]; GST_TRACE_OBJECT (self, "N_S[%d]: WIDTH=%u, HEIGHT=%u", i, self->ss_width, self->ss_height); } } if (g_bit) { guint i, j; guint n_g = ss[sssize]; sssize++; if (G_UNLIKELY (size < hdrsize + sssize + 1)) goto too_small; for (i = 0; i < n_g; i++) { guint t = (ss[sssize] & 0xe0) >> 5; guint u = (ss[sssize] & 0x10) >> 4; guint r = (ss[sssize] & 0x0c) >> 2; GST_TRACE_OBJECT (self, "N_G[%u]: 0x%02x -> T=%u, U=%u, R=%u", i, ss[sssize], t, u, r); for (j = 0; j < r; j++) GST_TRACE_OBJECT (self, " R[%u]: P_DIFF=%u", j, ss[sssize + 1 + j]); sssize += 1 + r; if (G_UNLIKELY (size < hdrsize + sssize + 1)) goto too_small; } } hdrsize += sssize; } GST_DEBUG_OBJECT (depay, "hdrsize %u, size %u", hdrsize, size); if (G_UNLIKELY (hdrsize >= size)) goto too_small; payload = gst_rtp_buffer_get_payload_subbuffer (rtp, hdrsize, -1); { GstMapInfo map; gst_buffer_map (payload, &map, GST_MAP_READ); GST_MEMDUMP_OBJECT (self, "vp9 payload", map.data, 16); gst_buffer_unmap (payload, &map); } gst_adapter_push (self->adapter, payload); /* Marker indicates that it was the last rtp packet for this frame */ if (gst_rtp_buffer_get_marker (rtp)) { GstBuffer *out; gboolean key_frame_first_layer = !p_bit && spatial_layer == 0; if (gst_adapter_available (self->adapter) < 10) goto too_small; out = gst_adapter_take_buffer (self->adapter, gst_adapter_available (self->adapter)); self->started = FALSE; /* mark keyframes */ out = gst_buffer_make_writable (out); /* Filter away all metas that are not sensible to copy */ gst_rtp_drop_meta (GST_ELEMENT_CAST (self), out, g_quark_from_static_string (GST_META_TAG_VIDEO_STR)); if (!key_frame_first_layer) { GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT); if (!self->caps_sent) { gst_buffer_unref (out); out = NULL; GST_INFO_OBJECT (self, "Dropping inter-frame before intra-frame"); gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depay), gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE, TRUE, 0)); } } else { GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT); if (self->last_width != self->ss_width || self->last_height != self->ss_height) { GstCaps *srccaps; /* Width and height are optional in the RTP header. Consider to parse * the frame header in addition if missing from RTP header */ if (self->ss_width != 0 && self->ss_height != 0) { srccaps = gst_caps_new_simple ("video/x-vp9", "framerate", GST_TYPE_FRACTION, 0, 1, "width", G_TYPE_INT, self->ss_width, "height", G_TYPE_INT, self->ss_height, NULL); } else { srccaps = gst_caps_new_simple ("video/x-vp9", "framerate", GST_TYPE_FRACTION, 0, 1, NULL); } gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), srccaps); gst_caps_unref (srccaps); self->caps_sent = TRUE; self->last_width = self->ss_width; self->last_height = self->ss_height; self->ss_width = 0; self->ss_height = 0; } } return out; } done: return NULL; too_small: GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring"); gst_adapter_clear (self->adapter); self->started = FALSE; goto done; }
static GstBuffer * gst_rtp_vraw_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstRtpVRawDepay *rtpvrawdepay; guint8 *payload, *p0, *yp, *up, *vp, *headers; guint32 timestamp; guint cont, ystride, uvstride, pgroup, payload_len; gint width, height, xinc, yinc; GstRTPBuffer rtp = { NULL }; GstVideoFrame *frame; gboolean marker; GstBuffer *outbuf = NULL; rtpvrawdepay = GST_RTP_VRAW_DEPAY (depayload); gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); timestamp = gst_rtp_buffer_get_timestamp (&rtp); if (timestamp != rtpvrawdepay->timestamp || rtpvrawdepay->outbuf == NULL) { GstBuffer *new_buffer; GstFlowReturn ret; GST_LOG_OBJECT (depayload, "new frame with timestamp %u", timestamp); /* new timestamp, flush old buffer and create new output buffer */ if (rtpvrawdepay->outbuf) { gst_video_frame_unmap (&rtpvrawdepay->frame); gst_rtp_base_depayload_push (depayload, rtpvrawdepay->outbuf); rtpvrawdepay->outbuf = NULL; } if (gst_pad_check_reconfigure (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload))) { GstCaps *caps; caps = gst_pad_get_current_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload)); gst_rtp_vraw_depay_negotiate_pool (rtpvrawdepay, caps, &rtpvrawdepay->vinfo); gst_caps_unref (caps); } ret = gst_buffer_pool_acquire_buffer (rtpvrawdepay->pool, &new_buffer, NULL); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto alloc_failed; /* clear timestamp from alloc... */ GST_BUFFER_TIMESTAMP (new_buffer) = -1; if (!gst_video_frame_map (&rtpvrawdepay->frame, &rtpvrawdepay->vinfo, new_buffer, GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)) { gst_buffer_unref (new_buffer); goto invalid_frame; } rtpvrawdepay->outbuf = new_buffer; rtpvrawdepay->timestamp = timestamp; } frame = &rtpvrawdepay->frame; g_assert (frame->buffer != NULL); /* get pointer and strides of the planes */ p0 = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); yp = GST_VIDEO_FRAME_COMP_DATA (frame, 0); up = GST_VIDEO_FRAME_COMP_DATA (frame, 1); vp = GST_VIDEO_FRAME_COMP_DATA (frame, 2); ystride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0); uvstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 1); pgroup = rtpvrawdepay->pgroup; width = GST_VIDEO_INFO_WIDTH (&rtpvrawdepay->vinfo); height = GST_VIDEO_INFO_HEIGHT (&rtpvrawdepay->vinfo); xinc = rtpvrawdepay->xinc; yinc = rtpvrawdepay->yinc; payload = gst_rtp_buffer_get_payload (&rtp); payload_len = gst_rtp_buffer_get_payload_len (&rtp); if (payload_len < 3) goto short_packet; /* skip extended seqnum */ payload += 2; payload_len -= 2; /* remember header position */ headers = payload; /* find data start */ do { if (payload_len < 6) goto short_packet; cont = payload[4] & 0x80; payload += 6; payload_len -= 6; } while (cont); while (TRUE) { guint length, line, offs, plen; guint8 *datap; /* stop when we run out of data */ if (payload_len == 0) break; /* read length and cont. This should work because we iterated the headers * above. */ length = (headers[0] << 8) | headers[1]; line = ((headers[2] & 0x7f) << 8) | headers[3]; offs = ((headers[4] & 0x7f) << 8) | headers[5]; cont = headers[4] & 0x80; headers += 6; /* length must be a multiple of pgroup */ if (length % pgroup != 0) goto wrong_length; if (length > payload_len) length = payload_len; /* sanity check */ if (line > (height - yinc)) { GST_WARNING_OBJECT (depayload, "skipping line %d: out of range", line); goto next; } if (offs > (width - xinc)) { GST_WARNING_OBJECT (depayload, "skipping offset %d: out of range", offs); goto next; } /* calculate the maximim amount of bytes we can use per line */ if (offs + ((length / pgroup) * xinc) > width) { plen = ((width - offs) * pgroup) / xinc; GST_WARNING_OBJECT (depayload, "clipping length %d, offset %d, plen %d", length, offs, plen); } else plen = length; GST_LOG_OBJECT (depayload, "writing length %u/%u, line %u, offset %u, remaining %u", plen, length, line, offs, payload_len); switch (GST_VIDEO_INFO_FORMAT (&rtpvrawdepay->vinfo)) { case GST_VIDEO_FORMAT_RGB: case GST_VIDEO_FORMAT_RGBA: case GST_VIDEO_FORMAT_BGR: case GST_VIDEO_FORMAT_BGRA: case GST_VIDEO_FORMAT_UYVY: case GST_VIDEO_FORMAT_UYVP: /* samples are packed just like gstreamer packs them */ offs /= xinc; datap = p0 + (line * ystride) + (offs * pgroup); memcpy (datap, payload, plen); break; case GST_VIDEO_FORMAT_AYUV: { gint i; guint8 *p; datap = p0 + (line * ystride) + (offs * 4); p = payload; /* samples are packed in order Cb-Y-Cr for both interlaced and * progressive frames */ for (i = 0; i < plen; i += pgroup) { *datap++ = 0; *datap++ = p[1]; *datap++ = p[0]; *datap++ = p[2]; p += pgroup; } break; } case GST_VIDEO_FORMAT_I420: { gint i; guint uvoff; guint8 *yd1p, *yd2p, *udp, *vdp, *p; yd1p = yp + (line * ystride) + (offs); yd2p = yd1p + ystride; uvoff = (line / yinc * uvstride) + (offs / xinc); udp = up + uvoff; vdp = vp + uvoff; p = payload; /* line 0/1: Y00-Y01-Y10-Y11-Cb00-Cr00 Y02-Y03-Y12-Y13-Cb01-Cr01 ... */ for (i = 0; i < plen; i += pgroup) { *yd1p++ = p[0]; *yd1p++ = p[1]; *yd2p++ = p[2]; *yd2p++ = p[3]; *udp++ = p[4]; *vdp++ = p[5]; p += pgroup; } break; } case GST_VIDEO_FORMAT_Y41B: { gint i; guint uvoff; guint8 *ydp, *udp, *vdp, *p; ydp = yp + (line * ystride) + (offs); uvoff = (line / yinc * uvstride) + (offs / xinc); udp = up + uvoff; vdp = vp + uvoff; p = payload; /* Samples are packed in order Cb0-Y0-Y1-Cr0-Y2-Y3 for both interlaced * and progressive scan lines */ for (i = 0; i < plen; i += pgroup) { *udp++ = p[0]; *ydp++ = p[1]; *ydp++ = p[2]; *vdp++ = p[3]; *ydp++ = p[4]; *ydp++ = p[5]; p += pgroup; } break; } default: goto unknown_sampling; } next: if (!cont) break; payload += length; payload_len -= length; } marker = gst_rtp_buffer_get_marker (&rtp); gst_rtp_buffer_unmap (&rtp); if (marker) { GST_LOG_OBJECT (depayload, "marker, flushing frame"); gst_video_frame_unmap (&rtpvrawdepay->frame); outbuf = rtpvrawdepay->outbuf; rtpvrawdepay->outbuf = NULL; rtpvrawdepay->timestamp = -1; } return outbuf; /* ERRORS */ unknown_sampling: { GST_ELEMENT_ERROR (depayload, STREAM, FORMAT, (NULL), ("unimplemented sampling")); gst_rtp_buffer_unmap (&rtp); return NULL; } alloc_failed: { GST_WARNING_OBJECT (depayload, "failed to alloc output buffer"); gst_rtp_buffer_unmap (&rtp); return NULL; } invalid_frame: { GST_ERROR_OBJECT (depayload, "could not map video frame"); return NULL; } wrong_length: { GST_WARNING_OBJECT (depayload, "length not multiple of pgroup"); gst_rtp_buffer_unmap (&rtp); return NULL; } short_packet: { GST_WARNING_OBJECT (depayload, "short packet"); gst_rtp_buffer_unmap (&rtp); return NULL; } }
static gboolean gst_rtp_vraw_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) { GstStructure *structure; GstRtpVRawDepay *rtpvrawdepay; gint clock_rate; const gchar *str; gint format, width, height, depth, pgroup, xinc, yinc; GstCaps *srccaps; gboolean res; GstFlowReturn ret; rtpvrawdepay = GST_RTP_VRAW_DEPAY (depayload); structure = gst_caps_get_structure (caps, 0); xinc = yinc = 1; if (!gst_structure_get_int (structure, "clock-rate", &clock_rate)) clock_rate = 90000; /* default */ depayload->clock_rate = clock_rate; if (!(str = gst_structure_get_string (structure, "width"))) goto no_width; width = atoi (str); if (!(str = gst_structure_get_string (structure, "height"))) goto no_height; height = atoi (str); if (!(str = gst_structure_get_string (structure, "depth"))) goto no_depth; depth = atoi (str); /* optional interlace value but we don't handle interlaced * formats yet */ if (gst_structure_get_string (structure, "interlace")) goto interlaced; if (!(str = gst_structure_get_string (structure, "sampling"))) goto no_sampling; if (!strcmp (str, "RGB")) { format = GST_VIDEO_FORMAT_RGB; pgroup = 3; } else if (!strcmp (str, "RGBA")) { format = GST_VIDEO_FORMAT_RGBA; pgroup = 4; } else if (!strcmp (str, "BGR")) { format = GST_VIDEO_FORMAT_BGR; pgroup = 3; } else if (!strcmp (str, "BGRA")) { format = GST_VIDEO_FORMAT_BGRA; pgroup = 4; } else if (!strcmp (str, "YCbCr-4:4:4")) { format = GST_VIDEO_FORMAT_AYUV; pgroup = 3; } else if (!strcmp (str, "YCbCr-4:2:2")) { if (depth == 8) { format = GST_VIDEO_FORMAT_UYVY; pgroup = 4; } else if (depth == 10) { format = GST_VIDEO_FORMAT_UYVP; pgroup = 5; } else goto unknown_format; xinc = 2; } else if (!strcmp (str, "YCbCr-4:2:0")) { format = GST_VIDEO_FORMAT_I420; pgroup = 6; xinc = yinc = 2; } else if (!strcmp (str, "YCbCr-4:1:1")) { format = GST_VIDEO_FORMAT_Y41B; pgroup = 6; xinc = 4; } else { goto unknown_format; } gst_video_info_init (&rtpvrawdepay->vinfo); gst_video_info_set_format (&rtpvrawdepay->vinfo, format, width, height); GST_VIDEO_INFO_FPS_N (&rtpvrawdepay->vinfo) = 0; GST_VIDEO_INFO_FPS_D (&rtpvrawdepay->vinfo) = 1; rtpvrawdepay->pgroup = pgroup; rtpvrawdepay->xinc = xinc; rtpvrawdepay->yinc = yinc; srccaps = gst_video_info_to_caps (&rtpvrawdepay->vinfo); res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps); gst_caps_unref (srccaps); GST_DEBUG_OBJECT (depayload, "width %d, height %d, format %d", width, height, format); GST_DEBUG_OBJECT (depayload, "xinc %d, yinc %d, pgroup %d", xinc, yinc, pgroup); /* negotiate a bufferpool */ if ((ret = gst_rtp_vraw_depay_negotiate_pool (rtpvrawdepay, srccaps, &rtpvrawdepay->vinfo)) != GST_FLOW_OK) goto no_bufferpool; return res; /* ERRORS */ no_width: { GST_ERROR_OBJECT (depayload, "no width specified"); return FALSE; } no_height: { GST_ERROR_OBJECT (depayload, "no height specified"); return FALSE; } no_depth: { GST_ERROR_OBJECT (depayload, "no depth specified"); return FALSE; } interlaced: { GST_ERROR_OBJECT (depayload, "interlaced formats not supported yet"); return FALSE; } no_sampling: { GST_ERROR_OBJECT (depayload, "no sampling specified"); return FALSE; } unknown_format: { GST_ERROR_OBJECT (depayload, "unknown sampling format '%s'", str); return FALSE; } no_bufferpool: { GST_DEBUG_OBJECT (depayload, "no bufferpool"); return FALSE; } }
static GstBuffer * gst_rtp_qdm2_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstRtpQDM2Depay *rtpqdm2depay; GstBuffer *outbuf = NULL; guint16 seq; GstRTPBuffer rtp = { NULL }; rtpqdm2depay = GST_RTP_QDM2_DEPAY (depayload); { gint payload_len; guint8 *payload; guint avail; guint pos = 0; gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); payload_len = gst_rtp_buffer_get_payload_len (&rtp); if (payload_len < 3) goto bad_packet; payload = gst_rtp_buffer_get_payload (&rtp); seq = gst_rtp_buffer_get_seq (&rtp); if (G_UNLIKELY (seq != rtpqdm2depay->nextseq)) { GST_DEBUG ("GAP in sequence number, Resetting data !"); /* Flush previous data */ flush_data (rtpqdm2depay); /* And store new timestamp */ rtpqdm2depay->ptimestamp = rtpqdm2depay->timestamp; rtpqdm2depay->timestamp = GST_BUFFER_TIMESTAMP (buf); /* And that previous data will be pushed at the bottom */ } rtpqdm2depay->nextseq = seq + 1; GST_DEBUG ("Payload size %d 0x%x sequence:%d", payload_len, payload_len, seq); GST_MEMDUMP ("Incoming payload", payload, payload_len); while (pos < payload_len) { switch (payload[pos]) { case 0x80:{ GST_DEBUG ("Unrecognized 0x80 marker, skipping 12 bytes"); pos += 12; } break; case 0xff: /* HEADERS */ GST_DEBUG ("Headers"); /* Store the incoming timestamp */ rtpqdm2depay->ptimestamp = rtpqdm2depay->timestamp; rtpqdm2depay->timestamp = GST_BUFFER_TIMESTAMP (buf); /* flush the internal data if needed */ flush_data (rtpqdm2depay); if (G_UNLIKELY (!rtpqdm2depay->configured)) { guint8 *ourdata; GstBuffer *codecdata; GstMapInfo cmap; GstCaps *caps; /* First bytes are unknown */ GST_MEMDUMP ("Header", payload + pos, 32); ourdata = payload + pos + 10; pos += 10; rtpqdm2depay->channs = GST_READ_UINT32_BE (payload + pos + 4); rtpqdm2depay->samplerate = GST_READ_UINT32_BE (payload + pos + 8); rtpqdm2depay->bitrate = GST_READ_UINT32_BE (payload + pos + 12); rtpqdm2depay->blocksize = GST_READ_UINT32_BE (payload + pos + 16); rtpqdm2depay->framesize = GST_READ_UINT32_BE (payload + pos + 20); rtpqdm2depay->packetsize = GST_READ_UINT32_BE (payload + pos + 24); /* 16 bit empty block (0x02 0x00) */ pos += 30; GST_DEBUG ("channs:%d, samplerate:%d, bitrate:%d, blocksize:%d, framesize:%d, packetsize:%d", rtpqdm2depay->channs, rtpqdm2depay->samplerate, rtpqdm2depay->bitrate, rtpqdm2depay->blocksize, rtpqdm2depay->framesize, rtpqdm2depay->packetsize); /* Caps */ codecdata = gst_buffer_new_and_alloc (48); gst_buffer_map (codecdata, &cmap, GST_MAP_WRITE); memcpy (cmap.data, headheader, 20); memcpy (cmap.data + 20, ourdata, 28); gst_buffer_unmap (codecdata, &cmap); caps = gst_caps_new_simple ("audio/x-qdm2", "samplesize", G_TYPE_INT, 16, "rate", G_TYPE_INT, rtpqdm2depay->samplerate, "channels", G_TYPE_INT, rtpqdm2depay->channs, "codec_data", GST_TYPE_BUFFER, codecdata, NULL); gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), caps); gst_caps_unref (caps); rtpqdm2depay->configured = TRUE; } else { GST_DEBUG ("Already configured, skipping headers"); pos += 40; } break; default:{ /* Shuffled packet contents */ guint packetid = payload[pos++]; guint packettype = payload[pos++]; guint packlen = payload[pos++]; guint hsize = 2; GST_DEBUG ("Packet id:%d, type:0x%x, len:%d", packetid, packettype, packlen); /* Packets bigger than 0xff bytes have a type with the high bit set */ if (G_UNLIKELY (packettype & 0x80)) { packettype &= 0x7f; packlen <<= 8; packlen |= payload[pos++]; hsize = 3; GST_DEBUG ("Packet id:%d, type:0x%x, len:%d", packetid, packettype, packlen); } if (packettype > 0x7f) { GST_ERROR ("HOUSTON WE HAVE A PROBLEM !!!!"); } add_packet (rtpqdm2depay, packetid, packlen + hsize, payload + pos - hsize); pos += packlen; } } } GST_DEBUG ("final pos %d", pos); avail = gst_adapter_available (rtpqdm2depay->adapter); if (G_UNLIKELY (avail)) { GST_DEBUG ("Pushing out %d bytes of collected data", avail); outbuf = gst_adapter_take_buffer (rtpqdm2depay->adapter, avail); GST_BUFFER_TIMESTAMP (outbuf) = rtpqdm2depay->ptimestamp; GST_DEBUG ("Outgoing buffer timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (rtpqdm2depay->ptimestamp)); } } gst_rtp_buffer_unmap (&rtp); return outbuf; /* ERRORS */ bad_packet: { GST_ELEMENT_WARNING (rtpqdm2depay, STREAM, DECODE, (NULL), ("Packet was too short")); gst_rtp_buffer_unmap (&rtp); return NULL; } }
static GstBuffer * gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp) { GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay); GstBuffer *payload; guint8 *data; guint hdrsize; guint size; if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (rtp->buffer))) { GST_LOG_OBJECT (self, "Discontinuity, flushing adapter"); gst_adapter_clear (self->adapter); self->started = FALSE; } size = gst_rtp_buffer_get_payload_len (rtp); /* At least one header and one vp8 byte */ if (G_UNLIKELY (size < 2)) goto too_small; data = gst_rtp_buffer_get_payload (rtp); if (G_UNLIKELY (!self->started)) { /* Check if this is the start of a VP8 frame, otherwise bail */ /* S=1 and PartID= 0 */ if ((data[0] & 0x17) != 0x10) goto done; self->started = TRUE; } hdrsize = 1; /* Check X optional header */ if ((data[0] & 0x80) != 0) { hdrsize++; /* Check I optional header */ if ((data[1] & 0x80) != 0) { if (G_UNLIKELY (size < 3)) goto too_small; hdrsize++; /* Check for 16 bits PictureID */ if ((data[2] & 0x80) != 0) hdrsize++; } /* Check L optional header */ if ((data[1] & 0x40) != 0) hdrsize++; /* Check T or K optional headers */ if ((data[1] & 0x20) != 0 || (data[1] & 0x10) != 0) hdrsize++; } GST_DEBUG_OBJECT (depay, "hdrsize %u, size %u", hdrsize, size); if (G_UNLIKELY (hdrsize >= size)) goto too_small; payload = gst_rtp_buffer_get_payload_subbuffer (rtp, hdrsize, -1); gst_adapter_push (self->adapter, payload); /* Marker indicates that it was the last rtp packet for this frame */ if (gst_rtp_buffer_get_marker (rtp)) { GstBuffer *out; guint8 header[10]; gst_adapter_copy (self->adapter, &header, 0, 10); out = gst_adapter_take_buffer (self->adapter, gst_adapter_available (self->adapter)); self->started = FALSE; /* mark keyframes */ out = gst_buffer_make_writable (out); if ((header[0] & 0x01)) { GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT); if (!self->caps_sent) { gst_buffer_unref (out); out = NULL; GST_INFO_OBJECT (self, "Dropping inter-frame before intra-frame"); gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depay), gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE, TRUE, 0)); } } else { guint profile, width, height; GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT); profile = (header[0] & 0x0e) >> 1; width = GST_READ_UINT16_LE (header + 6) & 0x3fff; height = GST_READ_UINT16_LE (header + 8) & 0x3fff; if (G_UNLIKELY (self->last_width != width || self->last_height != height || self->last_profile != profile)) { gchar profile_str[3]; GstCaps *srccaps; snprintf (profile_str, 3, "%u", profile); srccaps = gst_caps_new_simple ("video/x-vp8", "framerate", GST_TYPE_FRACTION, 0, 1, "height", G_TYPE_INT, height, "width", G_TYPE_INT, width, "profile", G_TYPE_STRING, profile_str, NULL); gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), srccaps); gst_caps_unref (srccaps); self->caps_sent = TRUE; self->last_width = width; self->last_height = height; self->last_profile = profile; } } return out; } done: return NULL; too_small: GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring"); gst_adapter_clear (self->adapter); self->started = FALSE; goto done; }
static gboolean gst_rtp_amr_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) { GstStructure *structure; GstCaps *srccaps; GstRtpAMRDepay *rtpamrdepay; const gchar *params; const gchar *str, *type; gint clock_rate, need_clock_rate; gboolean res; rtpamrdepay = GST_RTP_AMR_DEPAY (depayload); structure = gst_caps_get_structure (caps, 0); /* figure out the mode first and set the clock rates */ if ((str = gst_structure_get_string (structure, "encoding-name"))) { if (strcmp (str, "AMR") == 0) { rtpamrdepay->mode = GST_RTP_AMR_DP_MODE_NB; need_clock_rate = 8000; type = "audio/AMR"; } else if (strcmp (str, "AMR-WB") == 0) { rtpamrdepay->mode = GST_RTP_AMR_DP_MODE_WB; need_clock_rate = 16000; type = "audio/AMR-WB"; } else goto invalid_mode; } else goto invalid_mode; if (!(str = gst_structure_get_string (structure, "octet-align"))) rtpamrdepay->octet_align = FALSE; else rtpamrdepay->octet_align = (atoi (str) == 1); if (!(str = gst_structure_get_string (structure, "crc"))) rtpamrdepay->crc = FALSE; else rtpamrdepay->crc = (atoi (str) == 1); if (rtpamrdepay->crc) { /* crc mode implies octet aligned mode */ rtpamrdepay->octet_align = TRUE; } if (!(str = gst_structure_get_string (structure, "robust-sorting"))) rtpamrdepay->robust_sorting = FALSE; else rtpamrdepay->robust_sorting = (atoi (str) == 1); if (rtpamrdepay->robust_sorting) { /* robust_sorting mode implies octet aligned mode */ rtpamrdepay->octet_align = TRUE; } if (!(str = gst_structure_get_string (structure, "interleaving"))) rtpamrdepay->interleaving = FALSE; else rtpamrdepay->interleaving = (atoi (str) == 1); if (rtpamrdepay->interleaving) { /* interleaving mode implies octet aligned mode */ rtpamrdepay->octet_align = TRUE; } if (!(params = gst_structure_get_string (structure, "encoding-params"))) rtpamrdepay->channels = 1; else { rtpamrdepay->channels = atoi (params); } if (!gst_structure_get_int (structure, "clock-rate", &clock_rate)) clock_rate = need_clock_rate; depayload->clock_rate = clock_rate; /* we require 1 channel, 8000 Hz, octet aligned, no CRC, * no robust sorting, no interleaving for now */ if (rtpamrdepay->channels != 1) return FALSE; if (clock_rate != need_clock_rate) return FALSE; if (rtpamrdepay->octet_align != TRUE) return FALSE; if (rtpamrdepay->robust_sorting != FALSE) return FALSE; if (rtpamrdepay->interleaving != FALSE) return FALSE; srccaps = gst_caps_new_simple (type, "channels", G_TYPE_INT, rtpamrdepay->channels, "rate", G_TYPE_INT, clock_rate, NULL); res = gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depayload), srccaps); gst_caps_unref (srccaps); return res; /* ERRORS */ invalid_mode: { GST_ERROR_OBJECT (rtpamrdepay, "invalid encoding-name"); return FALSE; } }