static GstBuffer * gst_rtp_pcmu_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstBuffer *outbuf = NULL; guint len; gboolean marker; GstRTPBuffer rtp = { NULL }; gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); 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 (buf), marker, gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp)); len = gst_rtp_buffer_get_payload_len (&rtp); outbuf = gst_rtp_buffer_get_payload_buffer (&rtp); gst_rtp_buffer_unmap (&rtp); if (outbuf) { GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate); if (marker) { /* mark start of talkspurt with RESYNC */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC); } } return outbuf; }
static GstBuffer * gst_rtp_mp4v_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstRtpMP4VDepay *rtpmp4vdepay; GstBuffer *pbuf, *outbuf = NULL; GstRTPBuffer rtp = { NULL }; gboolean marker; rtpmp4vdepay = GST_RTP_MP4V_DEPAY (depayload); /* flush remaining data on discont */ if (GST_BUFFER_IS_DISCONT (buf)) gst_adapter_clear (rtpmp4vdepay->adapter); gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); pbuf = gst_rtp_buffer_get_payload_buffer (&rtp); marker = gst_rtp_buffer_get_marker (&rtp); gst_rtp_buffer_unmap (&rtp); gst_adapter_push (rtpmp4vdepay->adapter, pbuf); /* if this was the last packet of the VOP, create and push a buffer */ if (marker) { guint avail; avail = gst_adapter_available (rtpmp4vdepay->adapter); outbuf = gst_adapter_take_buffer (rtpmp4vdepay->adapter, avail); GST_DEBUG ("gst_rtp_mp4v_depay_chain: pushing buffer of size %" G_GSIZE_FORMAT, gst_buffer_get_size (outbuf)); } return outbuf; }
static void check_rtp_buffer (GstClockTime ts, GstClockTime duration, gboolean start, gboolean end, guint rtpts, guint ssrc, guint volume, guint number, guint rtpduration) { GstBuffer *buffer; GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; gchar *payload; g_mutex_lock (&check_mutex); while (buffers == NULL) g_cond_wait (&check_cond, &check_mutex); g_mutex_unlock (&check_mutex); fail_unless (buffers != NULL); buffer = buffers->data; buffers = g_list_delete_link (buffers, buffers); fail_unless (GST_BUFFER_PTS (buffer) == ts); fail_unless (GST_BUFFER_DURATION (buffer) == duration); fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtpbuffer)); fail_unless (gst_rtp_buffer_get_marker (&rtpbuffer) == start); fail_unless (gst_rtp_buffer_get_timestamp (&rtpbuffer) == rtpts); payload = gst_rtp_buffer_get_payload (&rtpbuffer); fail_unless (payload[0] == number); fail_unless ((payload[1] & 0x7F) == volume); fail_unless (! !(payload[1] & 0x80) == end); fail_unless (GST_READ_UINT16_BE (payload + 2) == rtpduration); gst_rtp_buffer_unmap (&rtpbuffer); gst_buffer_unref (buffer); }
static GstBuffer * gst_rtp_g722_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpG722Depay *rtpg722depay; GstBuffer *outbuf; gint payload_len; gboolean marker; rtpg722depay = GST_RTP_G722_DEPAY (depayload); payload_len = gst_rtp_buffer_get_payload_len (buf); 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 (buf); marker = gst_rtp_buffer_get_marker (buf); if (marker) { /* mark talk spurt with DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpg722depay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } }
static GstBuffer * gst_rtp_gsm_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstBuffer *outbuf = NULL; 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_ilbc_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstBuffer *outbuf; gboolean marker; GstRTPBuffer rtp = { NULL }; gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); 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 (buf), marker, gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp)); outbuf = gst_rtp_buffer_get_payload_buffer (&rtp); gst_rtp_buffer_unmap (&rtp); if (marker && outbuf) { /* mark start of talkspurt with DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } return outbuf; }
static GstBuffer * gst_rtp_mp4v_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpMP4VDepay *rtpmp4vdepay; GstBuffer *outbuf; rtpmp4vdepay = GST_RTP_MP4V_DEPAY (depayload); /* flush remaining data on discont */ if (GST_BUFFER_IS_DISCONT (buf)) gst_adapter_clear (rtpmp4vdepay->adapter); outbuf = gst_rtp_buffer_get_payload_buffer (buf); gst_adapter_push (rtpmp4vdepay->adapter, outbuf); /* if this was the last packet of the VOP, create and push a buffer */ if (gst_rtp_buffer_get_marker (buf)) { guint avail; avail = gst_adapter_available (rtpmp4vdepay->adapter); outbuf = gst_adapter_take_buffer (rtpmp4vdepay->adapter, avail); GST_DEBUG ("gst_rtp_mp4v_depay_chain: pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); return outbuf; } return NULL; }
static GstBuffer * gst_rtp_pcma_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstBuffer *outbuf = NULL; gboolean marker; guint len; marker = gst_rtp_buffer_get_marker (buf); GST_DEBUG ("process : got %d bytes, mark %d ts %u seqn %d", GST_BUFFER_SIZE (buf), marker, gst_rtp_buffer_get_timestamp (buf), gst_rtp_buffer_get_seq (buf)); len = gst_rtp_buffer_get_payload_len (buf); outbuf = gst_rtp_buffer_get_payload_buffer (buf); if (outbuf) { GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (len, GST_SECOND, depayload->clock_rate); if (marker) { /* mark start of talkspurt with DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } } return outbuf; }
static GstBuffer * gst_rtp_L16_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstRtpL16Depay *rtpL16depay; GstBuffer *outbuf; gint payload_len; gboolean marker; GstRTPBuffer rtp = { NULL }; rtpL16depay = GST_RTP_L16_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 (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 DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } outbuf = gst_buffer_make_writable (outbuf); if (rtpL16depay->order && !gst_audio_buffer_reorder_channels (outbuf, rtpL16depay->info.finfo->format, rtpL16depay->info.channels, rtpL16depay->info.position, rtpL16depay->order->pos)) { goto reorder_failed; } gst_rtp_buffer_unmap (&rtp); return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE, ("Empty Payload."), (NULL)); gst_rtp_buffer_unmap (&rtp); return NULL; } reorder_failed: { GST_ELEMENT_ERROR (rtpL16depay, STREAM, DECODE, ("Channel reordering failed."), (NULL)); gst_rtp_buffer_unmap (&rtp); return NULL; } }
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_g729_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstRtpG729Depay *rtpg729depay; GstBuffer *outbuf = NULL; gint payload_len; gboolean marker; GstRTPBuffer rtp = { NULL }; rtpg729depay = GST_RTP_G729_DEPAY (depayload); gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); payload_len = gst_rtp_buffer_get_payload_len (&rtp); /* At least 2 bytes (CNG from G729 Annex B) */ if (payload_len < 2) { GST_ELEMENT_WARNING (rtpg729depay, STREAM, DECODE, (NULL), ("G729 RTP payload too small (%d)", payload_len)); goto bad_packet; } GST_LOG_OBJECT (rtpg729depay, "payload len %d", payload_len); if ((payload_len % 10) == 2) { GST_LOG_OBJECT (rtpg729depay, "G729 payload contains CNG frame"); } outbuf = gst_rtp_buffer_get_payload_buffer (&rtp); marker = gst_rtp_buffer_get_marker (&rtp); gst_rtp_buffer_unmap (&rtp); if (marker) { /* marker bit starts talkspurt */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC); } GST_LOG_OBJECT (depayload, "pushing buffer of size %" G_GSIZE_FORMAT, gst_buffer_get_size (outbuf)); return outbuf; /* ERRORS */ bad_packet: { /* no fatal error */ return NULL; } }
static void compare_rtp_packets (GstBuffer * a, GstBuffer * b) { GstRTPBuffer rtp_a = GST_RTP_BUFFER_INIT; GstRTPBuffer rtp_b = GST_RTP_BUFFER_INIT; gst_rtp_buffer_map (a, GST_MAP_READ, &rtp_a); gst_rtp_buffer_map (b, GST_MAP_READ, &rtp_b); fail_unless_equals_int (gst_rtp_buffer_get_header_len (&rtp_a), gst_rtp_buffer_get_header_len (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_version (&rtp_a), gst_rtp_buffer_get_version (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp_a), gst_rtp_buffer_get_ssrc (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp_a), gst_rtp_buffer_get_seq (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (&rtp_a), gst_rtp_buffer_get_csrc_count (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_marker (&rtp_a), gst_rtp_buffer_get_marker (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp_a), gst_rtp_buffer_get_payload_type (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp_a), gst_rtp_buffer_get_timestamp (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_extension (&rtp_a), gst_rtp_buffer_get_extension (&rtp_b)); fail_unless_equals_int (gst_rtp_buffer_get_payload_len (&rtp_a), gst_rtp_buffer_get_payload_len (&rtp_b)); fail_unless_equals_int (memcmp (gst_rtp_buffer_get_payload (&rtp_a), gst_rtp_buffer_get_payload (&rtp_b), gst_rtp_buffer_get_payload_len (&rtp_a)), 0); gst_rtp_buffer_unmap (&rtp_a); gst_rtp_buffer_unmap (&rtp_b); }
static GstFlowReturn gst_scream_queue_sink_chain(GstPad *pad, GstObject *parent, GstBuffer *buffer) { GstScreamQueue *self = GST_SCREAM_QUEUE(parent); GstRTPBuffer rtp_buffer = GST_RTP_BUFFER_INIT; GstFlowReturn flow_ret = GST_FLOW_OK; GstScreamDataQueueRtpItem *rtp_item; if (GST_PAD_IS_FLUSHING(pad)) { flow_ret = GST_FLOW_FLUSHING; goto end; } if (!gst_rtp_buffer_map(buffer, GST_MAP_READ, &rtp_buffer)) { flow_ret = GST_FLOW_ERROR; goto end; } rtp_item = g_slice_new(GstScreamDataQueueRtpItem); ((GstDataQueueItem *)rtp_item)->object = GST_MINI_OBJECT(buffer); ((GstDataQueueItem *)rtp_item)->size = gst_buffer_get_size(buffer); ((GstDataQueueItem *)rtp_item)->visible = TRUE; ((GstDataQueueItem *)rtp_item)->duration = GST_BUFFER_DURATION(buffer); ((GstDataQueueItem *)rtp_item)->destroy = (GDestroyNotify) gst_scream_data_queue_rtp_item_free; ((GstScreamDataQueueItem *)rtp_item)->type = GST_SCREAM_DATA_QUEUE_ITEM_TYPE_RTP; ((GstScreamDataQueueItem *)rtp_item)->rtp_ssrc = gst_rtp_buffer_get_ssrc(&rtp_buffer); rtp_item->rtp_pt = gst_rtp_buffer_get_payload_type(&rtp_buffer); rtp_item->gst_ts = GST_BUFFER_PTS(buffer); rtp_item->rtp_seq = gst_rtp_buffer_get_seq(&rtp_buffer); rtp_item->rtp_ts = gst_rtp_buffer_get_timestamp(&rtp_buffer); rtp_item->rtp_marker = gst_rtp_buffer_get_marker(&rtp_buffer); rtp_item->rtp_payload_size = gst_rtp_buffer_get_payload_len(&rtp_buffer); rtp_item->enqueued_time = get_gst_time_us(self); gst_rtp_buffer_unmap(&rtp_buffer); if (self->pass_through) { rtp_item->adapted = FALSE; GST_LOG_OBJECT(self, "passing through: pt = %u, seq: %u, pass: %u", rtp_item->rtp_pt, rtp_item->rtp_seq, self->pass_through); gst_data_queue_push(self->approved_packets, (GstDataQueueItem *)rtp_item); goto end; } GST_LOG_OBJECT(self, "queuing: pt = %u, seq: %u, pass: %u", rtp_item->rtp_pt, rtp_item->rtp_seq, self->pass_through); g_async_queue_push(self->incoming_packets, (gpointer)rtp_item); end: return flow_ret; }
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_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 GstBuffer * gst_rtp_g723_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpG723Depay *rtpg723depay; GstBuffer *outbuf = NULL; gint payload_len; gboolean marker; rtpg723depay = GST_RTP_G723_DEPAY (depayload); payload_len = gst_rtp_buffer_get_payload_len (buf); /* At least 4 bytes */ if (payload_len < 4) goto too_small; GST_LOG_OBJECT (rtpg723depay, "payload len %d", payload_len); outbuf = gst_rtp_buffer_get_payload_buffer (buf); marker = gst_rtp_buffer_get_marker (buf); if (marker) { /* marker bit starts talkspurt */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } GST_LOG_OBJECT (depayload, "pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); return outbuf; /* ERRORS */ too_small: { GST_ELEMENT_WARNING (rtpg723depay, STREAM, DECODE, (NULL), ("G723 RTP payload too small (%d)", payload_len)); goto bad_packet; } bad_packet: { /* no fatal error */ return NULL; } }
static GstBuffer * gst_rtp_ilbc_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstBuffer *outbuf; gboolean marker; marker = gst_rtp_buffer_get_marker (buf); GST_DEBUG ("process : got %d bytes, mark %d ts %u seqn %d", GST_BUFFER_SIZE (buf), marker, gst_rtp_buffer_get_timestamp (buf), gst_rtp_buffer_get_seq (buf)); outbuf = gst_rtp_buffer_get_payload_buffer (buf); if (marker && outbuf) { /* mark start of talkspurt with DISCONT */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } return outbuf; }
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); } return outbuf; }
static GstBuffer * gst_rtp_speex_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstBuffer *outbuf = NULL; GstRTPBuffer rtp = { NULL }; gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); GST_DEBUG ("process : got %" G_GSIZE_FORMAT " bytes, mark %d ts %u seqn %d", gst_buffer_get_size (buf), gst_rtp_buffer_get_marker (&rtp), gst_rtp_buffer_get_timestamp (&rtp), gst_rtp_buffer_get_seq (&rtp)); /* nothing special to be done */ outbuf = gst_rtp_buffer_get_payload_buffer (&rtp); gst_rtp_buffer_unmap (&rtp); if (outbuf) GST_BUFFER_DURATION (outbuf) = 20 * GST_MSECOND; return outbuf; }
gboolean gst_al_rtp_buffer_get_marker(GstAlBuf *buf) { return gst_rtp_buffer_get_marker(buf->m_buffer); }
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_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_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_dtmf_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpDTMFDepay *rtpdtmfdepay = NULL; GstBuffer *outbuf = NULL; gint payload_len; guint8 *payload = NULL; guint32 timestamp; GstRTPDTMFPayload dtmf_payload; gboolean marker; GstStructure *structure = NULL; GstMessage *dtmf_message = NULL; rtpdtmfdepay = GST_RTP_DTMF_DEPAY (depayload); if (!gst_rtp_buffer_validate (buf)) goto bad_packet; payload_len = gst_rtp_buffer_get_payload_len (buf); payload = gst_rtp_buffer_get_payload (buf); if (payload_len != sizeof (GstRTPDTMFPayload)) goto bad_packet; memcpy (&dtmf_payload, payload, sizeof (GstRTPDTMFPayload)); if (dtmf_payload.event > MAX_EVENT) goto bad_packet; marker = gst_rtp_buffer_get_marker (buf); timestamp = gst_rtp_buffer_get_timestamp (buf); dtmf_payload.duration = g_ntohs (dtmf_payload.duration); /* clip to whole units of unit_time */ if (rtpdtmfdepay->unit_time) { guint unit_time_clock = (rtpdtmfdepay->unit_time * depayload->clock_rate) / 1000; if (dtmf_payload.duration % unit_time_clock) { /* Make sure we don't overflow the duration */ if (dtmf_payload.duration < G_MAXUINT16 - unit_time_clock) dtmf_payload.duration += unit_time_clock - (dtmf_payload.duration % unit_time_clock); else dtmf_payload.duration -= dtmf_payload.duration % unit_time_clock; } } /* clip to max duration */ if (rtpdtmfdepay->max_duration) { guint max_duration_clock = (rtpdtmfdepay->max_duration * depayload->clock_rate) / 1000; if (max_duration_clock < G_MAXUINT16 && dtmf_payload.duration > max_duration_clock) dtmf_payload.duration = max_duration_clock; } GST_DEBUG_OBJECT (depayload, "Received new RTP DTMF packet : " "marker=%d - timestamp=%u - event=%d - duration=%d", marker, timestamp, dtmf_payload.event, dtmf_payload.duration); GST_DEBUG_OBJECT (depayload, "Previous information : timestamp=%u - duration=%d", rtpdtmfdepay->previous_ts, rtpdtmfdepay->previous_duration); /* First packet */ if (marker || rtpdtmfdepay->previous_ts != timestamp) { rtpdtmfdepay->sample = 0; rtpdtmfdepay->previous_ts = timestamp; rtpdtmfdepay->previous_duration = dtmf_payload.duration; rtpdtmfdepay->first_gst_ts = GST_BUFFER_TIMESTAMP (buf); structure = gst_structure_new ("dtmf-event", "number", G_TYPE_INT, dtmf_payload.event, "volume", G_TYPE_INT, dtmf_payload.volume, "type", G_TYPE_INT, 1, "method", G_TYPE_INT, 1, NULL); if (structure) { dtmf_message = gst_message_new_element (GST_OBJECT (depayload), structure); if (dtmf_message) { if (!gst_element_post_message (GST_ELEMENT (depayload), dtmf_message)) { GST_ERROR_OBJECT (depayload, "Unable to send dtmf-event message to bus"); } } else { GST_ERROR_OBJECT (depayload, "Unable to create dtmf-event message"); } } else { GST_ERROR_OBJECT (depayload, "Unable to create dtmf-event structure"); } } else { guint16 duration = dtmf_payload.duration; dtmf_payload.duration -= rtpdtmfdepay->previous_duration; /* If late buffer, ignore */ if (duration > rtpdtmfdepay->previous_duration) rtpdtmfdepay->previous_duration = duration; } GST_DEBUG_OBJECT (depayload, "new previous duration : %d - new duration : %d" " - diff : %d - clock rate : %d - timestamp : %llu", rtpdtmfdepay->previous_duration, dtmf_payload.duration, (rtpdtmfdepay->previous_duration - dtmf_payload.duration), depayload->clock_rate, GST_BUFFER_TIMESTAMP (buf)); /* If late or duplicate packet (like the redundant end packet). Ignore */ if (dtmf_payload.duration > 0) { outbuf = gst_buffer_new (); gst_dtmf_src_generate_tone (rtpdtmfdepay, dtmf_payload, outbuf); GST_BUFFER_TIMESTAMP (outbuf) = rtpdtmfdepay->first_gst_ts + (rtpdtmfdepay->previous_duration - dtmf_payload.duration) * GST_SECOND / depayload->clock_rate; GST_BUFFER_OFFSET (outbuf) = (rtpdtmfdepay->previous_duration - dtmf_payload.duration) * GST_SECOND / depayload->clock_rate; GST_BUFFER_OFFSET_END (outbuf) = rtpdtmfdepay->previous_duration * GST_SECOND / depayload->clock_rate; GST_DEBUG_OBJECT (depayload, "timestamp : %llu - time %" GST_TIME_FORMAT, GST_BUFFER_TIMESTAMP (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); } return outbuf; bad_packet: GST_ELEMENT_WARNING (rtpdtmfdepay, STREAM, DECODE, ("Packet did not validate"), (NULL)); return NULL; }
static GstBuffer * gst_rtp_xqt_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstRtpXQTDepay *rtpxqtdepay; GstBuffer *outbuf = NULL; gboolean m; GstRTPBuffer rtp = { NULL }; rtpxqtdepay = GST_RTP_XQT_DEPAY (depayload); gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); if (!gst_rtp_buffer_validate (buf)) goto bad_packet; if (GST_BUFFER_IS_DISCONT (buf)) { /* discont, clear adapter and try to find a new packet start */ gst_adapter_clear (rtpxqtdepay->adapter); rtpxqtdepay->need_resync = TRUE; GST_DEBUG_OBJECT (rtpxqtdepay, "we need resync"); } m = gst_rtp_buffer_get_marker (&rtp); GST_LOG_OBJECT (rtpxqtdepay, "marker: %d", m); { gint payload_len; guint avail; guint8 *payload; guint8 ver, pck; gboolean s, q, l, d; payload_len = gst_rtp_buffer_get_payload_len (&rtp); payload = gst_rtp_buffer_get_payload (&rtp); /* 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | VER |PCK|S|Q|L| RES |D| QuickTime Payload ID | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ if (payload_len <= 4) goto wrong_length; ver = (payload[0] & 0xf0) >> 4; if (ver > 1) goto wrong_version; pck = (payload[0] & 0x0c) >> 2; if (pck == 0) goto pck_reserved; s = (payload[0] & 0x02) != 0; /* contains sync sample */ q = (payload[0] & 0x01) != 0; /* has payload description */ l = (payload[1] & 0x80) != 0; /* has packet specific information description */ d = (payload[2] & 0x80) != 0; /* don't cache info for payload id */ /* id used for caching info */ rtpxqtdepay->current_id = ((payload[2] & 0x7f) << 8) | payload[3]; GST_LOG_OBJECT (rtpxqtdepay, "VER: %d, PCK: %d, S: %d, Q: %d, L: %d, D: %d, ID: %d", ver, pck, s, q, l, d, rtpxqtdepay->current_id); if (rtpxqtdepay->need_resync) { /* we need to find the boundary of a new packet after a DISCONT */ if (pck != 3 || q) { /* non-fragmented packet or payload description present, packet starts * here. */ rtpxqtdepay->need_resync = FALSE; } else { /* fragmented packet without description */ if (m) { /* marker bit set, next packet is start of new one */ rtpxqtdepay->need_resync = FALSE; } goto need_resync; } } payload += 4; payload_len -= 4; if (q) { gboolean k, f, a, z; guint pdlen, pdpadded; gint padding; /* media_type only used for printing */ guint32 G_GNUC_UNUSED media_type; guint32 timescale; /* 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |K|F|A|Z| RES | QuickTime Payload Desc Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . QuickTime Payload Desc Data ... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ if (payload_len <= 4) goto wrong_length; k = (payload[0] & 0x80) != 0; /* keyframe */ f = (payload[0] & 0x40) != 0; /* sparse */ a = (payload[0] & 0x20) != 0; /* start of payload */ z = (payload[0] & 0x10) != 0; /* end of payload */ pdlen = (payload[2] << 8) | payload[3]; if (pdlen < 12) goto wrong_length; /* calc padding */ pdpadded = pdlen + 3; pdpadded -= pdpadded % 4; if (payload_len < pdpadded) goto wrong_length; padding = pdpadded - pdlen; GST_LOG_OBJECT (rtpxqtdepay, "K: %d, F: %d, A: %d, Z: %d, len: %d, padding %d", k, f, a, z, pdlen, padding); payload += 4; payload_len -= 4; /* 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | QuickTime Media Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Timescale | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . QuickTime TLVs ... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ media_type = (payload[0] << 24) | (payload[1] << 16) | (payload[2] << 8) | payload[3]; timescale = (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) | payload[7]; GST_LOG_OBJECT (rtpxqtdepay, "media_type: %c%c%c%c, timescale %u", payload[0], payload[1], payload[2], payload[3], timescale); payload += 8; payload_len -= 8; pdlen -= 12; /* parse TLV (type-length-value triplets */ while (pdlen > 3) { guint16 tlv_len, tlv_type; /* 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | QuickTime TLV Length | QuickTime TLV Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . QuickTime TLV Value ... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ tlv_len = (payload[0] << 8) | payload[1]; tlv_type = (payload[2] << 8) | payload[3]; pdlen -= 4; if (tlv_len > pdlen) goto wrong_length; GST_LOG_OBJECT (rtpxqtdepay, "TLV '%c%c', len %d", payload[2], payload[3], tlv_len); payload += 4; payload_len -= 4; switch (tlv_type) { case TLV_sd: /* Session description */ if (!gst_rtp_quicktime_parse_sd (rtpxqtdepay, payload, tlv_len)) goto unknown_format; rtpxqtdepay->have_sd = TRUE; break; case TLV_qt: case TLV_ti: case TLV_ly: case TLV_vo: case TLV_mx: case TLV_tr: case TLV_tw: case TLV_th: case TLV_la: case TLV_rt: case TLV_gm: case TLV_oc: case TLV_cr: case TLV_du: case TLV_po: default: break; } pdlen -= tlv_len; payload += tlv_len; payload_len -= tlv_len; } payload += padding; payload_len -= padding; } if (l) { guint ssilen, ssipadded; gint padding; /* 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | RES | Sample-Specific Info Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . QuickTime TLVs ... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ if (payload_len <= 4) goto wrong_length; ssilen = (payload[2] << 8) | payload[3]; if (ssilen < 4) goto wrong_length; /* calc padding */ ssipadded = ssilen + 3; ssipadded -= ssipadded % 4; if (payload_len < ssipadded) goto wrong_length; padding = ssipadded - ssilen; GST_LOG_OBJECT (rtpxqtdepay, "len: %d, padding %d", ssilen, padding); payload += 4; payload_len -= 4; ssilen -= 4; /* parse TLV (type-length-value triplets */ while (ssilen > 3) { guint16 tlv_len, tlv_type; /* 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | QuickTime TLV Length | QuickTime TLV Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . QuickTime TLV Value ... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ tlv_len = (payload[0] << 8) | payload[1]; tlv_type = (payload[2] << 8) | payload[3]; ssilen -= 4; if (tlv_len > ssilen) goto wrong_length; GST_LOG_OBJECT (rtpxqtdepay, "TLV '%c%c', len %d", payload[2], payload[3], tlv_len); payload += 4; payload_len -= 4; switch (tlv_type) { case TLV_sd: case TLV_qt: case TLV_ti: case TLV_ly: case TLV_vo: case TLV_mx: case TLV_tr: case TLV_tw: case TLV_th: case TLV_la: case TLV_rt: case TLV_gm: case TLV_oc: case TLV_cr: case TLV_du: case TLV_po: default: break; } ssilen -= tlv_len; payload += tlv_len; payload_len -= tlv_len; } payload += padding; payload_len -= padding; } rtpxqtdepay->previous_id = rtpxqtdepay->current_id; switch (pck) { case 1: { /* multiple samples per packet. */ outbuf = gst_buffer_new_and_alloc (payload_len); gst_buffer_fill (outbuf, 0, payload, payload_len); goto done; } case 2: { guint slen; /* multiple samples per packet. * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |S| Reserved | Sample Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Sample Timestamp | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . Sample Data ... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |S| Reserved | Sample Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Sample Timestamp | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . Sample Data ... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . ...... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ while (payload_len > 8) { s = (payload[0] & 0x80) != 0; /* contains sync sample */ slen = (payload[2] << 8) | payload[3]; /* timestamp = * (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) | * payload[7]; */ payload += 8; payload_len -= 8; if (slen > payload_len) slen = payload_len; outbuf = gst_buffer_new_and_alloc (slen); gst_buffer_fill (outbuf, 0, payload, slen); if (!s) GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); gst_rtp_base_depayload_push (depayload, outbuf); /* aligned on 32 bit boundary */ slen = GST_ROUND_UP_4 (slen); payload += slen; payload_len -= slen; } break; } case 3: { /* one sample per packet, use adapter to combine based on marker bit. */ outbuf = gst_buffer_new_and_alloc (payload_len); gst_buffer_fill (outbuf, 0, payload, payload_len); gst_adapter_push (rtpxqtdepay->adapter, outbuf); if (!m) goto done; avail = gst_adapter_available (rtpxqtdepay->adapter); outbuf = gst_adapter_take_buffer (rtpxqtdepay->adapter, avail); GST_DEBUG_OBJECT (rtpxqtdepay, "gst_rtp_xqt_depay_chain: pushing buffer of size %u", avail); goto done; } } } done: gst_rtp_buffer_unmap (&rtp); return outbuf; bad_packet: { GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, ("Packet did not validate."), (NULL)); goto done; } need_resync: { GST_DEBUG_OBJECT (rtpxqtdepay, "waiting for marker"); goto done; } wrong_version: { GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, ("Unknown payload version."), (NULL)); goto done; } pck_reserved: { GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, ("PCK reserved 0."), (NULL)); goto done; } wrong_length: { GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, ("Wrong payload length."), (NULL)); goto done; } unknown_format: { GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, ("Unknown payload format."), (NULL)); goto done; } }
static GstFlowReturn gst_asteriskh263_chain (GstPad * pad, GstBuffer * buf) { GstAsteriskh263 *asteriskh263; GstBuffer *outbuf; GstFlowReturn ret; asteriskh263 = GST_ASTERISK_H263 (GST_OBJECT_PARENT (pad)); if (!gst_rtp_buffer_validate (buf)) goto bad_packet; { gint payload_len; guint8 *payload; gboolean M; guint32 timestamp; guint32 samples; guint16 asterisk_len; payload_len = gst_rtp_buffer_get_payload_len (buf); payload = gst_rtp_buffer_get_payload (buf); M = gst_rtp_buffer_get_marker (buf); timestamp = gst_rtp_buffer_get_timestamp (buf); outbuf = gst_buffer_new_and_alloc (payload_len + GST_ASTERISKH263_HEADER_LEN); /* build the asterisk header */ asterisk_len = payload_len; if (M) asterisk_len |= 0x8000; if (!asteriskh263->lastts) asteriskh263->lastts = timestamp; samples = timestamp - asteriskh263->lastts; asteriskh263->lastts = timestamp; GST_ASTERISKH263_HEADER_TIMESTAMP (outbuf) = g_htonl (samples); GST_ASTERISKH263_HEADER_LENGTH (outbuf) = g_htons (asterisk_len); /* copy the data into place */ memcpy (GST_BUFFER_DATA (outbuf) + GST_ASTERISKH263_HEADER_LEN, payload, payload_len); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; gst_buffer_set_caps (outbuf, (GstCaps *) gst_pad_get_pad_template_caps (asteriskh263->srcpad)); ret = gst_pad_push (asteriskh263->srcpad, outbuf); gst_buffer_unref (buf); } return ret; bad_packet: { GST_DEBUG ("Packet does not validate"); gst_buffer_unref (buf); return GST_FLOW_ERROR; } }
/* Process one RTP packet. Accumulate RTP payload in the proper place in a DV * frame, and return that frame if we detect a new frame, or NULL otherwise. * We assume a DV frame is 144000 bytes. That should accomodate PAL as well as * NTSC. */ static GstBuffer * gst_rtp_dv_depay_process (GstBaseRTPDepayload * base, GstBuffer * in) { GstBuffer *out = NULL; guint8 *payload; guint32 rtp_ts; guint payload_len, location; GstRTPDVDepay *dvdepay = GST_RTP_DV_DEPAY (base); gboolean marker; marker = gst_rtp_buffer_get_marker (in); /* Check if the received packet contains (the start of) a new frame, we do * this by checking the RTP timestamp. */ rtp_ts = gst_rtp_buffer_get_timestamp (in); /* we cannot copy the packet yet if the marker is set, we will do that below * after taking out the data */ if (dvdepay->prev_ts != -1 && rtp_ts != dvdepay->prev_ts && !marker) { /* the timestamp changed */ GST_DEBUG_OBJECT (dvdepay, "new frame with ts %u, old ts %u", rtp_ts, dvdepay->prev_ts); /* return copy of accumulator. */ out = gst_buffer_copy (dvdepay->acc); } /* Extract the payload */ payload_len = gst_rtp_buffer_get_payload_len (in); payload = gst_rtp_buffer_get_payload (in); /* copy all DIF chunks in their place. */ while (payload_len >= 80) { guint offset; /* Calculate where in the frame the payload should go */ location = calculate_difblock_location (payload); if (location < 6) { /* part of a header, set the flag to mark that we have the header. */ dvdepay->header_mask |= (1 << location); GST_LOG_OBJECT (dvdepay, "got header at location %d, now %02x", location, dvdepay->header_mask); } else { GST_LOG_OBJECT (dvdepay, "got block at location %d", location); } if (location != -1) { /* get the byte offset of the dif block */ offset = location * 80; /* And copy it in, provided the location is sane. */ if (offset <= dvdepay->frame_size - 80) memcpy (GST_BUFFER_DATA (dvdepay->acc) + offset, payload, 80); } payload += 80; payload_len -= 80; } if (marker) { GST_DEBUG_OBJECT (dvdepay, "marker bit complete frame %u", rtp_ts); /* only copy the frame when we have a complete header */ if (dvdepay->header_mask == 0x3f) { /* The marker marks the end of a frame that we need to push. The next frame * will change the timestamp but we won't copy the accumulator again because * we set the prev_ts to -1. */ out = gst_buffer_copy (dvdepay->acc); } else { GST_WARNING_OBJECT (dvdepay, "waiting for frame headers %02x", dvdepay->header_mask); } dvdepay->prev_ts = -1; } else { /* save last timestamp */ dvdepay->prev_ts = rtp_ts; } return out; }
static GstBuffer * gst_rtp_vraw_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpVRawDepay *rtpvrawdepay; guint8 *payload, *data, *yp, *up, *vp, *headers; guint32 timestamp; guint cont, ystride, uvstride, pgroup; rtpvrawdepay = GST_RTP_VRAW_DEPAY (depayload); timestamp = gst_rtp_buffer_get_timestamp (buf); if (timestamp != rtpvrawdepay->timestamp || rtpvrawdepay->outbuf == NULL) { GstBuffer *outbuf; 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_base_rtp_depayload_push_ts (depayload, rtpvrawdepay->timestamp, rtpvrawdepay->outbuf); rtpvrawdepay->outbuf = NULL; } ret = gst_pad_alloc_buffer (depayload->srcpad, -1, rtpvrawdepay->outsize, GST_PAD_CAPS (depayload->srcpad), &outbuf); if (ret != GST_FLOW_OK) goto alloc_failed; /* clear timestamp from alloc... */ GST_BUFFER_TIMESTAMP (outbuf) = -1; rtpvrawdepay->outbuf = outbuf; rtpvrawdepay->timestamp = timestamp; } data = GST_BUFFER_DATA (rtpvrawdepay->outbuf); /* get pointer and strides of the planes */ yp = data + rtpvrawdepay->yp; up = data + rtpvrawdepay->up; vp = data + rtpvrawdepay->vp; ystride = rtpvrawdepay->ystride; uvstride = rtpvrawdepay->uvstride; pgroup = rtpvrawdepay->pgroup; payload = gst_rtp_buffer_get_payload (buf); /* skip extended seqnum */ payload++; payload++; /* remember header position */ headers = payload; /* find data start */ do { cont = payload[4] & 0x80; payload += 6; } while (cont); while (TRUE) { guint length, line, offs; guint8 *datap; /* read length and cont */ 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; /* sanity check */ if (line > (rtpvrawdepay->height - rtpvrawdepay->yinc)) continue; if (offs > (rtpvrawdepay->width - rtpvrawdepay->xinc)) continue; GST_LOG_OBJECT (depayload, "writing length %u, line %u, offset %u", length, line, offs); switch (rtpvrawdepay->format) { 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: /* samples are packed just like gstreamer packs them */ offs /= rtpvrawdepay->xinc; datap = yp + (line * ystride) + (offs * pgroup); memcpy (datap, payload, length); payload += length; break; case GST_VIDEO_FORMAT_AYUV: { gint i; datap = yp + (line * ystride) + (offs * 4); /* samples are packed in order Cb-Y-Cr for both interlaced and * progressive frames */ for (i = 0; i < length; i += pgroup) { *datap++ = 0; *datap++ = payload[1]; *datap++ = payload[0]; *datap++ = payload[2]; payload += pgroup; } break; } case GST_VIDEO_FORMAT_I420: { gint i; guint uvoff; guint8 *yd1p, *yd2p, *udp, *vdp; yd1p = yp + (line * ystride) + (offs); yd2p = yd1p + ystride; uvoff = (line / rtpvrawdepay->yinc * uvstride) + (offs / rtpvrawdepay->xinc); udp = up + uvoff; vdp = vp + uvoff; /* line 0/1: Y00-Y01-Y10-Y11-Cb00-Cr00 Y02-Y03-Y12-Y13-Cb01-Cr01 ... */ for (i = 0; i < length; i += pgroup) { *yd1p++ = payload[0]; *yd1p++ = payload[1]; *yd2p++ = payload[2]; *yd2p++ = payload[3]; *udp++ = payload[4]; *vdp++ = payload[5]; payload += pgroup; } break; } case GST_VIDEO_FORMAT_Y41B: { gint i; guint uvoff; guint8 *ydp, *udp, *vdp; ydp = yp + (line * ystride) + (offs); uvoff = (line / rtpvrawdepay->yinc * uvstride) + (offs / rtpvrawdepay->xinc); udp = up + uvoff; vdp = vp + uvoff; /* Samples are packed in order Cb0-Y0-Y1-Cr0-Y2-Y3 for both interlaced * and progressive scan lines */ for (i = 0; i < length; i += pgroup) { *udp++ = payload[0]; *ydp++ = payload[1]; *ydp++ = payload[2]; *vdp++ = payload[3]; *ydp++ = payload[4]; *ydp++ = payload[5]; payload += pgroup; } break; } default: goto unknown_sampling; } if (!cont) break; } if (gst_rtp_buffer_get_marker (buf)) { GST_LOG_OBJECT (depayload, "marker, flushing frame"); if (rtpvrawdepay->outbuf) { gst_base_rtp_depayload_push_ts (depayload, timestamp, rtpvrawdepay->outbuf); rtpvrawdepay->outbuf = NULL; } rtpvrawdepay->timestamp = -1; } return NULL; /* ERRORS */ unknown_sampling: { GST_ELEMENT_ERROR (depayload, STREAM, FORMAT, (NULL), ("unimplemented sampling")); return NULL; } alloc_failed: { GST_DEBUG_OBJECT (depayload, "failed to alloc output buffer"); 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_amr_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpAMRDepay *rtpamrdepay; const gint *frame_size; GstBuffer *outbuf = NULL; gint payload_len; rtpamrdepay = GST_RTP_AMR_DEPAY (depayload); /* setup frame size pointer */ if (rtpamrdepay->mode == GST_RTP_AMR_DP_MODE_NB) frame_size = nb_frame_size; else frame_size = wb_frame_size; /* when we get here, 1 channel, 8000/16000 Hz, octet aligned, no CRC, * no robust sorting, no interleaving data is to be depayloaded */ { guint8 *payload, *p, *dp; guint8 CMR; gint i, num_packets, num_nonempty_packets; gint amr_len; gint ILL, ILP; payload_len = gst_rtp_buffer_get_payload_len (buf); /* need at least 2 bytes for the header */ if (payload_len < 2) goto too_small; payload = gst_rtp_buffer_get_payload (buf); /* depay CMR. The CMR is used by the sender to request * a new encoding mode. * * 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * | CMR |R|R|R|R| * +-+-+-+-+-+-+-+-+ */ CMR = (payload[0] & 0xf0) >> 4; /* strip CMR header now, pack FT and the data for the decoder */ payload_len -= 1; payload += 1; GST_DEBUG_OBJECT (rtpamrdepay, "payload len %d", payload_len); if (rtpamrdepay->interleaving) { ILL = (payload[0] & 0xf0) >> 4; ILP = (payload[0] & 0x0f); payload_len -= 1; payload += 1; if (ILP > ILL) goto wrong_interleaving; } /* * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 * +-+-+-+-+-+-+-+-+.. * |F| FT |Q|P|P| more FT.. * +-+-+-+-+-+-+-+-+.. */ /* count number of packets by counting the FTs. Also * count number of amr data bytes and number of non-empty * packets (this is also the number of CRCs if present). */ amr_len = 0; num_nonempty_packets = 0; num_packets = 0; for (i = 0; i < payload_len; i++) { gint fr_size; guint8 FT; FT = (payload[i] & 0x78) >> 3; fr_size = frame_size[FT]; GST_DEBUG_OBJECT (rtpamrdepay, "frame size %d", fr_size); if (fr_size == -1) goto wrong_framesize; if (fr_size > 0) { amr_len += fr_size; num_nonempty_packets++; } num_packets++; if ((payload[i] & 0x80) == 0) break; } if (rtpamrdepay->crc) { /* data len + CRC len + header bytes should be smaller than payload_len */ if (num_packets + num_nonempty_packets + amr_len > payload_len) goto wrong_length_1; } else { /* data len + header bytes should be smaller than payload_len */ if (num_packets + amr_len > payload_len) goto wrong_length_2; } outbuf = gst_buffer_new_and_alloc (payload_len); /* point to destination */ p = GST_BUFFER_DATA (outbuf); /* point to first data packet */ dp = payload + num_packets; if (rtpamrdepay->crc) { /* skip CRC if present */ dp += num_nonempty_packets; } for (i = 0; i < num_packets; i++) { gint fr_size; /* copy FT, clear F bit */ *p++ = payload[i] & 0x7f; fr_size = frame_size[(payload[i] & 0x78) >> 3]; if (fr_size > 0) { /* copy data packet, FIXME, calc CRC here. */ memcpy (p, dp, fr_size); p += fr_size; dp += fr_size; } } /* we can set the duration because each packet is 20 milliseconds */ GST_BUFFER_DURATION (outbuf) = num_packets * 20 * GST_MSECOND; if (gst_rtp_buffer_get_marker (buf)) { /* marker bit marks a discont buffer after a talkspurt. */ GST_DEBUG_OBJECT (depayload, "marker bit was set"); GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); } GST_DEBUG_OBJECT (depayload, "pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); }