static GstFlowReturn gst_rtp_sbc_pay_flush_buffers (GstRtpSBCPay * sbcpay) { GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; guint available; guint max_payload; GstBuffer *outbuf, *paybuf; 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 (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_rtp_buffer_unmap (&rtp); paybuf = gst_adapter_take_buffer_fast (sbcpay->adapter, payload_length); gst_rtp_copy_meta (GST_ELEMENT_CAST (sbcpay), outbuf, paybuf, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); outbuf = gst_buffer_append (outbuf, paybuf); /* 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_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_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 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; }
/** * gst_rtp_base_audio_payload_flush: * @baseaudiopayload: a #GstRTPBasePayload * @payload_len: length of payload * @timestamp: a #GstClockTime * * Create an RTP buffer and store @payload_len bytes of the adapter as the * payload. Set the timestamp on the new buffer to @timestamp before pushing * the buffer downstream. * * If @payload_len is -1, all pending bytes will be flushed. If @timestamp is * -1, the timestamp will be calculated automatically. * * Returns: a #GstFlowReturn */ GstFlowReturn gst_rtp_base_audio_payload_flush (GstRTPBaseAudioPayload * baseaudiopayload, guint payload_len, GstClockTime timestamp) { GstRTPBasePayload *basepayload; GstRTPBaseAudioPayloadPrivate *priv; GstBuffer *outbuf; GstFlowReturn ret; GstAdapter *adapter; guint64 distance; priv = baseaudiopayload->priv; adapter = priv->adapter; basepayload = GST_RTP_BASE_PAYLOAD (baseaudiopayload); if (payload_len == -1) payload_len = gst_adapter_available (adapter); /* nothing to do, just return */ if (payload_len == 0) return GST_FLOW_OK; if (timestamp == -1) { /* calculate the timestamp */ timestamp = gst_adapter_prev_pts (adapter, &distance); GST_LOG_OBJECT (baseaudiopayload, "last timestamp %" GST_TIME_FORMAT ", distance %" G_GUINT64_FORMAT, GST_TIME_ARGS (timestamp), distance); if (GST_CLOCK_TIME_IS_VALID (timestamp) && distance > 0) { /* convert the number of bytes since the last timestamp to time and add to * the last seen timestamp */ timestamp += priv->bytes_to_time (baseaudiopayload, distance); } } GST_DEBUG_OBJECT (baseaudiopayload, "Pushing %d bytes ts %" GST_TIME_FORMAT, payload_len, GST_TIME_ARGS (timestamp)); if (priv->buffer_list && gst_adapter_available_fast (adapter) >= payload_len) { GstBuffer *buffer; /* we can quickly take a buffer out of the adapter without having to copy * anything. */ buffer = gst_adapter_take_buffer (adapter, payload_len); ret = gst_rtp_base_audio_payload_push_buffer (baseaudiopayload, buffer, timestamp); } else { GstBuffer *paybuf; CopyMetaData data; /* create buffer to hold the payload */ outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, 0, 0, 0); paybuf = gst_adapter_take_buffer_fast (adapter, payload_len); data.pay = baseaudiopayload; data.outbuf = outbuf; gst_buffer_foreach_meta (paybuf, foreach_metadata, &data); outbuf = gst_buffer_append (outbuf, paybuf); /* 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_h263p_pay_flush (GstRtpH263PPay * rtph263ppay) { guint avail; GstBufferList *list = NULL; GstBuffer *outbuf = NULL; GstFlowReturn ret; gboolean fragmented = FALSE; avail = gst_adapter_available (rtph263ppay->adapter); if (avail == 0) return GST_FLOW_OK; fragmented = FALSE; /* This algorithm assumes the H263/+/++ encoder sends complete frames in each * buffer */ /* With Fragmentation Mode at GST_FRAGMENTATION_MODE_NORMAL: * This algorithm implements the Follow-on packets method for packetization. * This assumes low packet loss network. * With Fragmentation Mode at GST_FRAGMENTATION_MODE_SYNC: * This algorithm separates large frames at synchronisation points (Segments) * (See RFC 4629 section 6). It would be interesting to have a property such as network * quality to select between both packetization methods */ /* TODO Add VRC supprt (See RFC 4629 section 5.2) */ while (avail > 0) { guint towrite; guint8 *payload; gint header_len; guint next_gop = 0; gboolean found_gob = FALSE; GstRTPBuffer rtp = { NULL }; GstBuffer *payload_buf; if (rtph263ppay->fragmentation_mode == GST_FRAGMENTATION_MODE_SYNC) { /* start after 1st gop possible */ /* Check if we have a gob or eos , eossbs */ /* FIXME EOS and EOSSBS packets should never contain any gobs and vice-versa */ next_gop = gst_adapter_masked_scan_uint32 (rtph263ppay->adapter, 0xffff8000, 0x00008000, 0, avail); if (next_gop == 0) { GST_DEBUG_OBJECT (rtph263ppay, " Found GOB header"); found_gob = TRUE; } /* Find next and cut the packet accordingly */ /* TODO we should get as many gobs as possible until MTU is reached, this * code seems to just get one GOB per packet */ if (next_gop == 0 && avail > 3) next_gop = gst_adapter_masked_scan_uint32 (rtph263ppay->adapter, 0xffff8000, 0x00008000, 3, avail - 3); GST_DEBUG_OBJECT (rtph263ppay, " Next GOB Detected at : %d", next_gop); if (next_gop == -1) next_gop = 0; } /* for picture start frames (non-fragmented), we need to remove the first * two 0x00 bytes and set P=1 */ if (!fragmented || found_gob) { gst_adapter_flush (rtph263ppay->adapter, 2); avail -= 2; } header_len = 2; towrite = MIN (avail, gst_rtp_buffer_calc_payload_len (GST_RTP_BASE_PAYLOAD_MTU (rtph263ppay) - header_len, 0, 0)); if (next_gop > 0) towrite = MIN (next_gop, towrite); outbuf = gst_rtp_buffer_new_allocate (header_len, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); /* last fragment gets the marker bit set */ gst_rtp_buffer_set_marker (&rtp, avail > towrite ? 0 : 1); payload = gst_rtp_buffer_get_payload (&rtp); /* 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | RR |P|V| PLEN |PEBIT| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ /* if fragmented or gop header , write p bit =1 */ payload[0] = (fragmented && !found_gob) ? 0x00 : 0x04; payload[1] = 0; GST_BUFFER_PTS (outbuf) = rtph263ppay->first_timestamp; GST_BUFFER_DURATION (outbuf) = rtph263ppay->first_duration; gst_rtp_buffer_unmap (&rtp); payload_buf = gst_adapter_take_buffer_fast (rtph263ppay->adapter, towrite); gst_rtp_copy_meta (GST_ELEMENT_CAST (rtph263ppay), outbuf, payload_buf, g_quark_from_static_string (GST_META_TAG_VIDEO_STR)); outbuf = gst_buffer_append (outbuf, payload_buf); avail -= towrite; /* If more data is available and this is our first iteration, * we create a buffer list and remember that we're fragmented. * * If we're fragmented already, add buffers to the previously * created buffer list. * * Otherwise fragmented will be FALSE and we just push the single output * buffer, and no list is allocated. */ if (avail && !fragmented) { fragmented = TRUE; list = gst_buffer_list_new (); gst_buffer_list_add (list, outbuf); } else if (fragmented) { gst_buffer_list_add (list, outbuf); } } if (fragmented) { ret = gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtph263ppay), list); } else { ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtph263ppay), outbuf); } return ret; }
static GstFlowReturn gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay) { guint avail, total; GstBuffer *outbuf; GstFlowReturn ret; guint mtu; /* 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 fragment the MPEG data * over multiple packets. */ total = avail = gst_adapter_available (rtpmp4gpay->adapter); ret = GST_FLOW_OK; mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp4gpay); while (avail > 0) { guint towrite; guint8 *payload; guint payload_len; guint packet_len; GstRTPBuffer rtp = { NULL }; GstBuffer *paybuf; /* 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, we need 4 spare bytes for * the AU header. */ towrite = MIN (packet_len, mtu - 4); /* this is the payload length */ payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0); GST_DEBUG_OBJECT (rtpmp4gpay, "avail %d, towrite %d, packet_len %d, payload_len %d", avail, towrite, packet_len, payload_len); /* create buffer to hold the payload, also make room for the 4 header bytes. */ outbuf = gst_rtp_buffer_new_allocate (4, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); /* copy payload */ payload = gst_rtp_buffer_get_payload (&rtp); /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+ * |AU-headers-length|AU-header|AU-header| |AU-header|padding| * | | (1) | (2) | | (n) | bits | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+ */ /* AU-headers-length, we only have 1 AU-header */ payload[0] = 0x00; payload[1] = 0x10; /* we use 16 bits for the header */ /* +---------------------------------------+ * | AU-size | * +---------------------------------------+ * | AU-Index / AU-Index-delta | * +---------------------------------------+ * | CTS-flag | * +---------------------------------------+ * | CTS-delta | * +---------------------------------------+ * | DTS-flag | * +---------------------------------------+ * | DTS-delta | * +---------------------------------------+ * | RAP-flag | * +---------------------------------------+ * | Stream-state | * +---------------------------------------+ */ /* The AU-header, no CTS, DTS, RAP, Stream-state * * AU-size is always the total size of the AU, not the fragmented size */ payload[2] = (total & 0x1fe0) >> 5; payload[3] = (total & 0x1f) << 3; /* we use 13 bits for the size, 3 bits index */ /* marker only if the packet is complete */ gst_rtp_buffer_set_marker (&rtp, avail <= payload_len); gst_rtp_buffer_unmap (&rtp); paybuf = gst_adapter_take_buffer_fast (rtpmp4gpay->adapter, payload_len); outbuf = gst_buffer_append (outbuf, paybuf); GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4gpay->first_timestamp; GST_BUFFER_DURATION (outbuf) = rtpmp4gpay->first_duration; if (rtpmp4gpay->frame_len) { GST_BUFFER_OFFSET (outbuf) = rtpmp4gpay->offset; rtpmp4gpay->offset += rtpmp4gpay->frame_len; } if (rtpmp4gpay->discont) { GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); /* Only the first outputted buffer has the DISCONT flag */ rtpmp4gpay->discont = FALSE; } ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmp4gpay), outbuf); avail -= payload_len; } return ret; }
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; GstRTPBuffer rtp = { NULL }; GstBuffer *paybuf; packet_len = gst_rtp_buffer_calc_packet_len (avail, 4, 0); towrite = MIN (packet_len, GST_RTP_BASE_PAYLOAD_MTU (rtpmpvpay)); payload_len = gst_rtp_buffer_calc_payload_len (towrite, 4, 0); outbuf = gst_rtp_buffer_new_allocate (4, 0, 0); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); payload = gst_rtp_buffer_get_payload (&rtp); /* 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); avail -= payload_len; gst_rtp_buffer_set_marker (&rtp, avail == 0); gst_rtp_buffer_unmap (&rtp); paybuf = gst_adapter_take_buffer_fast (rtpmpvpay->adapter, payload_len); outbuf = gst_buffer_append (outbuf, paybuf); GST_BUFFER_TIMESTAMP (outbuf) = rtpmpvpay->first_ts; ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmpvpay), outbuf); } return ret; }
static GstFlowReturn gst_rtp_mpv_pay_flush (GstRTPMPVPay * rtpmpvpay) { GstFlowReturn ret; guint avail; GstBufferList *list; GstBuffer *outbuf; guint8 *payload; avail = gst_adapter_available (rtpmpvpay->adapter); ret = GST_FLOW_OK; list = gst_buffer_list_new_sized (avail / (GST_RTP_BASE_PAYLOAD_MTU (rtpmpvpay) - RTP_HEADER_LEN) + 1); while (avail > 0) { guint towrite; guint packet_len; guint payload_len; GstRTPBuffer rtp = { NULL }; GstBuffer *paybuf; packet_len = gst_rtp_buffer_calc_packet_len (avail + 4, 0, 0); towrite = MIN (packet_len, GST_RTP_BASE_PAYLOAD_MTU (rtpmpvpay)); payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0); outbuf = gst_rtp_buffer_new_allocate (4, 0, 0); payload_len -= 4; gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); payload = gst_rtp_buffer_get_payload (&rtp); /* 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); avail -= payload_len; gst_rtp_buffer_set_marker (&rtp, avail == 0); gst_rtp_buffer_unmap (&rtp); paybuf = gst_adapter_take_buffer_fast (rtpmpvpay->adapter, payload_len); gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpmpvpay), outbuf, paybuf, g_quark_from_static_string (GST_META_TAG_VIDEO_STR)); outbuf = gst_buffer_append (outbuf, paybuf); GST_BUFFER_PTS (outbuf) = rtpmpvpay->first_ts; gst_buffer_list_add (list, outbuf); } ret = gst_rtp_base_payload_push_list (GST_RTP_BASE_PAYLOAD (rtpmpvpay), list); return ret; }
static GstFlowReturn gst_rtp_ac3_pay_flush (GstRtpAC3Pay * rtpac3pay) { guint avail, FT, NF, mtu; 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 AC3 data * over multiple packets. */ avail = gst_adapter_available (rtpac3pay->adapter); ret = GST_FLOW_OK; FT = 0; /* number of frames */ NF = rtpac3pay->NF; mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpac3pay); GST_LOG_OBJECT (rtpac3pay, "flushing %u bytes", avail); while (avail > 0) { guint towrite; guint8 *payload; guint payload_len; guint packet_len; GstRTPBuffer rtp = { NULL, }; GstBuffer *payload_buffer; /* this will be the total length of the packet */ packet_len = gst_rtp_buffer_calc_packet_len (2 + 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); /* create buffer to hold the payload */ outbuf = gst_rtp_buffer_new_allocate (2, 0, 0); if (FT == 0) { /* check if it all fits */ if (towrite < packet_len) { guint maxlen; GST_LOG_OBJECT (rtpac3pay, "we need to fragment"); /* check if we will be able to put at least 5/8th of the total * frame in this first frame. */ if ((avail * 5) / 8 >= (payload_len - 2)) FT = 1; else FT = 2; /* check how many fragments we will need */ maxlen = gst_rtp_buffer_calc_payload_len (mtu - 2, 0, 0); NF = (avail + maxlen - 1) / maxlen; } } else if (FT != 3) { /* remaining fragment */ FT = 3; } /* * 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MBZ | FT| NF | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * FT: 0: one or more complete frames * 1: initial 5/8 fragment * 2: initial fragment not 5/8 * 3: other fragment * NF: amount of frames if FT = 0, else number of fragments. */ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); GST_LOG_OBJECT (rtpac3pay, "FT %u, NF %u", FT, NF); payload = gst_rtp_buffer_get_payload (&rtp); payload[0] = (FT & 3); payload[1] = NF; payload_len -= 2; if (avail == payload_len) gst_rtp_buffer_set_marker (&rtp, TRUE); gst_rtp_buffer_unmap (&rtp); payload_buffer = gst_adapter_take_buffer_fast (rtpac3pay->adapter, payload_len); gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpac3pay), outbuf, payload_buffer, g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); outbuf = gst_buffer_append (outbuf, payload_buffer); avail -= payload_len; GST_BUFFER_PTS (outbuf) = rtpac3pay->first_ts; GST_BUFFER_DURATION (outbuf) = rtpac3pay->duration; ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpac3pay), outbuf); } return ret; }