static GstBuffer * gst_rtp_ilbc_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstBuffer *outbuf; gboolean marker; marker = gst_rtp_buffer_get_marker (rtp); GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d", gst_buffer_get_size (rtp->buffer), marker, gst_rtp_buffer_get_timestamp (rtp), gst_rtp_buffer_get_seq (rtp)); outbuf = gst_rtp_buffer_get_payload_buffer (rtp); if (marker && outbuf) { /* mark start of talkspurt with RESYNC */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC); } if (outbuf) { gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); } return outbuf; }
static GstBuffer * gst_rtp_g722_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstRtpG722Depay *rtpg722depay; GstBuffer *outbuf; gint payload_len; gboolean marker; GstRTPBuffer rtp = { NULL }; rtpg722depay = GST_RTP_G722_DEPAY (depayload); gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); payload_len = gst_rtp_buffer_get_payload_len (&rtp); if (payload_len <= 0) goto empty_packet; GST_DEBUG_OBJECT (rtpg722depay, "got payload of %d bytes", payload_len); outbuf = gst_rtp_buffer_get_payload_buffer (&rtp); marker = gst_rtp_buffer_get_marker (&rtp); gst_rtp_buffer_unmap (&rtp); if (marker && outbuf) { /* mark talk spurt with RESYNC */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC); } if (outbuf) { gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpg722depay), outbuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); } return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpg722depay, STREAM, DECODE, ("Empty Payload."), (NULL)); gst_rtp_buffer_unmap (&rtp); return NULL; } }
static GstFlowReturn gst_rtp_g723_pay_flush (GstRTPG723Pay * pay) { GstBuffer *outbuf, *payload_buf; GstFlowReturn ret; guint avail; GstRTPBuffer rtp = { NULL }; avail = gst_adapter_available (pay->adapter); outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); GST_BUFFER_PTS (outbuf) = pay->timestamp; GST_BUFFER_DURATION (outbuf) = pay->duration; /* copy G723 data as payload */ payload_buf = gst_adapter_take_buffer_fast (pay->adapter, avail); pay->timestamp = GST_CLOCK_TIME_NONE; pay->duration = 0; /* set discont and marker */ if (pay->discont) { GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); gst_rtp_buffer_set_marker (&rtp, TRUE); pay->discont = FALSE; } gst_rtp_buffer_unmap (&rtp); gst_rtp_drop_meta (GST_ELEMENT_CAST (pay), outbuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); outbuf = gst_buffer_append (outbuf, payload_buf); ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (pay), outbuf); return ret; }
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_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_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_L16_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstRtpL16Depay *rtpL16depay; GstBuffer *outbuf; gint payload_len; gboolean marker; GstAudioInfo *info; rtpL16depay = GST_RTP_L16_DEPAY (depayload); payload_len = gst_rtp_buffer_get_payload_len (rtp); if (payload_len <= 0) goto empty_packet; GST_DEBUG_OBJECT (rtpL16depay, "got payload of %d bytes", payload_len); outbuf = gst_rtp_buffer_get_payload_buffer (rtp); marker = gst_rtp_buffer_get_marker (rtp); if (marker) { /* mark talk spurt with RESYNC */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC); } outbuf = gst_buffer_make_writable (outbuf); info = &rtpL16depay->info; if (payload_len % ((info->finfo->width * info->channels) / 8) != 0) goto wrong_payload_size; if (rtpL16depay->order && !gst_audio_buffer_reorder_channels (outbuf, info->finfo->format, info->channels, info->position, rtpL16depay->order->pos)) { goto reorder_failed; } gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpL16depay), outbuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } wrong_payload_size: { GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE, ("Wrong Payload Size."), (NULL)); return NULL; } reorder_failed: { GST_ELEMENT_ERROR (rtpL16depay, STREAM, DECODE, ("Channel reordering failed."), (NULL)); return NULL; } }
static GstFlowReturn gst_rtp_j2k_depay_flush_frame (GstRTPBaseDepayload * depayload) { GstRtpJ2KDepay *rtpj2kdepay; guint8 end[2]; guint avail; GstFlowReturn ret = GST_FLOW_OK; rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload); /* flush pending tile */ gst_rtp_j2k_depay_flush_tile (depayload); /* last buffer take all data out of the adapter */ avail = gst_adapter_available (rtpj2kdepay->f_adapter); if (avail == 0) goto done; if (avail > 2) { GstBuffer *outbuf; /* take the last bytes of the JPEG 2000 data to see if there is an EOC * marker */ gst_adapter_copy (rtpj2kdepay->f_adapter, end, avail - 2, 2); if (end[0] != 0xff && end[1] != 0xd9) { 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); gst_buffer_fill (outbuf, 0, end, 2); gst_adapter_push (rtpj2kdepay->f_adapter, outbuf); avail += 2; } GST_DEBUG_OBJECT (rtpj2kdepay, "pushing buffer of %u bytes", avail); outbuf = gst_adapter_take_buffer (rtpj2kdepay->f_adapter, avail); gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf, g_quark_from_static_string (GST_META_TAG_VIDEO_STR)); ret = gst_rtp_base_depayload_push (depayload, outbuf); } else { GST_WARNING_OBJECT (rtpj2kdepay, "empty packet"); gst_adapter_clear (rtpj2kdepay->f_adapter); } /* we accept any mh_id now */ rtpj2kdepay->last_mh_id = -1; /* reset state */ rtpj2kdepay->next_frag = 0; rtpj2kdepay->have_sync = FALSE; done: /* we can't keep headers with mh_id of 0 */ store_mheader (rtpj2kdepay, 0, NULL); return ret; }
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_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]; if (gst_adapter_available (self->adapter) < 10) goto too_small; 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); /* 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 ((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_mpa_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstRtpMPADepay *rtpmpadepay; GstBuffer *outbuf; gint payload_len; #if 0 guint8 *payload; guint16 frag_offset; #endif gboolean marker; rtpmpadepay = GST_RTP_MPA_DEPAY (depayload); 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)); if (outbuf) { gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpmpadepay), outbuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); } /* 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)); 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; } }