static GstBuffer * gst_rtp_mp2t_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpMP2TDepay *rtpmp2tdepay; GstBuffer *outbuf; gint payload_len; rtpmp2tdepay = GST_RTP_MP2T_DEPAY (depayload); payload_len = gst_rtp_buffer_get_payload_len (buf); if (G_UNLIKELY (payload_len <= rtpmp2tdepay->skip_first_bytes)) goto empty_packet; outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, rtpmp2tdepay->skip_first_bytes, -1); if (outbuf) GST_DEBUG ("gst_rtp_mp2t_depay_chain: pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpmp2tdepay, STREAM, DECODE, (NULL), ("Packet was empty")); return NULL; } }
EXPORT_C #endif GstBuffer * gst_rtp_buffer_get_payload_buffer (GstBuffer * buffer) { return gst_rtp_buffer_get_payload_subbuffer (buffer, 0, -1); }
static GstBuffer * gst_rtp_mpa_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpMPADepay *rtpmpadepay; GstBuffer *outbuf; rtpmpadepay = GST_RTP_MPA_DEPAY (depayload); { gint payload_len; gboolean marker; payload_len = gst_rtp_buffer_get_payload_len (buf); if (payload_len <= 4) goto empty_packet; /* strip off header * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MBZ | Frag_offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ /* frag_offset = (payload[2] << 8) | payload[3]; */ /* subbuffer skipping the 4 header bytes */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 4, -1); marker = gst_rtp_buffer_get_marker (buf); if (marker) { /* mark start of talkspurt with discont */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } GST_DEBUG_OBJECT (rtpmpadepay, "gst_rtp_mpa_depay_chain: pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); /* FIXME, we can push half mpeg frames when they are split over multiple * RTP packets */ return outbuf; } return NULL; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpmpadepay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } }
static GstBuffer * gst_rtp_ac3_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpAC3Depay *rtpac3depay; GstBuffer *outbuf; rtpac3depay = GST_RTP_AC3_DEPAY (depayload); { guint8 *payload; guint16 FT, NF; if (gst_rtp_buffer_get_payload_len (buf) < 2) goto empty_packet; payload = gst_rtp_buffer_get_payload (buf); /* strip off header * * 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MBZ | FT| NF | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ FT = payload[0] & 0x3; NF = payload[1]; GST_DEBUG_OBJECT (rtpac3depay, "FT: %d, NF: %d", FT, NF); /* We don't bother with fragmented packets yet */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1); GST_DEBUG_OBJECT (rtpac3depay, "pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); return outbuf; } return NULL; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpac3depay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } }
static GstBuffer * gst_rtp_celt_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstBuffer *outbuf = NULL; guint8 *payload; guint offset, pos, payload_len, total_size, size; guint8 s; GST_DEBUG ("process : got %d bytes, mark %d ts %u seqn %d", GST_BUFFER_SIZE (buf), gst_rtp_buffer_get_marker (buf), gst_rtp_buffer_get_timestamp (buf), gst_rtp_buffer_get_seq (buf)); payload = gst_rtp_buffer_get_payload (buf); payload_len = gst_rtp_buffer_get_payload_len (buf); /* first count how many bytes are consumed by the size headers and make offset * point to the first data byte */ total_size = 0; offset = 0; while (total_size < payload_len) { size = 0; do { s = payload[offset++]; total_size += s + 1; } while (s == 0xff); } /* offset is now pointing to the payload */ total_size = 0; pos = 0; while (total_size < payload_len) { size = 0; do { s = payload[pos++]; size += s; total_size += size + 1; } while (s == 0xff); outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, offset, size); offset += size; gst_base_rtp_depayload_push (depayload, outbuf); } return NULL; }
static GstBuffer * gst_rtp_mpv_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpMPVDepay *rtpmpvdepay; GstBuffer *outbuf; rtpmpvdepay = GST_RTP_MPV_DEPAY (depayload); { gint payload_len, payload_header; guint8 *payload; guint8 T; payload_len = gst_rtp_buffer_get_payload_len (buf); payload = gst_rtp_buffer_get_payload (buf); payload_header = 0; if (payload_len <= 4) goto empty_packet; /* 3.4 MPEG Video-specific header * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MBZ |T| TR | |N|S|B|E| P | | BFC | | FFC | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * AN FBV FFV */ T = (payload[0] & 0x04); payload_len -= 4; payload_header += 4; payload += 4; if (T) { /* * 3.4.1 MPEG-2 Video-specific header extension * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |X|E|f_[0,0]|f_[0,1]|f_[1,0]|f_[1,1]| DC| PS|T|P|C|Q|V|A|R|H|G|D| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ if (payload_len <= 4) goto empty_packet; payload_len -= 4; payload_header += 4; payload += 4; } outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, payload_header, -1); GST_DEBUG_OBJECT (rtpmpvdepay, "gst_rtp_mpv_depay_chain: pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); return outbuf; } return NULL; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpmpvdepay, STREAM, DECODE, (NULL), ("Empty payload.")); return NULL; } }
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_mpa_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstRtpMPADepay *rtpmpadepay; GstBuffer *outbuf; GstRTPBuffer rtp = { NULL }; gint payload_len; #if 0 guint8 *payload; guint16 frag_offset; #endif gboolean marker; rtpmpadepay = GST_RTP_MPA_DEPAY (depayload); gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); payload_len = gst_rtp_buffer_get_payload_len (&rtp); if (payload_len <= 4) goto empty_packet; #if 0 payload = gst_rtp_buffer_get_payload (&rtp); /* strip off header * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MBZ | Frag_offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ frag_offset = (payload[2] << 8) | payload[3]; #endif /* subbuffer skipping the 4 header bytes */ outbuf = gst_rtp_buffer_get_payload_subbuffer (&rtp, 4, -1); marker = gst_rtp_buffer_get_marker (&rtp); if (marker) { /* mark start of talkspurt with RESYNC */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC); } GST_DEBUG_OBJECT (rtpmpadepay, "gst_rtp_mpa_depay_chain: pushing buffer of size %" G_GSIZE_FORMAT "", gst_buffer_get_size (outbuf)); gst_rtp_buffer_unmap (&rtp); /* FIXME, we can push half mpeg frames when they are split over multiple * RTP packets */ return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpmpadepay, STREAM, DECODE, ("Empty Payload."), (NULL)); gst_rtp_buffer_unmap (&rtp); return NULL; } }
static GstBuffer * gst_rtp_mpv_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstRtpMPVDepay *rtpmpvdepay; GstBuffer *outbuf = NULL; rtpmpvdepay = GST_RTP_MPV_DEPAY (depayload); { gint payload_len, payload_header; guint8 *payload; guint8 T; payload_len = gst_rtp_buffer_get_payload_len (rtp); payload = gst_rtp_buffer_get_payload (rtp); payload_header = 0; if (payload_len <= 4) goto empty_packet; /* 3.4 MPEG Video-specific header * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MBZ |T| TR | |N|S|B|E| P | | BFC | | FFC | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * AN FBV FFV */ T = (payload[0] & 0x04); payload_len -= 4; payload_header += 4; payload += 4; if (T) { /* * 3.4.1 MPEG-2 Video-specific header extension * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |X|E|f_[0,0]|f_[0,1]|f_[1,0]|f_[1,1]| DC| PS|T|P|C|Q|V|A|R|H|G|D| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ if (payload_len <= 4) goto empty_packet; payload_len -= 4; payload_header += 4; payload += 4; } outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, payload_header, -1); if (outbuf) { GST_DEBUG_OBJECT (rtpmpvdepay, "gst_rtp_mpv_depay_chain: pushing buffer of size %" G_GSIZE_FORMAT, gst_buffer_get_size (outbuf)); gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpmpvdepay), outbuf, g_quark_from_static_string (GST_META_TAG_VIDEO_STR)); } } return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpmpvdepay, STREAM, DECODE, (NULL), ("Empty payload.")); return NULL; } }
static GstBuffer * gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstRtpJPEGDepay *rtpjpegdepay; GstBuffer *outbuf; gint payload_len, header_len; guint8 *payload; guint frag_offset; gint Q; guint type, width, height; guint16 dri, precision, length; guint8 *qtable; rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload); if (GST_BUFFER_IS_DISCONT (rtp->buffer)) { GST_DEBUG_OBJECT (depayload, "DISCONT, reset adapter"); gst_adapter_clear (rtpjpegdepay->adapter); rtpjpegdepay->discont = TRUE; } payload_len = gst_rtp_buffer_get_payload_len (rtp); if (payload_len < 8) goto empty_packet; payload = gst_rtp_buffer_get_payload (rtp); header_len = 0; /* 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type-specific | Fragment Offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type | Q | Width | Height | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3]; type = payload[4]; Q = payload[5]; width = payload[6] * 8; height = payload[7] * 8; /* saw a packet with fragment offset > 0 and we don't already have data queued * up (most importantly, we don't have a header for this data) -- drop it * XXX: maybe we can check if the jpeg is progressive and salvage the data? * XXX: not implemented yet because jpegenc can't create progressive jpegs */ if (frag_offset > 0 && gst_adapter_available (rtpjpegdepay->adapter) == 0) goto no_header_packet; /* allow frame dimensions > 2040, passed in SDP session or media attributes * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */ if (!width) width = rtpjpegdepay->media_width; if (!height) height = rtpjpegdepay->media_height; if (width == 0 || height == 0) goto invalid_dimension; GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u", frag_offset, type, Q, width, height); header_len += 8; payload += 8; payload_len -= 8; dri = 0; if (type > 63) { if (payload_len < 4) goto empty_packet; /* 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Restart Interval |F|L| Restart Count | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ dri = (payload[0] << 8) | payload[1]; GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri); payload += 4; header_len += 4; payload_len -= 4; } if (Q >= 128 && frag_offset == 0) { if (payload_len < 4) goto empty_packet; /* 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MBZ | Precision | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Quantization Table Data | * | ... | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ precision = payload[1]; length = (payload[2] << 8) | payload[3]; GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT, precision, length); if (Q == 255 && length == 0) goto empty_packet; payload += 4; header_len += 4; payload_len -= 4; if (length > payload_len) goto empty_packet; if (length > 0) qtable = payload; else qtable = rtpjpegdepay->qtables[Q]; payload += length; header_len += length; payload_len -= length; } else { length = 0; qtable = NULL; precision = 0; } if (frag_offset == 0) { GstMapInfo map; guint size; if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) { GstCaps *outcaps; outcaps = gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION, rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); gst_pad_set_caps (depayload->srcpad, outcaps); gst_caps_unref (outcaps); rtpjpegdepay->width = width; rtpjpegdepay->height = height; } GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT, length); /* first packet */ if (length == 0) { if (Q < 128) { /* no quant table, see if we have one cached */ qtable = rtpjpegdepay->qtables[Q]; if (!qtable) { GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q); /* make and cache the table */ qtable = g_new (guint8, 128); MakeTables (rtpjpegdepay, Q, qtable); rtpjpegdepay->qtables[Q] = qtable; } else { GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q); } /* all 8 bit quantizers */ precision = 0; } else { if (!qtable) goto no_qtable; } } /* I think we can get here with a NULL qtable, so make sure we don't go dereferencing it in MakeHeaders if we do */ if (!qtable) goto no_qtable; /* max header length, should be big enough */ outbuf = gst_buffer_new_and_alloc (1000); gst_buffer_map (outbuf, &map, GST_MAP_WRITE); size = MakeHeaders (map.data, type, width, height, qtable, precision, dri); gst_buffer_unmap (outbuf, &map); gst_buffer_resize (outbuf, 0, size); GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size); gst_adapter_push (rtpjpegdepay->adapter, outbuf); } /* take JPEG data, push in the adapter */ GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len); outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, -1); gst_adapter_push (rtpjpegdepay->adapter, outbuf); outbuf = NULL; if (gst_rtp_buffer_get_marker (rtp)) { guint avail; guint8 end[2]; GstMapInfo map; /* last buffer take all data out of the adapter */ avail = gst_adapter_available (rtpjpegdepay->adapter); GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer"); if (avail < 2) goto invalid_packet; /* take the last bytes of the jpeg data to see if there is an EOI * marker */ gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2); if (end[0] != 0xff && end[1] != 0xd9) { GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one"); /* no EOI marker, add one */ outbuf = gst_buffer_new_and_alloc (2); gst_buffer_map (outbuf, &map, GST_MAP_WRITE); map.data[0] = 0xff; map.data[1] = 0xd9; gst_buffer_unmap (outbuf, &map); gst_adapter_push (rtpjpegdepay->adapter, outbuf); avail += 2; } outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail); if (rtpjpegdepay->discont) { GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); rtpjpegdepay->discont = FALSE; } gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpjpegdepay), outbuf, g_quark_from_static_string (GST_META_TAG_VIDEO_STR)); GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail); } return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } invalid_dimension: { GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT, ("Invalid Dimension %dx%d.", width, height), (NULL)); return NULL; } no_qtable: { GST_WARNING_OBJECT (rtpjpegdepay, "no qtable"); return NULL; } invalid_packet: { GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet"); gst_adapter_flush (rtpjpegdepay->adapter, gst_adapter_available (rtpjpegdepay->adapter)); return NULL; } no_header_packet: { GST_WARNING_OBJECT (rtpjpegdepay, "discarding data packets received when we have no header"); return NULL; } }
static GstBuffer * gst_rtp_j2k_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpJ2KDepay *rtpj2kdepay; GstBuffer *outbuf; guint8 *payload; guint frag_offset; rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload); /* flush everything on discont for now */ if (GST_BUFFER_IS_DISCONT (buf)) { GST_DEBUG_OBJECT (rtpj2kdepay, "DISCONT, flushing data"); gst_adapter_clear (rtpj2kdepay->adapter); rtpj2kdepay->need_header = TRUE; } if (gst_rtp_buffer_get_payload_len (buf) < 8) goto empty_packet; payload = gst_rtp_buffer_get_payload (buf); /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |tp |MHF|mh_id|T| priority | tile number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |reserved | fragment offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ frag_offset = (payload[5] << 16) | (payload[6] << 8) | payload[7]; GST_DEBUG_OBJECT (rtpj2kdepay, "frag %u", frag_offset); if (rtpj2kdepay->need_header) { if (frag_offset != 0) goto waiting_header; rtpj2kdepay->need_header = FALSE; } /* take JPEG 2000 data, push in the adapter */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 8, -1); gst_adapter_push (rtpj2kdepay->adapter, outbuf); outbuf = NULL; if (gst_rtp_buffer_get_marker (buf)) { guint avail; guint8 end[2]; guint8 *data; /* last buffer take all data out of the adapter */ avail = gst_adapter_available (rtpj2kdepay->adapter); GST_DEBUG_OBJECT (rtpj2kdepay, "marker set, last buffer"); /* take the last bytes of the JPEG 2000 data to see if there is an EOC * marker */ gst_adapter_copy (rtpj2kdepay->adapter, end, avail - 2, 2); if (end[0] != 0xff && end[1] != 0xd9) { GST_DEBUG_OBJECT (rtpj2kdepay, "no EOC marker, adding one"); /* no EOI marker, add one */ outbuf = gst_buffer_new_and_alloc (2); data = GST_BUFFER_DATA (outbuf); data[0] = 0xff; data[1] = 0xd9; gst_adapter_push (rtpj2kdepay->adapter, outbuf); avail += 2; } outbuf = gst_adapter_take_buffer (rtpj2kdepay->adapter, avail); GST_DEBUG_OBJECT (rtpj2kdepay, "returning %u bytes", avail); } return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } waiting_header: { GST_DEBUG_OBJECT (rtpj2kdepay, "we are waiting for a header"); 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 GstBuffer * gst_rtp_celt_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstBuffer *outbuf = NULL; guint8 *payload; guint offset, pos, payload_len, total_size, size; guint8 s; gint clock_rate = 0, frame_size = 0; GstClockTime framesize_ns = 0, timestamp; guint n = 0; GstRtpCELTDepay *rtpceltdepay; rtpceltdepay = GST_RTP_CELT_DEPAY (depayload); clock_rate = depayload->clock_rate; frame_size = rtpceltdepay->frame_size; framesize_ns = gst_util_uint64_scale_int (frame_size, GST_SECOND, clock_rate); timestamp = GST_BUFFER_PTS (rtp->buffer); GST_LOG_OBJECT (depayload, "got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d", gst_buffer_get_size (rtp->buffer), gst_rtp_buffer_get_marker (rtp), gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp)); GST_LOG_OBJECT (depayload, "got clock-rate=%d, frame_size=%d, " "_ns=%" GST_TIME_FORMAT ", timestamp=%" GST_TIME_FORMAT, clock_rate, frame_size, GST_TIME_ARGS (framesize_ns), GST_TIME_ARGS (timestamp)); payload = gst_rtp_buffer_get_payload (rtp); payload_len = gst_rtp_buffer_get_payload_len (rtp); /* first count how many bytes are consumed by the size headers and make offset * point to the first data byte */ total_size = 0; offset = 0; while (total_size < payload_len) { do { s = payload[offset++]; total_size += s + 1; } while (s == 0xff); } /* offset is now pointing to the payload */ total_size = 0; pos = 0; while (total_size < payload_len) { n++; size = 0; do { s = payload[pos++]; size += s; total_size += s + 1; } while (s == 0xff); outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, offset, size); offset += size; if (frame_size != -1 && clock_rate != -1) { GST_BUFFER_PTS (outbuf) = timestamp + framesize_ns * n; GST_BUFFER_DURATION (outbuf) = framesize_ns; } GST_LOG_OBJECT (depayload, "push timestamp=%" GST_TIME_FORMAT ", duration=%" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)), GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf))); gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); gst_rtp_base_depayload_push (depayload, outbuf); } return NULL; }
static GstBuffer * gst_rtp_jpeg_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpJPEGDepay *rtpjpegdepay; GstBuffer *outbuf; gint payload_len, header_len; guint8 *payload; guint frag_offset; gint Q; guint type, width, height; guint16 dri, precision, length; guint8 *qtable; rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload); if (GST_BUFFER_IS_DISCONT (buf)) { gst_adapter_clear (rtpjpegdepay->adapter); } payload_len = gst_rtp_buffer_get_payload_len (buf); if (payload_len < 8) goto empty_packet; payload = gst_rtp_buffer_get_payload (buf); header_len = 0; /* 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type-specific | Fragment Offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type | Q | Width | Height | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3]; type = payload[4]; Q = payload[5]; width = payload[6] * 8; height = payload[7] * 8; if (width == 0 || height == 0) goto invalid_dimension; GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u", frag_offset, type, Q, width, height); header_len += 8; payload += 8; payload_len -= 8; dri = 0; if (type > 63) { if (payload_len < 4) goto empty_packet; /* 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Restart Interval |F|L| Restart Count | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ dri = (payload[0] << 8) | payload[1]; GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri); payload += 4; header_len += 4; payload_len -= 4; } if (Q >= 128 && frag_offset == 0) { if (payload_len < 4) goto empty_packet; /* 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MBZ | Precision | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Quantization Table Data | * | ... | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ precision = payload[1]; length = (payload[2] << 8) | payload[3]; GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT, precision, length); if (Q == 255 && length == 0) goto empty_packet; payload += 4; header_len += 4; payload_len -= 4; if (length > payload_len) goto empty_packet; if (length > 0) qtable = payload; else qtable = rtpjpegdepay->qtables[Q]; payload += length; header_len += length; payload_len -= length; } else { length = 0; qtable = NULL; precision = 0; } if (frag_offset == 0) { guint size; if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) { GstCaps *outcaps; outcaps = gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION, 0, 1, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); gst_pad_set_caps (depayload->srcpad, outcaps); gst_caps_unref (outcaps); rtpjpegdepay->width = width; rtpjpegdepay->height = height; } GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT, length); /* first packet */ if (length == 0) { if (Q < 128) { /* no quant table, see if we have one cached */ qtable = rtpjpegdepay->qtables[Q]; if (!qtable) { GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q); /* make and cache the table */ qtable = g_new (guint8, 128); MakeTables (rtpjpegdepay, Q, qtable); rtpjpegdepay->qtables[Q] = qtable; } else { GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q); } /* all 8 bit quantizers */ precision = 0; } else { if (!qtable) goto no_qtable; } } /* max header length, should be big enough */ outbuf = gst_buffer_new_and_alloc (1000); size = MakeHeaders (GST_BUFFER_DATA (outbuf), type, width, height, qtable, precision, dri); GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size); GST_BUFFER_SIZE (outbuf) = size; gst_adapter_push (rtpjpegdepay->adapter, outbuf); } /* take JPEG data, push in the adapter */ GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len); outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, header_len, -1); gst_adapter_push (rtpjpegdepay->adapter, outbuf); outbuf = NULL; if (gst_rtp_buffer_get_marker (buf)) { guint avail; guint8 end[2]; guint8 *data; /* last buffer take all data out of the adapter */ avail = gst_adapter_available (rtpjpegdepay->adapter); GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer"); /* take the last bytes of the jpeg data to see if there is an EOI * marker */ gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2); if (end[0] != 0xff && end[1] != 0xd9) { GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one"); /* no EOI marker, add one */ outbuf = gst_buffer_new_and_alloc (2); data = GST_BUFFER_DATA (outbuf); data[0] = 0xff; data[1] = 0xd9; gst_adapter_push (rtpjpegdepay->adapter, outbuf); avail += 2; } outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail); GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail); } return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } invalid_dimension: { GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT, ("Invalid Dimension %dx%d.", width, height), (NULL)); return NULL; } no_qtable: { GST_WARNING_OBJECT (rtpjpegdepay, "no qtable"); return NULL; } }
static GstBuffer * gst_rtp_vp8_depay_process (GstBaseRTPDepayload * depay, GstBuffer * buf) { GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay); GstBuffer *payload; guint8 *data; guint offset; guint size = gst_rtp_buffer_get_payload_len (buf); if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) { GST_LOG_OBJECT (self, "Discontinuity, flushing adapter"); gst_adapter_clear (self->adapter); self->started = FALSE; } /* At least one header and one vp8 byte */ if (G_UNLIKELY (size < 2)) goto too_small; data = gst_rtp_buffer_get_payload (buf); if (G_UNLIKELY (!self->started)) { /* Check if this is the start of a VP8 frame, otherwise bail */ if ((data[0] & 0x1) == 0) return NULL; self->started = TRUE; } offset = 1; if ((data[0] & 0x10) != 0) { /* Skip Picture identifier bytes */ for (; (data[offset] & 0x80) != 0; offset++) { /* should be at least one more pictureID byte and at least one byte in * the vp8 payload */ if (G_UNLIKELY (offset + 2 >= size)) goto too_small; } offset++; } if (G_UNLIKELY (offset >= size)) goto too_small; payload = gst_rtp_buffer_get_payload_subbuffer (buf, offset, -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 (buf)) { GstBuffer *out; out = gst_adapter_take_buffer (self->adapter, gst_adapter_available (self->adapter)); self->started = FALSE; return out; } return NULL; too_small: GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring"); gst_adapter_clear (self->adapter); self->started = FALSE; return NULL; }
static GstBuffer * gst_rtp_qcelp_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstRtpQCELPDepay *depay; GstBuffer *outbuf; GstClockTime timestamp; guint payload_len, offset, index; guint8 *payload; guint LLL, NNN; depay = GST_RTP_QCELP_DEPAY (depayload); payload_len = gst_rtp_buffer_get_payload_len (rtp); if (payload_len < 2) goto too_small; timestamp = GST_BUFFER_PTS (rtp->buffer); payload = gst_rtp_buffer_get_payload (rtp); /* 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * |RR | LLL | NNN | * +-+-+-+-+-+-+-+-+ */ /* RR = payload[0] >> 6; */ LLL = (payload[0] & 0x38) >> 3; NNN = (payload[0] & 0x07); payload_len--; payload++; GST_DEBUG_OBJECT (depay, "LLL %u, NNN %u", LLL, NNN); if (LLL > 5) goto invalid_lll; if (NNN > LLL) goto invalid_nnn; if (LLL != 0) { /* we are interleaved */ if (!depay->interleaved) { guint size; GST_DEBUG_OBJECT (depay, "starting interleaving group"); /* bundling is not allowed to change in one interleave group */ depay->bundling = count_packets (depay, payload, payload_len); GST_DEBUG_OBJECT (depay, "got bundling of %u", depay->bundling); /* we have one bundle where NNN goes from 0 to L, we don't store the index * 0 frames, so L+1 packets. Each packet has 'bundling - 1' packets */ size = (depay->bundling - 1) * (LLL + 1); /* create the array to hold the packets */ if (depay->packets == NULL) depay->packets = g_ptr_array_sized_new (size); GST_DEBUG_OBJECT (depay, "created packet array of size %u", size); g_ptr_array_set_size (depay->packets, size); /* we were previously not interleaved, figure out how much space we * need to deinterleave */ depay->interleaved = TRUE; } } else { /* we are not interleaved */ if (depay->interleaved) { GST_DEBUG_OBJECT (depay, "stopping interleaving"); /* flush packets if we were previously interleaved */ flush_packets (depay); } depay->bundling = 0; } index = 0; offset = 1; while (payload_len > 0) { gint frame_len; gboolean do_erasure; frame_len = get_frame_len (depay, payload[0]); GST_DEBUG_OBJECT (depay, "got frame len %d", frame_len); if (frame_len == 0) goto invalid_frame; if (frame_len < 0) { /* need to add an erasure frame but we can recover */ frame_len = -frame_len; do_erasure = TRUE; } else { do_erasure = FALSE; } if (frame_len > payload_len) goto invalid_frame; if (do_erasure) { /* create erasure frame */ outbuf = create_erasure_buffer (depay); } else { /* each frame goes into its buffer */ outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, offset, frame_len); } GST_BUFFER_PTS (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = FRAME_DURATION; gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); if (!depay->interleaved || index == 0) { /* not interleaved or first frame in packet, just push */ gst_rtp_base_depayload_push (depayload, outbuf); if (timestamp != -1) timestamp += FRAME_DURATION; } else { /* put in interleave buffer */ add_packet (depay, LLL, NNN, index, outbuf); if (timestamp != -1) timestamp += (FRAME_DURATION * (LLL + 1)); } payload_len -= frame_len; payload += frame_len; offset += frame_len; index++; /* discard excess packets */ if (depay->bundling > 0 && depay->bundling <= index) break; } while (index < depay->bundling) { GST_DEBUG_OBJECT (depay, "filling with erasure buffer"); /* fill remainder with erasure packets */ outbuf = create_erasure_buffer (depay); add_packet (depay, LLL, NNN, index, outbuf); index++; } if (depay->interleaved && LLL == NNN) { GST_DEBUG_OBJECT (depay, "interleave group ended, flushing"); /* we have the complete interleave group, flush */ flush_packets (depay); } return NULL; /* ERRORS */ too_small: { GST_ELEMENT_WARNING (depay, STREAM, DECODE, (NULL), ("QCELP RTP payload too small (%d)", payload_len)); return NULL; } invalid_lll: { GST_ELEMENT_WARNING (depay, STREAM, DECODE, (NULL), ("QCELP RTP invalid LLL received (%d)", LLL)); return NULL; } invalid_nnn: { GST_ELEMENT_WARNING (depay, STREAM, DECODE, (NULL), ("QCELP RTP invalid NNN received (%d)", NNN)); return NULL; } invalid_frame: { GST_ELEMENT_WARNING (depay, STREAM, DECODE, (NULL), ("QCELP RTP invalid frame received")); return NULL; } }
static GstBuffer * gst_rtp_sv3v_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpSV3VDepay *rtpsv3vdepay; GstBuffer *outbuf; guint16 seq; rtpsv3vdepay = GST_RTP_SV3V_DEPAY (depayload); if (!gst_rtp_buffer_validate (buf)) goto bad_packet; /* flush on sequence number gaps */ seq = gst_rtp_buffer_get_seq (buf); if (seq != rtpsv3vdepay->nextseq) { gst_adapter_clear (rtpsv3vdepay->adapter); } rtpsv3vdepay->nextseq = seq + 1; { gint payload_len; guint8 *payload; gboolean M; gboolean C, S, E; payload_len = gst_rtp_buffer_get_payload_len (buf); if (payload_len < 3) goto bad_packet; payload = gst_rtp_buffer_get_payload (buf); M = gst_rtp_buffer_get_marker (buf); /* This is all a guess: * 1 1 1 1 1 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |0|C|S|E|0|0|0|0|0|0|0|0|0|0|0|0| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * C: config, packet contains config info * S: start, packet contains start of frame * E: end, packet contains end of frame */ /* this seems to indicate a packet with a config string sent before each * keyframe */ C = (payload[0] & 0x40) == 0x40; /* redundant with the RTP marker bit */ S = (payload[0] & 0x20) == 0x20; E = (payload[0] & 0x10) == 0x10; if (C) { GstCaps *caps; GstBuffer *codec_data; GValue value = { 0 }; /* if we already have caps, we don't need to do anything. FIXME, check if * something changed. */ if (GST_PAD_CAPS (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload))) return NULL; /* No idea... These are the two examples I found.. */ if (payload[2] == 0x1d) { rtpsv3vdepay->width = 160; rtpsv3vdepay->height = 128; } else if (payload[2] == 0xdd) { rtpsv3vdepay->width = 320; rtpsv3vdepay->height = 240; } /* we need a dummy empty codec data */ g_value_init (&value, GST_TYPE_BUFFER); gst_value_deserialize (&value, ""); codec_data = gst_value_get_buffer (&value); caps = gst_caps_new_simple ("video/x-svq", "svqversion", G_TYPE_INT, 3, "width", G_TYPE_INT, rtpsv3vdepay->width, "height", G_TYPE_INT, rtpsv3vdepay->height, "codec_data", GST_TYPE_BUFFER, codec_data, NULL); gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), caps); gst_caps_unref (caps); g_value_unset (&value); return NULL; } /* store data in adapter, stip off 2 bytes header */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1); gst_adapter_push (rtpsv3vdepay->adapter, outbuf); if (M) { /* frame is completed: push contents of adapter */ guint avail; avail = gst_adapter_available (rtpsv3vdepay->adapter); outbuf = gst_adapter_take_buffer (rtpsv3vdepay->adapter, avail); /* timestamp for complete buffer is that of last buffer as well */ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (depayload->srcpad)); return outbuf; } } return NULL; /* ERRORS */ bad_packet: { GST_ELEMENT_WARNING (rtpsv3vdepay, STREAM, DECODE, ("Packet did not validate"), (NULL)); return NULL; } }
static GstBuffer * gst_rtp_ac3_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpAC3Depay *rtpac3depay; GstBuffer *outbuf; rtpac3depay = GST_RTP_AC3_DEPAY (depayload); if (!gst_rtp_buffer_validate (buf)) goto bad_packet; { gint payload_len; guint8 *payload; guint16 FT, NF; payload_len = gst_rtp_buffer_get_payload_len (buf); payload = gst_rtp_buffer_get_payload (buf); if (payload_len <= 2) goto empty_packet; /* strip off header * * 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MBZ | FT| NF | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ FT = payload[0] & 0x3; NF = payload[1]; GST_DEBUG_OBJECT (rtpac3depay, "FT: %d, NF: %d", FT, NF); payload_len -= 2; payload += 2; /* We don't bother with fragmented packets yet */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1); GST_DEBUG_OBJECT (rtpac3depay, "pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); return outbuf; } return NULL; bad_packet: { GST_ELEMENT_WARNING (rtpac3depay, STREAM, DECODE, ("Packet did not validate."), (NULL)); return NULL; } #if 0 bad_payload: { GST_ELEMENT_WARNING (rtpac3depay, STREAM, DECODE, ("Unexpected payload type."), (NULL)); return NULL; } #endif empty_packet: { GST_ELEMENT_WARNING (rtpac3depay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } }
static GstBuffer * gst_rtp_j2k_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpJ2KDepay *rtpj2kdepay; guint8 *payload; guint MHF, mh_id, frag_offset, tile, payload_len, j2klen; gint gap; guint32 rtptime; rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload); payload = gst_rtp_buffer_get_payload (buf); payload_len = gst_rtp_buffer_get_payload_len (buf); /* we need at least a header */ if (payload_len < 8) goto empty_packet; rtptime = gst_rtp_buffer_get_timestamp (buf); /* new timestamp marks new frame */ if (rtpj2kdepay->last_rtptime != rtptime) { rtpj2kdepay->last_rtptime = rtptime; /* flush pending frame */ gst_rtp_j2k_depay_flush_frame (depayload); } /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |tp |MHF|mh_id|T| priority | tile number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |reserved | fragment offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ MHF = (payload[0] & 0x30) >> 4; mh_id = (payload[0] & 0xe) >> 1; if (rtpj2kdepay->last_mh_id == -1) rtpj2kdepay->last_mh_id = mh_id; else if (rtpj2kdepay->last_mh_id != mh_id) goto wrong_mh_id; tile = (payload[2] << 8) | payload[3]; frag_offset = (payload[5] << 16) | (payload[6] << 8) | payload[7]; j2klen = payload_len - 8; GST_DEBUG_OBJECT (rtpj2kdepay, "MHF %u, tile %u, frag %u, expected %u", MHF, tile, frag_offset, rtpj2kdepay->next_frag); /* calculate the gap between expected frag */ gap = frag_offset - rtpj2kdepay->next_frag; /* calculate next frag */ rtpj2kdepay->next_frag = frag_offset + j2klen; if (gap != 0) { GST_DEBUG_OBJECT (rtpj2kdepay, "discont of %d, clear PU", gap); /* discont, clear pu adapter and resync */ gst_rtp_j2k_depay_clear_pu (rtpj2kdepay); } /* check for sync code */ if (j2klen > 2 && payload[8] == 0xff) { guint marker = payload[9]; /* packets must start with SOC, SOT or SOP */ switch (marker) { case J2K_MARKER_SOC: GST_DEBUG_OBJECT (rtpj2kdepay, "found SOC packet"); /* flush the previous frame, should have happened when the timestamp * changed above. */ gst_rtp_j2k_depay_flush_frame (depayload); rtpj2kdepay->have_sync = TRUE; break; case J2K_MARKER_SOT: /* flush the previous tile */ gst_rtp_j2k_depay_flush_tile (depayload); GST_DEBUG_OBJECT (rtpj2kdepay, "found SOT packet"); rtpj2kdepay->have_sync = TRUE; /* we sync on the tile now */ rtpj2kdepay->last_tile = tile; break; case J2K_MARKER_SOP: GST_DEBUG_OBJECT (rtpj2kdepay, "found SOP packet"); /* flush the previous PU */ gst_rtp_j2k_depay_flush_pu (depayload); if (rtpj2kdepay->last_tile != tile) { /* wrong tile, we lose sync and we need a new SOT or SOC to regain * sync. First flush out the previous tile if we have one. */ if (rtpj2kdepay->last_tile != -1) gst_rtp_j2k_depay_flush_tile (depayload); /* now we have no more valid tile and no sync */ rtpj2kdepay->last_tile = -1; rtpj2kdepay->have_sync = FALSE; } else { rtpj2kdepay->have_sync = TRUE; } break; default: GST_DEBUG_OBJECT (rtpj2kdepay, "no sync packet 0x%02d", marker); break; } } if (rtpj2kdepay->have_sync) { GstBuffer *pu_frag; if (gst_adapter_available (rtpj2kdepay->pu_adapter) == 0) { /* first part of pu, record state */ GST_DEBUG_OBJECT (rtpj2kdepay, "first PU"); rtpj2kdepay->pu_MHF = MHF; } /* and push in pu adapter */ GST_DEBUG_OBJECT (rtpj2kdepay, "push pu of size %u in adapter", j2klen); pu_frag = gst_rtp_buffer_get_payload_subbuffer (buf, 8, -1); gst_adapter_push (rtpj2kdepay->pu_adapter, pu_frag); if (MHF & 2) { /* last part of main header received, we can flush it */ GST_DEBUG_OBJECT (rtpj2kdepay, "header end, flush pu"); gst_rtp_j2k_depay_flush_pu (depayload); } } else { GST_DEBUG_OBJECT (rtpj2kdepay, "discard packet, no sync"); } /* marker bit finishes the frame */ if (gst_rtp_buffer_get_marker (buf)) { GST_DEBUG_OBJECT (rtpj2kdepay, "marker set, last buffer"); /* then flush frame */ gst_rtp_j2k_depay_flush_frame (depayload); } return NULL; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } wrong_mh_id: { GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Invalid mh_id %u, expected %u", mh_id, rtpj2kdepay->last_mh_id), (NULL)); gst_rtp_j2k_depay_clear_pu (rtpj2kdepay); return NULL; } }
static GstBuffer * gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstBuffer * buf) { GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay); GstBuffer *payload; guint8 *data; guint hdrsize; guint size; GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) { GST_LOG_OBJECT (self, "Discontinuity, flushing adapter"); gst_adapter_clear (self->adapter); self->started = FALSE; } gst_rtp_buffer_map (buf, GST_MAP_READ, &rtpbuffer); size = gst_rtp_buffer_get_payload_len (&rtpbuffer); /* At least one header and one vp8 byte */ if (G_UNLIKELY (size < 2)) goto too_small; data = gst_rtp_buffer_get_payload (&rtpbuffer); 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] & 0x1F) != 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 (&rtpbuffer, 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 (&rtpbuffer)) { GstBuffer *out; guint8 flag0; gst_adapter_copy (self->adapter, &flag0, 0, 1); out = gst_adapter_take_buffer (self->adapter, gst_adapter_available (self->adapter)); self->started = FALSE; gst_rtp_buffer_unmap (&rtpbuffer); /* mark keyframes */ out = gst_buffer_make_writable (out); if ((flag0 & 0x01)) GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT); else GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT); return out; } done: gst_rtp_buffer_unmap (&rtpbuffer); return NULL; too_small: GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring"); gst_adapter_clear (self->adapter); self->started = FALSE; goto done; }