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 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_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 (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; }
/** * 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_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; }
static GstFlowReturn gst_rtp_opus_pay_handle_buffer (GstRTPBasePayload * basepayload, GstBuffer * buffer) { GstBuffer *outbuf; GstClockTime pts, dts, duration; CopyMetaData data; pts = GST_BUFFER_PTS (buffer); dts = GST_BUFFER_DTS (buffer); duration = GST_BUFFER_DURATION (buffer); outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); data.pay = GST_RTP_OPUS_PAY (basepayload); data.outbuf = outbuf; gst_buffer_foreach_meta (buffer, foreach_metadata, &data); outbuf = gst_buffer_append (outbuf, buffer); GST_BUFFER_PTS (outbuf) = pts; GST_BUFFER_DTS (outbuf) = dts; GST_BUFFER_DURATION (outbuf) = duration; /* Push out */ return gst_rtp_base_payload_push (basepayload, outbuf); }
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_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 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_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 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); }
/** * gst_rtp_buffer_new_allocate_len: * @packet_len: the total length of the packet * @pad_len: the amount of padding * @csrc_count: the number of CSRC entries * * Create a new #GstBuffer that can hold an RTP packet that is exactly * @packet_len long. The length of the payload depends on @pad_len and * @csrc_count and can be calculated with gst_rtp_buffer_calc_payload_len(). * All RTP header fields will be set to 0/FALSE. * * Returns: A newly allocated buffer that can hold an RTP packet of @packet_len. */ GstBuffer * gst_rtp_buffer_new_allocate_len (guint packet_len, guint8 pad_len, guint8 csrc_count) { guint len; g_return_val_if_fail (csrc_count <= 15, NULL); len = gst_rtp_buffer_calc_payload_len (packet_len, pad_len, csrc_count); return gst_rtp_buffer_new_allocate (len, pad_len, csrc_count); }
static GstFlowReturn gst_rtp_opus_pay_handle_buffer (GstRTPBasePayload * basepayload, GstBuffer * buffer) { GstBuffer *outbuf; outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); outbuf = gst_buffer_append (outbuf, gst_buffer_ref (buffer)); /* Push out */ return gst_rtp_base_payload_push (basepayload, outbuf); }
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 GstFlowReturn gst_rtp_mp2t_pay_flush (GstRTPMP2TPay * rtpmp2tpay) { guint avail, mtu; GstFlowReturn ret = GST_FLOW_OK; GstBuffer *outbuf; avail = gst_adapter_available (rtpmp2tpay->adapter); mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp2tpay); while (avail > 0 && (ret == GST_FLOW_OK)) { guint towrite; guint payload_len; guint packet_len; GstBuffer *paybuf; /* this will be the total length 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, mtu); /* this is the payload length */ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0); payload_len -= payload_len % 188; /* need whole packets */ if (!payload_len) break; /* create buffer to hold the payload */ outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); /* get payload */ paybuf = gst_adapter_take_buffer_fast (rtpmp2tpay->adapter, payload_len); gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpmp2tpay), outbuf, paybuf, 0); outbuf = gst_buffer_append (outbuf, paybuf); avail -= payload_len; GST_BUFFER_PTS (outbuf) = rtpmp2tpay->first_ts; GST_BUFFER_DURATION (outbuf) = rtpmp2tpay->duration; GST_DEBUG_OBJECT (rtpmp2tpay, "pushing buffer of size %u", (guint) gst_buffer_get_size (outbuf)); ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmp2tpay), outbuf); } return ret; }
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 (GstRTPBasePayload * basepayload, GstBuffer * buffer) { GstRTPGSMPay *rtpgsmpay; guint payload_len; GstBuffer *outbuf; GstClockTime timestamp, duration; GstFlowReturn ret; rtpgsmpay = GST_RTP_GSM_PAY (basepayload); timestamp = GST_BUFFER_PTS (buffer); duration = GST_BUFFER_DURATION (buffer); /* FIXME, only one GSM frame per RTP packet for now */ payload_len = gst_buffer_get_size (buffer); /* FIXME, just error out for now */ if (payload_len > GST_RTP_BASE_PAYLOAD_MTU (rtpgsmpay)) goto too_big; outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0); /* copy timestamp and duration */ GST_BUFFER_PTS (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = duration; gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpgsmpay), outbuf, buffer, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); /* append payload */ outbuf = gst_buffer_append (outbuf, buffer); GST_DEBUG ("gst_rtp_gsm_pay_chain: pushing buffer of size %" G_GSIZE_FORMAT, gst_buffer_get_size (outbuf)); ret = gst_rtp_base_payload_push (basepayload, outbuf); return ret; /* ERRORS */ too_big: { GST_ELEMENT_ERROR (rtpgsmpay, STREAM, ENCODE, (NULL), ("payload_len %u > mtu %u", payload_len, GST_RTP_BASE_PAYLOAD_MTU (rtpgsmpay))); return GST_FLOW_ERROR; } }
static GstBuffer * gst_rtp_dtmf_src_create_next_rtp_packet (GstRTPDTMFSrc * dtmfsrc) { GstBuffer *buf = NULL; /* create buffer to hold the payload */ buf = gst_rtp_buffer_new_allocate (sizeof (GstRTPDTMFPayload), 0, 0); gst_rtp_dtmf_prepare_buffer_data (dtmfsrc, buf); /* Set caps on the buffer before pushing it */ gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (dtmfsrc))); return buf; }
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 * 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; }
/* Create a RTP buffer without the extension */ static GstBuffer * create_rtp_buffer (GstClockTime timestamp, gboolean clean_point) { GstBuffer *buffer_in; GstRTPBuffer rtpbuffer_in = GST_RTP_BUFFER_INIT; buffer_in = gst_rtp_buffer_new_allocate (0, 0, 0); GST_BUFFER_PTS (buffer_in) = timestamp; if (!clean_point) GST_BUFFER_FLAG_SET (buffer_in, GST_BUFFER_FLAG_DELTA_UNIT); fail_unless (gst_rtp_buffer_map (buffer_in, GST_MAP_READ, &rtpbuffer_in)); fail_if (gst_rtp_buffer_get_extension (&rtpbuffer_in)); gst_rtp_buffer_unmap (&rtpbuffer_in); return buffer_in; }
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 GstFlowReturn gst_rtp_g723_pay_flush (GstRTPG723Pay * pay) { GstBuffer *outbuf, *payload_buf; GstFlowReturn ret; guint avail; GstRTPBuffer rtp = { NULL }; avail = gst_adapter_available (pay->adapter); outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); GST_BUFFER_PTS (outbuf) = pay->timestamp; GST_BUFFER_DURATION (outbuf) = pay->duration; /* copy G723 data as payload */ payload_buf = gst_adapter_take_buffer_fast (pay->adapter, avail); pay->timestamp = GST_CLOCK_TIME_NONE; pay->duration = 0; /* set discont and marker */ if (pay->discont) { GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); gst_rtp_buffer_set_marker (&rtp, TRUE); pay->discont = FALSE; } gst_rtp_buffer_unmap (&rtp); gst_rtp_copy_meta (GST_ELEMENT_CAST (pay), outbuf, payload_buf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); outbuf = gst_buffer_append (outbuf, payload_buf); ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (pay), outbuf); return ret; }
static void lock_check_cb (GstPad * pad, int i) { GstBuffer *inbuf; if (i % 2) { fail_unless (buffers == NULL); } else { GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; fail_unless (buffers && g_list_length (buffers) == 1); gst_rtp_buffer_map (buffers->data, GST_MAP_READ, &rtpbuffer); fail_unless_equals_int (66, gst_rtp_buffer_get_ssrc (&rtpbuffer)); fail_unless_equals_int64 (200 - 57 + 1000 + i, gst_rtp_buffer_get_timestamp (&rtpbuffer)); fail_unless_equals_int (100 + 1 + i, gst_rtp_buffer_get_seq (&rtpbuffer)); gst_rtp_buffer_unmap (&rtpbuffer); inbuf = gst_rtp_buffer_new_allocate (10, 0, 0); GST_BUFFER_PTS (inbuf) = i * 1000 + 500; GST_BUFFER_DURATION (inbuf) = 1000; gst_rtp_buffer_map (inbuf, GST_MAP_WRITE, &rtpbuffer); gst_rtp_buffer_set_version (&rtpbuffer, 2); gst_rtp_buffer_set_payload_type (&rtpbuffer, 98); gst_rtp_buffer_set_ssrc (&rtpbuffer, 44); gst_rtp_buffer_set_timestamp (&rtpbuffer, 200 + i); gst_rtp_buffer_set_seq (&rtpbuffer, 2000 + i); gst_rtp_buffer_unmap (&rtpbuffer); fail_unless (gst_pad_push (pad, inbuf) == GST_FLOW_OK); g_list_foreach (buffers, (GFunc) gst_buffer_unref, NULL); g_list_free (buffers); buffers = NULL; } }
static GstFlowReturn gst_rtp_klv_pay_handle_buffer (GstRTPBasePayload * basepayload, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; GstBufferList *list = NULL; GstRtpKlvPay *pay; GstMapInfo map; GstBuffer *outbuf = NULL; gsize offset; guint mtu, rtp_header_size, max_payload_size; pay = GST_RTP_KLV_PAY (basepayload); mtu = GST_RTP_BASE_PAYLOAD_MTU (basepayload); rtp_header_size = gst_rtp_buffer_calc_header_len (0); max_payload_size = mtu - rtp_header_size; gst_buffer_map (buf, &map, GST_MAP_READ); if (map.size == 0) goto done; /* KLV coding shall use and only use a fixed 16-byte SMPTE-administered * Universal Label, according to SMPTE 298M as Key (Rec. ITU R-BT.1653-1) */ if (map.size < 16 || GST_READ_UINT32_BE (map.data) != 0x060E2B34) goto bad_input; if (map.size > max_payload_size) list = gst_buffer_list_new (); GST_LOG_OBJECT (pay, "%" G_GSIZE_FORMAT " bytes of data to payload", map.size); offset = 0; while (offset < map.size) { GstBuffer *payloadbuf; GstRTPBuffer rtp = { NULL }; guint payload_size; guint bytes_left; bytes_left = map.size - offset; payload_size = MIN (bytes_left, max_payload_size); outbuf = gst_rtp_buffer_new_allocate (0, 0, 0); if (payload_size == bytes_left) { GST_LOG_OBJECT (pay, "last packet of KLV unit"); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); gst_rtp_buffer_set_marker (&rtp, 1); gst_rtp_buffer_unmap (&rtp); } GST_LOG_OBJECT (pay, "packet with payload size %u", payload_size); gst_rtp_copy_meta (GST_ELEMENT_CAST (pay), outbuf, buf, 0); payloadbuf = gst_buffer_copy_region (buf, GST_BUFFER_COPY_MEMORY, offset, payload_size); /* join rtp header + payload memory parts */ outbuf = gst_buffer_append (outbuf, payloadbuf); GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf); GST_BUFFER_DTS (outbuf) = GST_BUFFER_DTS (buf); /* and add to list */ if (list != NULL) gst_buffer_list_insert (list, -1, outbuf); offset += payload_size; } done: gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); if (list != NULL) ret = gst_rtp_base_payload_push_list (basepayload, list); else if (outbuf != NULL) ret = gst_rtp_base_payload_push (basepayload, outbuf); return ret; /* ERRORS */ bad_input: { GST_ERROR_OBJECT (pay, "Input doesn't look like a KLV packet, ignoring"); goto done; } }
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; } }
static GstFlowReturn gst_rtp_mpa_pay_flush (GstRtpMPAPay * rtpmpapay) { guint avail; GstBuffer *outbuf; GstFlowReturn ret; guint16 frag_offset; GstBufferList *list; /* 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 MPA data * over multiple packets. The frag_offset in each packet header * needs to be updated with the position in the MPA frame. */ avail = gst_adapter_available (rtpmpapay->adapter); ret = GST_FLOW_OK; list = gst_buffer_list_new_sized (avail / (GST_RTP_BASE_PAYLOAD_MTU (rtpmpapay) - RTP_HEADER_LEN) + 1); frag_offset = 0; while (avail > 0) { guint towrite; guint8 *payload; guint payload_len; guint packet_len; GstRTPBuffer rtp = { NULL }; GstBuffer *paybuf; /* this will be the total length of the packet */ packet_len = gst_rtp_buffer_calc_packet_len (4 + avail, 0, 0); /* fill one MTU or all available bytes */ towrite = MIN (packet_len, GST_RTP_BASE_PAYLOAD_MTU (rtpmpapay)); /* 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 (4, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); payload_len -= 4; gst_rtp_buffer_set_payload_type (&rtp, GST_RTP_PAYLOAD_MPA); /* * 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 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ payload = gst_rtp_buffer_get_payload (&rtp); payload[0] = 0; payload[1] = 0; payload[2] = frag_offset >> 8; payload[3] = frag_offset & 0xff; avail -= payload_len; frag_offset += payload_len; if (avail == 0) gst_rtp_buffer_set_marker (&rtp, TRUE); gst_rtp_buffer_unmap (&rtp); paybuf = gst_adapter_take_buffer_fast (rtpmpapay->adapter, payload_len); gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpmpapay), outbuf, paybuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); outbuf = gst_buffer_append (outbuf, paybuf); GST_BUFFER_PTS (outbuf) = rtpmpapay->first_ts; GST_BUFFER_DURATION (outbuf) = rtpmpapay->duration; gst_buffer_list_add (list, outbuf); } ret = gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtpmpapay), list); return ret; }
static GstFlowReturn gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer) { GstRtpVRawPay *rtpvrawpay; GstFlowReturn ret = GST_FLOW_OK; gfloat packets_per_packline; guint pgroups_per_packet; guint packlines_per_list, buffers_per_list; guint lines_delay; /* after how many packed lines we push out a buffer list */ guint last_line; /* last pack line number we pushed out a buffer list */ guint line, offset; guint8 *p0, *yp, *up, *vp; guint ystride, uvstride; guint xinc, yinc; guint pgroup; guint mtu; guint width, height; gint field, fields; GstVideoFormat format; GstVideoFrame frame; gint interlaced; gboolean use_buffer_lists; GstBufferList *list = NULL; GstRTPBuffer rtp = { NULL, }; rtpvrawpay = GST_RTP_VRAW_PAY (payload); gst_video_frame_map (&frame, &rtpvrawpay->vinfo, buffer, GST_MAP_READ); GST_LOG_OBJECT (rtpvrawpay, "new frame of %" G_GSIZE_FORMAT " bytes", gst_buffer_get_size (buffer)); /* get pointer and strides of the planes */ p0 = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0); yp = GST_VIDEO_FRAME_COMP_DATA (&frame, 0); up = GST_VIDEO_FRAME_COMP_DATA (&frame, 1); vp = GST_VIDEO_FRAME_COMP_DATA (&frame, 2); ystride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0); uvstride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1); mtu = GST_RTP_BASE_PAYLOAD_MTU (payload); /* amount of bytes for one pixel */ pgroup = rtpvrawpay->pgroup; width = GST_VIDEO_INFO_WIDTH (&rtpvrawpay->vinfo); height = GST_VIDEO_INFO_HEIGHT (&rtpvrawpay->vinfo); interlaced = GST_VIDEO_INFO_IS_INTERLACED (&rtpvrawpay->vinfo); format = GST_VIDEO_INFO_FORMAT (&rtpvrawpay->vinfo); yinc = rtpvrawpay->yinc; xinc = rtpvrawpay->xinc; /* after how many packed lines we push out a buffer list */ lines_delay = GST_ROUND_UP_4 (height / rtpvrawpay->chunks_per_frame); /* calculate how many buffers we expect to store in a single buffer list */ pgroups_per_packet = (mtu - (12 + 14)) / pgroup; packets_per_packline = width / (xinc * pgroups_per_packet * 1.0); packlines_per_list = height / (yinc * rtpvrawpay->chunks_per_frame); buffers_per_list = packlines_per_list * packets_per_packline; buffers_per_list = GST_ROUND_UP_8 (buffers_per_list); use_buffer_lists = (rtpvrawpay->chunks_per_frame < (height / yinc)); fields = 1 + interlaced; /* start with line 0, offset 0 */ for (field = 0; field < fields; field++) { line = field; offset = 0; last_line = 0; if (use_buffer_lists) list = gst_buffer_list_new_sized (buffers_per_list); /* write all lines */ while (line < height) { guint left, pack_line; GstBuffer *out; guint8 *outdata, *headers; gboolean next_line, complete = FALSE; guint length, cont, pixels; /* get the max allowed payload length size, we try to fill the complete MTU */ left = gst_rtp_buffer_calc_payload_len (mtu, 0, 0); out = gst_rtp_buffer_new_allocate (left, 0, 0); if (field == 0) { GST_BUFFER_PTS (out) = GST_BUFFER_PTS (buffer); } else { GST_BUFFER_PTS (out) = GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer) / 2; } gst_rtp_buffer_map (out, GST_MAP_WRITE, &rtp); outdata = gst_rtp_buffer_get_payload (&rtp); GST_LOG_OBJECT (rtpvrawpay, "created buffer of size %u for MTU %u", left, mtu); /* * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Extended Sequence Number | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |F| Line No |C| Offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Length |F| Line No | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |C| Offset | . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ . * . . * . Two (partial) lines of video data . * . . * +---------------------------------------------------------------+ */ /* need 2 bytes for the extended sequence number */ *outdata++ = 0; *outdata++ = 0; left -= 2; /* the headers start here */ headers = outdata; /* make sure we can fit at least *one* header and pixel */ if (!(left > (6 + pgroup))) { gst_rtp_buffer_unmap (&rtp); gst_buffer_unref (out); goto too_small; } /* while we can fit at least one header and one pixel */ while (left > (6 + pgroup)) { /* we need a 6 bytes header */ left -= 6; /* get how may bytes we need for the remaining pixels */ pixels = width - offset; length = (pixels * pgroup) / xinc; if (left >= length) { /* pixels and header fit completely, we will write them and skip to the * next line. */ next_line = TRUE; } else { /* line does not fit completely, see how many pixels fit */ pixels = (left / pgroup) * xinc; length = (pixels * pgroup) / xinc; next_line = FALSE; } GST_LOG_OBJECT (rtpvrawpay, "filling %u bytes in %u pixels", length, pixels); left -= length; /* write length */ *outdata++ = (length >> 8) & 0xff; *outdata++ = length & 0xff; /* write line no */ *outdata++ = ((line >> 8) & 0x7f) | ((field << 7) & 0x80); *outdata++ = line & 0xff; if (next_line) { /* go to next line we do this here to make the check below easier */ line += yinc; } /* calculate continuation marker */ cont = (left > (6 + pgroup) && line < height) ? 0x80 : 0x00; /* write offset and continuation marker */ *outdata++ = ((offset >> 8) & 0x7f) | cont; *outdata++ = offset & 0xff; if (next_line) { /* reset offset */ offset = 0; GST_LOG_OBJECT (rtpvrawpay, "go to next line %u", line); } else { offset += pixels; GST_LOG_OBJECT (rtpvrawpay, "next offset %u", offset); } if (!cont) break; } GST_LOG_OBJECT (rtpvrawpay, "consumed %u bytes", (guint) (outdata - headers)); /* second pass, read headers and write the data */ while (TRUE) { guint offs, lin; /* read length and cont */ length = (headers[0] << 8) | headers[1]; lin = ((headers[2] & 0x7f) << 8) | headers[3]; offs = ((headers[4] & 0x7f) << 8) | headers[5]; cont = headers[4] & 0x80; pixels = length / pgroup; headers += 6; GST_LOG_OBJECT (payload, "writing length %u, line %u, offset %u, cont %d", length, lin, offs, cont); switch (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: case GST_VIDEO_FORMAT_UYVP: offs /= xinc; memcpy (outdata, p0 + (lin * ystride) + (offs * pgroup), length); outdata += length; break; case GST_VIDEO_FORMAT_AYUV: { gint i; guint8 *datap; datap = p0 + (lin * ystride) + (offs * 4); for (i = 0; i < pixels; i++) { *outdata++ = datap[2]; *outdata++ = datap[1]; *outdata++ = datap[3]; datap += 4; } break; } case GST_VIDEO_FORMAT_I420: { gint i; guint uvoff; guint8 *yd1p, *yd2p, *udp, *vdp; yd1p = yp + (lin * ystride) + (offs); yd2p = yd1p + ystride; uvoff = (lin / yinc * uvstride) + (offs / xinc); udp = up + uvoff; vdp = vp + uvoff; for (i = 0; i < pixels; i++) { *outdata++ = *yd1p++; *outdata++ = *yd1p++; *outdata++ = *yd2p++; *outdata++ = *yd2p++; *outdata++ = *udp++; *outdata++ = *vdp++; } break; } case GST_VIDEO_FORMAT_Y41B: { gint i; guint uvoff; guint8 *ydp, *udp, *vdp; ydp = yp + (lin * ystride) + offs; uvoff = (lin / yinc * uvstride) + (offs / xinc); udp = up + uvoff; vdp = vp + uvoff; for (i = 0; i < pixels; i++) { *outdata++ = *udp++; *outdata++ = *ydp++; *outdata++ = *ydp++; *outdata++ = *vdp++; *outdata++ = *ydp++; *outdata++ = *ydp++; } break; } default: gst_rtp_buffer_unmap (&rtp); gst_buffer_unref (out); goto unknown_sampling; } if (!cont) break; } if (line >= height) { GST_LOG_OBJECT (rtpvrawpay, "field/frame complete, set marker"); gst_rtp_buffer_set_marker (&rtp, TRUE); complete = TRUE; } gst_rtp_buffer_unmap (&rtp); if (left > 0) { GST_LOG_OBJECT (rtpvrawpay, "we have %u bytes left", left); gst_buffer_resize (out, 0, gst_buffer_get_size (out) - left); } /* Now either push out the buffer directly */ if (!use_buffer_lists) { ret = gst_rtp_base_payload_push (payload, out); continue; } /* or add the buffer to buffer list ... */ gst_buffer_list_add (list, out); /* .. and check if we need to push out the list */ pack_line = (line - field) / fields; if (complete || (pack_line > last_line && pack_line % lines_delay == 0)) { GST_LOG_OBJECT (rtpvrawpay, "pushing list of %u buffers up to pack " "line %u", gst_buffer_list_length (list), pack_line); ret = gst_rtp_base_payload_push_list (payload, list); list = NULL; if (!complete) list = gst_buffer_list_new_sized (buffers_per_list); last_line = pack_line; } } } gst_video_frame_unmap (&frame); gst_buffer_unref (buffer); return ret; /* ERRORS */ unknown_sampling: { GST_ELEMENT_ERROR (payload, STREAM, FORMAT, (NULL), ("unimplemented sampling")); gst_video_frame_unmap (&frame); gst_buffer_unref (buffer); return GST_FLOW_NOT_SUPPORTED; } too_small: { GST_ELEMENT_ERROR (payload, RESOURCE, NO_SPACE_LEFT, (NULL), ("not enough space to send at least one pixel")); gst_video_frame_unmap (&frame); gst_buffer_unref (buffer); return GST_FLOW_NOT_SUPPORTED; } }