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; } }
/* Get a DV frame, chop it up in pieces, and push the pieces to the RTP layer. */ static GstFlowReturn gst_rtp_dv_pay_handle_buffer (GstRTPBasePayload * basepayload, GstBuffer * buffer) { GstRTPDVPay *rtpdvpay; guint max_payload_size; GstBuffer *outbuf; GstFlowReturn ret = GST_FLOW_OK; gint hdrlen; gsize size; GstMapInfo map; guint8 *data; guint8 *dest; guint filled; GstRTPBuffer rtp = { NULL, }; rtpdvpay = GST_RTP_DV_PAY (basepayload); hdrlen = gst_rtp_buffer_calc_header_len (0); /* DV frames are made up from a bunch of DIF blocks. DIF blocks are 80 bytes * each, and we should put an integral number of them in each RTP packet. * Therefore, we round the available room down to the nearest multiple of 80. * * The available room is just the packet MTU, minus the RTP header length. */ max_payload_size = ((GST_RTP_BASE_PAYLOAD_MTU (rtpdvpay) - hdrlen) / 80) * 80; /* The length of the buffer to transmit. */ if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) { GST_ELEMENT_ERROR (rtpdvpay, CORE, FAILED, (NULL), ("Failed to map buffer")); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } data = map.data; size = map.size; GST_DEBUG_OBJECT (rtpdvpay, "DV RTP payloader got buffer of %" G_GSIZE_FORMAT " bytes, splitting in %u byte " "payload fragments, at time %" GST_TIME_FORMAT, size, max_payload_size, GST_TIME_ARGS (GST_BUFFER_PTS (buffer))); if (!rtpdvpay->negotiated) { gst_dv_pay_negotiate (rtpdvpay, data, size); /* if we have not yet scanned the stream for its type, do so now */ rtpdvpay->negotiated = TRUE; } outbuf = NULL; dest = NULL; filled = 0; /* while we have a complete DIF chunks left */ while (size >= 80) { /* Allocate a new buffer, set the timestamp */ if (outbuf == NULL) { outbuf = gst_rtp_buffer_new_allocate (max_payload_size, 0, 0); GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buffer); if (!gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp)) { gst_buffer_unref (outbuf); GST_ELEMENT_ERROR (rtpdvpay, CORE, FAILED, (NULL), ("Failed to map RTP buffer")); ret = GST_FLOW_ERROR; goto beach; } dest = gst_rtp_buffer_get_payload (&rtp); filled = 0; } /* inspect the DIF chunk, if we don't need to include it, skip to the next one. */ if (include_dif (rtpdvpay, data)) { /* copy data in packet */ memcpy (dest, data, 80); dest += 80; filled += 80; } /* go to next dif chunk */ size -= 80; data += 80; /* push out the buffer if the next one would exceed the max packet size or * when we are pushing the last packet */ if (filled + 80 > max_payload_size || size < 80) { if (size < 160) { guint hlen; /* set marker */ gst_rtp_buffer_set_marker (&rtp, TRUE); /* shrink buffer to last packet */ hlen = gst_rtp_buffer_get_header_len (&rtp); gst_rtp_buffer_set_packet_len (&rtp, hlen + filled); } /* Push out the created piece, and check for errors. */ gst_rtp_buffer_unmap (&rtp); ret = gst_rtp_base_payload_push (basepayload, outbuf); if (ret != GST_FLOW_OK) break; outbuf = NULL; } } beach: gst_buffer_unmap (buffer, &map); gst_buffer_unref (buffer); return ret; }