static GstPadProbeReturn drop_theora_config (GstPad *pad, GstPadProbeInfo *info, gpointer user_data) { GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info); GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; guint8 *payload; guint32 header; guchar TDT; gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtpbuffer); payload = gst_rtp_buffer_get_payload (&rtpbuffer); header = GST_READ_UINT32_BE (payload); /* * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Ident | F |TDT|# pkts.| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * F: Fragment type (0=none, 1=start, 2=cont, 3=end) * TDT: Theora data type (0=theora, 1=config, 2=comment, 3=reserved) * pkts: number of packets. */ TDT = (header & 0x30) >> 4; gst_rtp_buffer_unmap (&rtpbuffer); if (TDT == 1) return GST_PAD_PROBE_DROP; else return GST_PAD_PROBE_OK; }
static GstBuffer * generate_test_buffer_full (GstClockTime dts, guint seq_num, guint32 rtp_ts, guint ssrc) { GstBuffer *buf; guint8 *payload; guint i; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; buf = gst_rtp_buffer_new_allocate (TEST_BUF_SIZE, 0, 0); GST_BUFFER_DTS (buf) = dts; gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp); gst_rtp_buffer_set_payload_type (&rtp, TEST_BUF_PT); gst_rtp_buffer_set_seq (&rtp, seq_num); gst_rtp_buffer_set_timestamp (&rtp, rtp_ts); gst_rtp_buffer_set_ssrc (&rtp, ssrc); payload = gst_rtp_buffer_get_payload (&rtp); for (i = 0; i < TEST_BUF_SIZE; i++) payload[i] = 0xff; gst_rtp_buffer_unmap (&rtp); return buf; }
static GstBuffer * generate_test_buffer (guint seq_num, guint ssrc) { GstBuffer *buf; guint8 *payload; guint i; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; gsize size = 10; buf = gst_rtp_buffer_new_allocate (size, 0, 0); GST_BUFFER_DTS (buf) = GST_MSECOND * 20 * seq_num; GST_BUFFER_PTS (buf) = GST_MSECOND * 20 * seq_num; gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp); gst_rtp_buffer_set_payload_type (&rtp, 0); gst_rtp_buffer_set_seq (&rtp, seq_num); gst_rtp_buffer_set_timestamp (&rtp, 160 * seq_num); gst_rtp_buffer_set_ssrc (&rtp, ssrc); payload = gst_rtp_buffer_get_payload (&rtp); for (i = 0; i < size; i++) payload[i] = 0xff; gst_rtp_buffer_unmap (&rtp); return buf; }
static GstBuffer * generate_test_buffer (GstClockTime gst_ts, gboolean marker_bit, guint seq_num, guint32 rtp_ts, guint ssrc) { GstBuffer *buf; guint8 *payload; guint i; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; buf = gst_rtp_buffer_new_allocate (payload_size, 0, 0); GST_BUFFER_DTS (buf) = gst_ts; GST_BUFFER_PTS (buf) = gst_ts; gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp); gst_rtp_buffer_set_payload_type (&rtp, payload_type); gst_rtp_buffer_set_marker (&rtp, marker_bit); gst_rtp_buffer_set_seq (&rtp, seq_num); gst_rtp_buffer_set_timestamp (&rtp, rtp_ts); gst_rtp_buffer_set_ssrc (&rtp, ssrc); payload = gst_rtp_buffer_get_payload (&rtp); for (i = 0; i < payload_size; i++) payload[i] = 0xff; gst_rtp_buffer_unmap (&rtp); return buf; }
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); }
/** * gst_base_rtp_audio_payload_push: * @baseaudiopayload: a #GstBaseRTPPayload * @data: data to set as payload * @payload_len: length of payload * @timestamp: a #GstClockTime * * Create an RTP buffer and store @payload_len bytes of @data as the * payload. Set the timestamp on the new buffer to @timestamp before pushing * the buffer downstream. * * Returns: a #GstFlowReturn * * Since: 0.10.13 */ GstFlowReturn gst_base_rtp_audio_payload_push (GstBaseRTPAudioPayload * baseaudiopayload, const guint8 * data, guint payload_len, GstClockTime timestamp) { GstBaseRTPPayload *basepayload; GstBuffer *outbuf; guint8 *payload; GstFlowReturn ret; basepayload = GST_BASE_RTP_PAYLOAD (baseaudiopayload); GST_DEBUG_OBJECT (baseaudiopayload, "Pushing %d bytes ts %" GST_TIME_FORMAT, payload_len, GST_TIME_ARGS (timestamp)); /* create buffer to hold the payload */ outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0); /* copy payload */ payload = gst_rtp_buffer_get_payload (outbuf); memcpy (payload, data, payload_len); /* set metadata */ gst_base_rtp_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len, timestamp); ret = gst_basertppayload_push (basepayload, outbuf); return ret; }
static GstFlowReturn gst_rtp_celt_pay_flush_queued (GstRtpCELTPay * rtpceltpay) { GstFlowReturn ret; GstBuffer *buf, *outbuf; guint8 *payload, *spayload; guint payload_len; GstClockTime duration; GstRTPBuffer rtp = { NULL, }; payload_len = rtpceltpay->bytes + rtpceltpay->sbytes; duration = rtpceltpay->qduration; GST_DEBUG_OBJECT (rtpceltpay, "flushing out %u, duration %" GST_TIME_FORMAT, payload_len, GST_TIME_ARGS (rtpceltpay->qduration)); /* get a big enough packet for the sizes + payloads */ outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0); GST_BUFFER_DURATION (outbuf) = duration; gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); /* point to the payload for size headers and data */ spayload = gst_rtp_buffer_get_payload (&rtp); payload = spayload + rtpceltpay->sbytes; while ((buf = g_queue_pop_head (rtpceltpay->queue))) { guint size; /* copy first timestamp to output */ if (GST_BUFFER_TIMESTAMP (outbuf) == -1) GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf); /* write the size to the header */ size = gst_buffer_get_size (buf); while (size > 0xff) { *spayload++ = 0xff; size -= 0xff; } *spayload++ = size; /* copy payload */ size = gst_buffer_get_size (buf); gst_buffer_extract (buf, 0, payload, size); payload += size; gst_buffer_unref (buf); } gst_rtp_buffer_unmap (&rtp); /* we consumed it all */ rtpceltpay->bytes = 0; rtpceltpay->sbytes = 0; rtpceltpay->qduration = 0; ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpceltpay), outbuf); return ret; }
static GstFlowReturn gst_rtp_g723_pay_flush (GstRTPG723Pay * pay) { GstBuffer *outbuf; GstFlowReturn ret; guint8 *payload; guint avail; avail = gst_adapter_available (pay->adapter); outbuf = gst_rtp_buffer_new_allocate (avail, 0, 0); payload = gst_rtp_buffer_get_payload (outbuf); GST_BUFFER_TIMESTAMP (outbuf) = pay->timestamp; GST_BUFFER_DURATION (outbuf) = pay->duration; /* copy G723 data as payload */ gst_adapter_copy (pay->adapter, payload, 0, avail); /* flush bytes from adapter */ gst_adapter_flush (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 (outbuf, TRUE); pay->discont = FALSE; } ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (pay), outbuf); return ret; }
static GstFlowReturn gst_rtp_mp2t_pay_flush (GstRTPMP2TPay * rtpmp2tpay) { guint avail; guint8 *payload; GstFlowReturn ret; GstBuffer *outbuf; avail = gst_adapter_available (rtpmp2tpay->adapter); if (avail == 0) return GST_FLOW_OK; outbuf = gst_rtp_buffer_new_allocate (avail, 0, 0); /* get payload */ payload = gst_rtp_buffer_get_payload (outbuf); /* copy stuff from adapter to payload */ gst_adapter_copy (rtpmp2tpay->adapter, payload, 0, avail); GST_BUFFER_TIMESTAMP (outbuf) = rtpmp2tpay->first_ts; GST_BUFFER_DURATION (outbuf) = rtpmp2tpay->duration; GST_DEBUG_OBJECT (rtpmp2tpay, "pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmp2tpay), outbuf); /* flush the adapter content */ gst_adapter_flush (rtpmp2tpay->adapter, avail); return ret; }
/** * gst_rtp_base_audio_payload_push: * @baseaudiopayload: a #GstRTPBasePayload * @data: data to set as payload * @payload_len: length of payload * @timestamp: a #GstClockTime * * Create an RTP buffer and store @payload_len bytes of @data as the * payload. Set the timestamp on the new buffer to @timestamp before pushing * the buffer downstream. * * Returns: a #GstFlowReturn */ GstFlowReturn gst_rtp_base_audio_payload_push (GstRTPBaseAudioPayload * baseaudiopayload, const guint8 * data, guint payload_len, GstClockTime timestamp) { GstRTPBasePayload *basepayload; GstBuffer *outbuf; guint8 *payload; GstFlowReturn ret; GstRTPBuffer rtp = { NULL }; basepayload = GST_RTP_BASE_PAYLOAD (baseaudiopayload); GST_DEBUG_OBJECT (baseaudiopayload, "Pushing %d bytes ts %" GST_TIME_FORMAT, payload_len, GST_TIME_ARGS (timestamp)); /* create buffer to hold the payload */ outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, payload_len, 0, 0); /* copy payload */ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); payload = gst_rtp_buffer_get_payload (&rtp); memcpy (payload, data, payload_len); gst_rtp_buffer_unmap (&rtp); /* set metadata */ gst_rtp_base_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len, timestamp); ret = gst_rtp_base_payload_push (basepayload, outbuf); return ret; }
static GstFlowReturn gst_rtp_mpv_pay_flush (GstRTPMPVPay * rtpmpvpay, GstClockTime timestamp, GstClockTime duration) { GstBuffer *outbuf; GstFlowReturn ret; guint avail; guint8 *payload; gint packet_size; gint payload_size; avail = gst_adapter_available (rtpmpvpay->adapter); packet_size = gst_rtp_buffer_calc_packet_len (4 + avail, 0, 0); /* check for the maximum size of the rtp buffer */ if (packet_size > GST_BASE_RTP_PAYLOAD_MTU (rtpmpvpay)) { payload_size = GST_BASE_RTP_PAYLOAD_MTU (rtpmpvpay) - gst_rtp_buffer_calc_packet_len (4, 0, 0); } else { payload_size = avail; } outbuf = gst_rtp_buffer_new_allocate (4 + payload_size, 0, 0); /* enable 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 */ payload = gst_rtp_buffer_get_payload (outbuf); /* fill in the MPEG Video-specific header */ memset (payload, 0x0, 4); /* copy stuff from adapter to payload */ gst_adapter_copy (rtpmpvpay->adapter, payload + 4, 0, payload_size); GST_BUFFER_TIMESTAMP (outbuf) = rtpmpvpay->first_ts; GST_BUFFER_DURATION (outbuf) = rtpmpvpay->duration; GST_DEBUG_OBJECT (rtpmpvpay, "pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmpvpay), outbuf); gst_adapter_flush (rtpmpvpay->adapter, payload_size); /* update the timestamp and duration */ rtpmpvpay->first_ts = timestamp; rtpmpvpay->duration = duration; /* check if there is enough data for another rtp buffer */ avail = gst_adapter_available (rtpmpvpay->adapter); packet_size = gst_rtp_buffer_calc_packet_len (4 + avail, 0, 0); if (packet_size >= GST_BASE_RTP_PAYLOAD_MTU (rtpmpvpay) && ret == GST_FLOW_OK) { GST_DEBUG_OBJECT (rtpmpvpay, "Have enough data for another rtp packet"); ret = gst_rtp_mpv_pay_flush (rtpmpvpay, timestamp, duration); } return ret; }
GstAlBuf* gst_al_pull_rtp_buffer(GstAppSink *sink) { GstAlBuf *buf = g_new(GstAlBuf,1); buf->m_buffer = gst_app_sink_pull_buffer(sink); buf->m_dptr = gst_rtp_buffer_get_payload(buf->m_buffer); buf->m_dlen = gst_rtp_buffer_get_payload_len(buf->m_buffer); return buf; }
GstAlBuf* gst_al_alloc_rtp_buffer(guint payload_len, guint8 pad_len, guint8 csrc_count) { GstAlBuf *buf = g_new(GstAlBuf,1); buf->m_buffer = gst_rtp_buffer_new_allocate(payload_len, pad_len, csrc_count); buf->m_dptr = gst_rtp_buffer_get_payload(buf->m_buffer); buf->m_dlen = gst_rtp_buffer_get_payload_len(buf->m_buffer); return buf; }
static GstFlowReturn gst_rtp_sbc_pay_flush_buffers (GstRtpSBCPay * sbcpay) { GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; guint available; guint max_payload; GstBuffer *outbuf; guint8 *payload_data; guint frame_count; guint payload_length; struct rtp_payload *payload; if (sbcpay->frame_length == 0) { GST_ERROR_OBJECT (sbcpay, "Frame length is 0"); return GST_FLOW_ERROR; } available = gst_adapter_available (sbcpay->adapter); max_payload = gst_rtp_buffer_calc_payload_len (GST_RTP_BASE_PAYLOAD_MTU (sbcpay) - RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0); max_payload = MIN (max_payload, available); frame_count = max_payload / sbcpay->frame_length; payload_length = frame_count * sbcpay->frame_length; if (payload_length == 0) /* Nothing to send */ return GST_FLOW_OK; outbuf = gst_rtp_buffer_new_allocate (payload_length + RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0); /* get payload */ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); gst_rtp_buffer_set_payload_type (&rtp, GST_RTP_BASE_PAYLOAD_PT (sbcpay)); /* write header and copy data into payload */ payload_data = gst_rtp_buffer_get_payload (&rtp); payload = (struct rtp_payload *) payload_data; memset (payload, 0, sizeof (struct rtp_payload)); payload->frame_count = frame_count; gst_adapter_copy (sbcpay->adapter, payload_data + RTP_SBC_PAYLOAD_HEADER_SIZE, 0, payload_length); gst_rtp_buffer_unmap (&rtp); gst_adapter_flush (sbcpay->adapter, payload_length); /* FIXME: what about duration? */ GST_BUFFER_PTS (outbuf) = sbcpay->timestamp; GST_DEBUG_OBJECT (sbcpay, "Pushing %d bytes", payload_length); return gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (sbcpay), outbuf); }
static GstFlowReturn gst_rtp_mpv_pay_flush (GstRTPMPVPay * rtpmpvpay) { GstBuffer *outbuf; GstFlowReturn ret; guint avail; guint8 *payload; avail = gst_adapter_available (rtpmpvpay->adapter); ret = GST_FLOW_OK; while (avail > 0) { guint towrite; guint packet_len; guint payload_len; packet_len = gst_rtp_buffer_calc_packet_len (avail, 4, 0); towrite = MIN (packet_len, GST_BASE_RTP_PAYLOAD_MTU (rtpmpvpay)); payload_len = gst_rtp_buffer_calc_payload_len (towrite, 4, 0); outbuf = gst_rtp_buffer_new_allocate (payload_len, 4, 0); payload = gst_rtp_buffer_get_payload (outbuf); /* enable 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 */ /* fill in the MPEG Video-specific header * data is set to 0x0 here */ memset (payload, 0x0, 4); gst_adapter_copy (rtpmpvpay->adapter, payload + 4, 0, payload_len); gst_adapter_flush (rtpmpvpay->adapter, payload_len); avail -= payload_len; gst_rtp_buffer_set_marker (outbuf, avail == 0); GST_BUFFER_TIMESTAMP (outbuf) = rtpmpvpay->first_ts; ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmpvpay), outbuf); } return ret; }
static GstBuffer * gst_rtp_dtmf_src_create_next_rtp_packet (GstRTPDTMFSrc * dtmfsrc) { GstBuffer *buf; GstRTPDTMFPayload *payload; GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; buf = gst_rtp_buffer_new_allocate (sizeof (GstRTPDTMFPayload), 0, 0); gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtpbuffer); gst_rtp_dtmf_prepare_rtp_headers (dtmfsrc, &rtpbuffer); /* timestamp and duration of GstBuffer */ /* Redundant buffer have no duration ... */ if (dtmfsrc->redundancy_count > 1) GST_BUFFER_DURATION (buf) = 0; else GST_BUFFER_DURATION (buf) = dtmfsrc->ptime * GST_MSECOND; GST_BUFFER_PTS (buf) = dtmfsrc->timestamp; payload = (GstRTPDTMFPayload *) gst_rtp_buffer_get_payload (&rtpbuffer); /* copy payload and convert to network-byte order */ memmove (payload, dtmfsrc->payload, sizeof (GstRTPDTMFPayload)); payload->duration = g_htons (payload->duration); if (dtmfsrc->redundancy_count <= 1 && dtmfsrc->last_packet) { GstClockTime inter_digit_interval = MIN_INTER_DIGIT_INTERVAL; if (inter_digit_interval % dtmfsrc->ptime != 0) inter_digit_interval += dtmfsrc->ptime - (MIN_INTER_DIGIT_INTERVAL % dtmfsrc->ptime); GST_BUFFER_DURATION (buf) += inter_digit_interval * GST_MSECOND; } GST_LOG_OBJECT (dtmfsrc, "Creating new buffer with event %u duration " " gst: %" GST_TIME_FORMAT " at %" GST_TIME_FORMAT "(rtp ts:%u dur:%u)", dtmfsrc->payload->event, GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), dtmfsrc->rtp_timestamp, dtmfsrc->payload->duration); /* duration of DTMF payloadfor the NEXT packet */ /* not updated for redundant packets */ if (dtmfsrc->redundancy_count <= 1) dtmfsrc->payload->duration += dtmfsrc->ptime * dtmfsrc->clock_rate / 1000; if (GST_CLOCK_TIME_IS_VALID (dtmfsrc->timestamp)) dtmfsrc->timestamp += GST_BUFFER_DURATION (buf); gst_rtp_buffer_unmap (&rtpbuffer); return buf; }
static GstFlowReturn gst_rtp_mp4v_pay_flush (GstRtpMP4VPay * rtpmp4vpay) { guint avail; GstBuffer *outbuf; GstFlowReturn ret; /* the data available in the adapter is either smaller * than the MTU or bigger. In the case it is smaller, the complete * adapter contents can be put in one packet. In the case the * adapter has more than one MTU, we need to split the MP4V data * over multiple packets. */ avail = gst_adapter_available (rtpmp4vpay->adapter); ret = GST_FLOW_OK; while (avail > 0) { guint towrite; guint8 *payload; guint payload_len; guint packet_len; /* this will be the total lenght of the packet */ packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0); /* fill one MTU or all available bytes */ towrite = MIN (packet_len, GST_BASE_RTP_PAYLOAD_MTU (rtpmp4vpay)); /* this is the payload length */ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0); /* create buffer to hold the payload */ outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0); /* copy payload */ payload = gst_rtp_buffer_get_payload (outbuf); gst_adapter_copy (rtpmp4vpay->adapter, payload, 0, payload_len); gst_adapter_flush (rtpmp4vpay->adapter, payload_len); avail -= payload_len; gst_rtp_buffer_set_marker (outbuf, avail == 0); GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4vpay->first_timestamp; ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmp4vpay), outbuf); } return ret; }
static GstFlowReturn gst_rtp_gsm_pay_handle_buffer (GstBaseRTPPayload * basepayload, GstBuffer * buffer) { GstRTPGSMPay *rtpgsmpay; guint size, payload_len; GstBuffer *outbuf; guint8 *payload, *data; GstClockTime timestamp, duration; GstFlowReturn ret; rtpgsmpay = GST_RTP_GSM_PAY (basepayload); size = GST_BUFFER_SIZE (buffer); timestamp = GST_BUFFER_TIMESTAMP (buffer); duration = GST_BUFFER_DURATION (buffer); /* FIXME, only one GSM frame per RTP packet for now */ payload_len = size; /* FIXME, just error out for now */ if (payload_len > GST_BASE_RTP_PAYLOAD_MTU (rtpgsmpay)) { GST_ELEMENT_ERROR (rtpgsmpay, STREAM, ENCODE, (NULL), ("payload_len %u > mtu %u", payload_len, GST_BASE_RTP_PAYLOAD_MTU (rtpgsmpay))); return GST_FLOW_ERROR; } outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0); /* copy timestamp and duration */ GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = duration; /* get payload */ payload = gst_rtp_buffer_get_payload (outbuf); data = GST_BUFFER_DATA (buffer); /* copy data in payload */ memcpy (&payload[0], data, size); gst_buffer_unref (buffer); GST_DEBUG ("gst_rtp_gsm_pay_chain: pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); ret = gst_basertppayload_push (basepayload, outbuf); return ret; }
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 GstBuffer * gst_rtp_ac3_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpAC3Depay *rtpac3depay; GstBuffer *outbuf; rtpac3depay = GST_RTP_AC3_DEPAY (depayload); { guint8 *payload; guint16 FT, NF; if (gst_rtp_buffer_get_payload_len (buf) < 2) goto empty_packet; payload = gst_rtp_buffer_get_payload (buf); /* strip off header * * 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MBZ | FT| NF | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ FT = payload[0] & 0x3; NF = payload[1]; GST_DEBUG_OBJECT (rtpac3depay, "FT: %d, NF: %d", FT, NF); /* We don't bother with fragmented packets yet */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1); GST_DEBUG_OBJECT (rtpac3depay, "pushing buffer of size %d", GST_BUFFER_SIZE (outbuf)); return outbuf; } return NULL; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpac3depay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } }
static GstFlowReturn gst_rtp_sbc_pay_flush_buffers(GstRtpSBCPay *sbcpay) { guint available; guint max_payload; GstBuffer *outbuf; guint8 *payload_data; guint frame_count; guint payload_length; struct rtp_payload *payload; if (sbcpay->frame_length == 0) { GST_ERROR_OBJECT(sbcpay, "Frame length is 0"); return GST_FLOW_ERROR; } available = gst_adapter_available(sbcpay->adapter); max_payload = gst_rtp_buffer_calc_payload_len( GST_BASE_RTP_PAYLOAD_MTU(sbcpay) - RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0); max_payload = MIN(max_payload, available); frame_count = max_payload / sbcpay->frame_length; payload_length = frame_count * sbcpay->frame_length; if (payload_length == 0) /* Nothing to send */ return GST_FLOW_OK; outbuf = gst_rtp_buffer_new_allocate(payload_length + RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0); gst_rtp_buffer_set_payload_type(outbuf, GST_BASE_RTP_PAYLOAD_PT(sbcpay)); payload_data = gst_rtp_buffer_get_payload(outbuf); payload = (struct rtp_payload *) payload_data; memset(payload, 0, sizeof(struct rtp_payload)); payload->frame_count = frame_count; gst_adapter_copy(sbcpay->adapter, payload_data + RTP_SBC_PAYLOAD_HEADER_SIZE, 0, payload_length); gst_adapter_flush(sbcpay->adapter, payload_length); GST_BUFFER_TIMESTAMP(outbuf) = sbcpay->timestamp; GST_DEBUG_OBJECT(sbcpay, "Pushing %d bytes", payload_length); return gst_basertppayload_push(GST_BASE_RTP_PAYLOAD(sbcpay), outbuf); }
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 * create_rtp_buffer (guint32 ssrc, guint8 payload_type, guint16 seqnum) { GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT; guint payload_size = 29; guint64 timestamp = gst_util_uint64_scale_int (seqnum, 90000, 30); GstBuffer *buf = gst_rtp_buffer_new_allocate (payload_size, 0, 0); gst_rtp_buffer_map (buf, GST_MAP_WRITE, &rtpbuf); gst_rtp_buffer_set_ssrc (&rtpbuf, ssrc); gst_rtp_buffer_set_payload_type (&rtpbuf, payload_type); gst_rtp_buffer_set_seq (&rtpbuf, seqnum); gst_rtp_buffer_set_timestamp (&rtpbuf, (guint32) timestamp); memset (gst_rtp_buffer_get_payload (&rtpbuf), 0x29, payload_size); gst_rtp_buffer_unmap (&rtpbuf); return buf; }
static void send_rtp_packet (GstPad * src, guint timestamp, gboolean marker, gboolean end, guint number, guint volume, guint duration) { GstBuffer *buf; GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT; gchar *payload; static guint seqnum = 1; buf = gst_rtp_buffer_new_allocate (4, 0, 0); fail_unless (gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtpbuf)); gst_rtp_buffer_set_seq (&rtpbuf, seqnum++); gst_rtp_buffer_set_timestamp (&rtpbuf, timestamp); gst_rtp_buffer_set_marker (&rtpbuf, marker); payload = gst_rtp_buffer_get_payload (&rtpbuf); payload[0] = number; payload[1] = volume | (end ? END_BIT : 0); GST_WRITE_UINT16_BE (payload + 2, duration); gst_rtp_buffer_unmap (&rtpbuf); fail_unless (gst_pad_push (src, buf) == GST_FLOW_OK); }
static void gst_rtp_dtmf_prepare_buffer_data (GstRTPDTMFSrc * dtmfsrc, GstBuffer * buf) { GstRTPDTMFPayload *payload; gst_rtp_dtmf_prepare_rtp_headers (dtmfsrc, buf); /* timestamp and duration of GstBuffer */ /* Redundant buffer have no duration ... */ if (dtmfsrc->redundancy_count > 1) GST_BUFFER_DURATION (buf) = 0; else GST_BUFFER_DURATION (buf) = dtmfsrc->interval * GST_MSECOND; GST_BUFFER_TIMESTAMP (buf) = dtmfsrc->timestamp; dtmfsrc->timestamp += GST_BUFFER_DURATION (buf); payload = (GstRTPDTMFPayload *) gst_rtp_buffer_get_payload (buf); /* copy payload and convert to network-byte order */ g_memmove (payload, dtmfsrc->payload, sizeof (GstRTPDTMFPayload)); /* Force the packet duration to a certain minumum * if its the end of the event */ if (payload->e && payload->duration < MIN_PULSE_DURATION * dtmfsrc->clock_rate / 1000) payload->duration = MIN_PULSE_DURATION * dtmfsrc->clock_rate / 1000; payload->duration = g_htons (payload->duration); /* duration of DTMF payloadfor the NEXT packet */ /* not updated for redundant packets */ if (dtmfsrc->redundancy_count == 0) dtmfsrc->payload->duration += dtmfsrc->interval * dtmfsrc->clock_rate / 1000; }
static void send_dmtf_havedata_handler (GstPad *pad, GstBuffer *buf, gpointer user_data) { gchar *data; ts_fail_unless (gst_rtp_buffer_validate (buf), "Buffer is not valid rtp"); if (gst_rtp_buffer_get_payload_type (buf) != dtmf_id) return; data = gst_rtp_buffer_get_payload (buf); if (data[0] < digit) { /* Still on previou digit */ return; } ts_fail_if (data[0] != digit, "Not sending the right digit" " (sending %d, should be %d", data[0], digit); received = TRUE; }
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 GstFlowReturn gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer) { GstRTPBasePayload *rtppay; GstAsfPacketInfo *packetinfo; guint8 flags; guint8 *data; guint32 packet_util_size; guint32 packet_offset; guint32 size_left; GstFlowReturn ret = GST_FLOW_OK; rtppay = GST_RTP_BASE_PAYLOAD (rtpasfpay); packetinfo = &rtpasfpay->packetinfo; if (!gst_asf_parse_packet (buffer, packetinfo, TRUE, rtpasfpay->asfinfo.packet_size)) { GST_ERROR_OBJECT (rtpasfpay, "Error while parsing asf packet"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } if (packetinfo->packet_size == 0) packetinfo->packet_size = rtpasfpay->asfinfo.packet_size; GST_LOG_OBJECT (rtpasfpay, "Packet size: %" G_GUINT32_FORMAT ", padding: %" G_GUINT32_FORMAT, packetinfo->packet_size, packetinfo->padding); /* update padding field to 0 */ if (packetinfo->padding > 0) { GstAsfPacketInfo info; /* find padding field offset */ guint offset = packetinfo->err_cor_len + 2 + gst_asf_get_var_size_field_len (packetinfo->packet_field_type) + gst_asf_get_var_size_field_len (packetinfo->seq_field_type); buffer = gst_buffer_make_writable (buffer); switch (packetinfo->padd_field_type) { case ASF_FIELD_TYPE_DWORD: gst_buffer_memset (buffer, offset, 0, 4); break; case ASF_FIELD_TYPE_WORD: gst_buffer_memset (buffer, offset, 0, 2); break; case ASF_FIELD_TYPE_BYTE: gst_buffer_memset (buffer, offset, 0, 1); break; case ASF_FIELD_TYPE_NONE: default: break; } gst_asf_parse_packet (buffer, &info, FALSE, 0); } if (packetinfo->padding != 0) packet_util_size = rtpasfpay->asfinfo.packet_size - packetinfo->padding; else packet_util_size = packetinfo->packet_size; packet_offset = 0; while (packet_util_size > 0) { /* Even if we don't fill completely an output buffer we * push it when we add an fragment. Because it seems that * it is not possible to determine where a asf packet * fragment ends inside a rtp packet payload. * This flag tells us to push the packet. */ gboolean force_push = FALSE; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; /* we have no output buffer pending, create one */ if (rtpasfpay->current == NULL) { GST_LOG_OBJECT (rtpasfpay, "Creating new output buffer"); rtpasfpay->current = gst_rtp_buffer_new_allocate_len (GST_RTP_BASE_PAYLOAD_MTU (rtpasfpay), 0, 0); rtpasfpay->cur_off = 0; rtpasfpay->has_ts = FALSE; rtpasfpay->marker = FALSE; } gst_rtp_buffer_map (rtpasfpay->current, GST_MAP_READWRITE, &rtp); data = gst_rtp_buffer_get_payload (&rtp); data += rtpasfpay->cur_off; size_left = gst_rtp_buffer_get_payload_len (&rtp) - rtpasfpay->cur_off; GST_DEBUG_OBJECT (rtpasfpay, "Input buffer bytes consumed: %" G_GUINT32_FORMAT "/%" G_GSIZE_FORMAT, packet_offset, gst_buffer_get_size (buffer)); GST_DEBUG_OBJECT (rtpasfpay, "Output rtpbuffer status"); GST_DEBUG_OBJECT (rtpasfpay, "Current offset: %" G_GUINT32_FORMAT, rtpasfpay->cur_off); GST_DEBUG_OBJECT (rtpasfpay, "Size left: %" G_GUINT32_FORMAT, size_left); GST_DEBUG_OBJECT (rtpasfpay, "Has ts: %s", rtpasfpay->has_ts ? "yes" : "no"); if (rtpasfpay->has_ts) { GST_DEBUG_OBJECT (rtpasfpay, "Ts: %" G_GUINT32_FORMAT, rtpasfpay->ts); } flags = 0; if (packetinfo->has_keyframe) { flags = flags | 0x80; } flags = flags | 0x20; /* Relative timestamp is present */ if (!rtpasfpay->has_ts) { /* this is the first asf packet, its send time is the * rtp packet timestamp */ rtpasfpay->has_ts = TRUE; rtpasfpay->ts = packetinfo->send_time; } if (size_left >= packet_util_size + 8) { /* enough space for the rest of the packet */ if (packet_offset == 0) { flags = flags | 0x40; GST_WRITE_UINT24_BE (data + 1, packet_util_size); } else { GST_WRITE_UINT24_BE (data + 1, packet_offset); force_push = TRUE; } data[0] = flags; GST_WRITE_UINT32_BE (data + 4, (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts); gst_buffer_extract (buffer, packet_offset, data + 8, packet_util_size); /* updating status variables */ rtpasfpay->cur_off += 8 + packet_util_size; size_left -= packet_util_size + 8; packet_offset += packet_util_size; packet_util_size = 0; rtpasfpay->marker = TRUE; } else { /* fragment packet */ data[0] = flags; GST_WRITE_UINT24_BE (data + 1, packet_offset); GST_WRITE_UINT32_BE (data + 4, (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts); gst_buffer_extract (buffer, packet_offset, data + 8, size_left - 8); /* updating status variables */ rtpasfpay->cur_off += size_left; packet_offset += size_left - 8; packet_util_size -= size_left - 8; size_left = 0; force_push = TRUE; } /* there is not enough room for any more buffers */ if (force_push || size_left <= 8) { gst_rtp_buffer_set_ssrc (&rtp, rtppay->current_ssrc); gst_rtp_buffer_set_marker (&rtp, rtpasfpay->marker); gst_rtp_buffer_set_payload_type (&rtp, GST_RTP_BASE_PAYLOAD_PT (rtppay)); gst_rtp_buffer_set_seq (&rtp, rtppay->seqnum + 1); gst_rtp_buffer_set_timestamp (&rtp, packetinfo->send_time); gst_rtp_buffer_unmap (&rtp); /* trim remaining bytes not used */ if (size_left != 0) { gst_buffer_set_size (rtpasfpay->current, gst_buffer_get_size (rtpasfpay->current) - size_left); } GST_BUFFER_TIMESTAMP (rtpasfpay->current) = GST_BUFFER_TIMESTAMP (buffer); rtppay->seqnum++; rtppay->timestamp = packetinfo->send_time; GST_DEBUG_OBJECT (rtpasfpay, "Pushing rtp buffer"); ret = gst_rtp_base_payload_push (rtppay, rtpasfpay->current); rtpasfpay->current = NULL; if (ret != GST_FLOW_OK) { gst_buffer_unref (buffer); return ret; } } } gst_buffer_unref (buffer); 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 GstFlowReturn gst_rtp_speex_pay_handle_buffer (GstBaseRTPPayload * basepayload, GstBuffer * buffer) { GstRtpSPEEXPay *rtpspeexpay; guint size, payload_len; GstBuffer *outbuf; guint8 *payload, *data; GstClockTime timestamp, duration; GstFlowReturn ret; rtpspeexpay = GST_RTP_SPEEX_PAY (basepayload); size = GST_BUFFER_SIZE (buffer); data = GST_BUFFER_DATA (buffer); switch (rtpspeexpay->packet) { case 0: /* ident packet. We need to parse the headers to construct the RTP * properties. */ if (!gst_rtp_speex_pay_parse_ident (rtpspeexpay, data, size)) goto parse_error; ret = GST_FLOW_OK; goto done; case 1: /* comment packet, we ignore it */ ret = GST_FLOW_OK; goto done; default: /* other packets go in the payload */ break; } if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_GAP)) { ret = GST_FLOW_OK; goto done; } timestamp = GST_BUFFER_TIMESTAMP (buffer); duration = GST_BUFFER_DURATION (buffer); /* FIXME, only one SPEEX frame per RTP packet for now */ payload_len = size; outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0); /* FIXME, assert for now */ g_assert (payload_len <= GST_BASE_RTP_PAYLOAD_MTU (rtpspeexpay)); /* copy timestamp and duration */ GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = duration; /* get payload */ payload = gst_rtp_buffer_get_payload (outbuf); /* copy data in payload */ memcpy (&payload[0], data, size); ret = gst_basertppayload_push (basepayload, outbuf); done: gst_buffer_unref (buffer); rtpspeexpay->packet++; return ret; /* ERRORS */ parse_error: { GST_ELEMENT_ERROR (rtpspeexpay, STREAM, DECODE, (NULL), ("Error parsing first identification packet.")); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } }