/** * gst_rtp_buffer_get_payload_subbuffer: * @buffer: the buffer * @offset: the offset in the payload * @len: the length in the payload * * Create a subbuffer of the payload of the RTP packet in @buffer. @offset bytes * are skipped in the payload and the subbuffer will be of size @len. * If @len is -1 the total payload starting from @offset if subbuffered. * * Returns: A new buffer with the specified data of the payload. * * Since: 0.10.10 */ GstBuffer * gst_rtp_buffer_get_payload_subbuffer (GstBuffer * buffer, guint offset, guint len) { guint poffset, plen; plen = gst_rtp_buffer_get_payload_len (buffer); /* we can't go past the length */ if (G_UNLIKELY (offset >= plen)) goto wrong_offset; /* apply offset */ poffset = gst_rtp_buffer_get_header_len (buffer) + offset; plen -= offset; /* see if we need to shrink the buffer based on @len */ if (len != -1 && len < plen) plen = len; return gst_buffer_create_sub (buffer, poffset, plen); /* ERRORS */ wrong_offset: { g_warning ("offset=%u should be less then plen=%u", offset, plen); return NULL; } }
EXPORT_C #endif GstBuffer * gst_rtp_buffer_get_payload_subbuffer (GstBuffer * buffer, guint offset, guint len) { guint poffset, plen; g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL); g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, NULL); plen = gst_rtp_buffer_get_payload_len (buffer); /* we can't go past the length */ if (G_UNLIKELY (offset >= plen)) { GST_WARNING ("offset=%u should be less then plen=%u", offset, plen); return (NULL); } /* apply offset */ poffset = gst_rtp_buffer_get_header_len (buffer) + offset; plen -= offset; /* see if we need to shrink the buffer based on @len */ if (len != -1 && len < plen) plen = len; return gst_buffer_create_sub (buffer, poffset, plen); }
EXPORT_C #endif gpointer gst_rtp_buffer_get_payload (GstBuffer * buffer) { return GST_BUFFER_DATA (buffer) + gst_rtp_buffer_get_header_len (buffer); }
EXPORT_C #endif gpointer gst_rtp_buffer_get_payload (GstBuffer * buffer) { g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL); g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, NULL); return GST_BUFFER_DATA (buffer) + gst_rtp_buffer_get_header_len (buffer); }
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); }
/** * gst_rtp_buffer_get_payload_len: * @buffer: the buffer * * Get the length of the payload of the RTP packet in @buffer. * * Returns: The length of the payload in @buffer. */ guint gst_rtp_buffer_get_payload_len (GstBuffer * buffer) { guint len, size; guint8 *data; size = GST_BUFFER_SIZE (buffer); data = GST_BUFFER_DATA (buffer); len = size - gst_rtp_buffer_get_header_len (buffer); if (GST_RTP_HEADER_PADDING (data)) len -= data[size - 1]; return len; }
EXPORT_C #endif guint gst_rtp_buffer_get_payload_len (GstBuffer * buffer) { guint len, size; g_return_val_if_fail (GST_IS_BUFFER (buffer), 0); g_return_val_if_fail (GST_BUFFER_DATA (buffer) != NULL, 0); size = GST_BUFFER_SIZE (buffer); len = size - gst_rtp_buffer_get_header_len (buffer); if (GST_RTP_HEADER_PADDING (buffer)) len -= GST_BUFFER_DATA (buffer)[size - 1]; return len; }
void fec_dec_push_fec_packet(fec_dec *dec, GstBuffer *packet) { guint8 *fec_data; guint32 snbase; guint16 seqnum; GList *link; fec_data = GST_BUFFER_DATA(packet) + gst_rtp_buffer_get_header_len(packet); snbase = (((guint16)(fec_data[0])) << 8) | (((guint16)(fec_data[1])) << 0); seqnum = gst_rtp_buffer_get_seq(packet); GST_DEBUG("Received FEC packet, snbase %u, index %u, seqnum %u", snbase, (guint)(fec_data[12]), seqnum); if (snbase == dec->blacklisted_snbase) { GST_DEBUG("Ignoring FEC packet since data from this snbase has been restored already (= the packet is not needed)"); return; } if (g_hash_table_lookup_extended(dec->fec_packet_set, GINT_TO_POINTER(seqnum), NULL, NULL)) { GST_DEBUG("FEC packet with seqnum %u is already in queue - discarding duplicate", seqnum); return; } if (dec->cur_snbase != snbase) { GST_DEBUG("snbase changed from %u to %u - purging FEC queue (%u FEC packets and %u media packets present)", dec->cur_snbase, snbase, dec->num_received_fec_packets, dec->num_received_media_packets); g_queue_foreach(dec->fec_packets, fec_dec_clear_packet, NULL); g_queue_clear(dec->fec_packets); g_hash_table_remove_all(dec->fec_packet_set); dec->num_received_fec_packets = 0; } dec->cur_snbase = snbase; dec->has_snbase = TRUE; dec->received_media_packet_mask = 0; dec->num_received_media_packets = 0; dec->max_packet_size = 0; g_queue_push_tail(dec->fec_packets, gst_buffer_ref(packet)); g_hash_table_add(dec->fec_packet_set, GINT_TO_POINTER(seqnum)); ++dec->num_received_fec_packets; for (link = g_queue_peek_head_link(dec->media_packets); link != NULL;) { GstBuffer *media_packet; guint32 corrected_seqnum; media_packet = link->data; seqnum = gst_rtp_buffer_get_seq(media_packet); corrected_seqnum = fec_dec_correct_seqnum(dec, seqnum); if ((corrected_seqnum < snbase) || (corrected_seqnum > (snbase + dec->num_media_packets - 1))) { GList *old_link; GST_DEBUG("Found media packet with seqnum %u outside bounds [%u, %u] - purging", seqnum, snbase, snbase + dec->num_media_packets - 1); g_hash_table_remove(dec->media_packet_set, GINT_TO_POINTER(seqnum)); gst_buffer_unref(media_packet); old_link = link; link = link->next; g_queue_delete_link(dec->media_packets, old_link); } else { dec->max_packet_size = MAX(dec->max_packet_size, GST_BUFFER_SIZE(media_packet)); dec->received_media_packet_mask |= (1ul << (corrected_seqnum - dec->cur_snbase)); ++dec->num_received_media_packets; link = link->next; } } fec_dec_check_state(dec); }
static void fec_dec_recover_packets(fec_dec *dec) { of_session_t *session; of_rs_parameters_t params; void **encoding_symbol_tab; guint i; GList *link; assert(dec->has_snbase); assert(dec->max_packet_size > 0); encoding_symbol_tab = malloc(sizeof(void*) * (dec->num_media_packets + dec->num_fec_packets)); memset(encoding_symbol_tab, 0, sizeof(void*) * (dec->num_media_packets + dec->num_fec_packets)); for (link = g_queue_peek_head_link(dec->media_packets); link != NULL; link = link->next) { GstBuffer *media_packet; guint32 seqnum; media_packet = link->data; seqnum = fec_dec_correct_seqnum(dec, gst_rtp_buffer_get_seq(media_packet)); encoding_symbol_tab[seqnum - dec->cur_snbase] = GST_BUFFER_DATA(media_packet); } for (link = g_queue_peek_head_link(dec->fec_packets); link != NULL; link = link->next) { GstBuffer *packet; guint8 *fec_data; guint8 esi; packet = link->data; fec_data = GST_BUFFER_DATA(packet) + gst_rtp_buffer_get_header_len(packet); esi = fec_data[12]; encoding_symbol_tab[esi + dec->num_media_packets] = fec_data + RTP_FEC_HEADER_SIZE + 1; } params.nb_source_symbols = dec->num_media_packets; params.nb_repair_symbols = dec->num_fec_packets; params.encoding_symbol_length = dec->max_packet_size; of_create_codec_instance(&session, OF_CODEC_REED_SOLOMON_GF_2_8_STABLE, OF_DECODER, 0); of_set_fec_parameters(session, (of_parameters_t*)(¶ms)); of_set_callback_functions(session, fec_dec_source_packet_cb, NULL, dec); #if 1 for (i = 0; i < dec->num_media_packets + dec->num_fec_packets; ++i) { if (encoding_symbol_tab[i] != 0) of_decode_with_new_symbol(session, encoding_symbol_tab[i], i); } #else of_set_available_symbols(session, encoding_symbol_tab); #endif if (!of_is_decoding_complete(session)) { of_finish_decoding(session); } free(encoding_symbol_tab); of_release_codec_instance(session); }
/* 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; }
static GstFlowReturn gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer) { GstBaseRTPPayload *rtppay; GstAsfPacketInfo *packetinfo; guint8 flags; guint8 *data; guint32 packet_util_size; guint32 packet_offset; guint32 size_left; GstFlowReturn ret = GST_FLOW_OK; rtppay = GST_BASE_RTP_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_WRITE_UINT32_LE (&(GST_BUFFER_DATA (buffer)[offset]), 0); break; case ASF_FIELD_TYPE_WORD: GST_WRITE_UINT16_LE (&(GST_BUFFER_DATA (buffer)[offset]), 0); break; case ASF_FIELD_TYPE_BYTE: GST_BUFFER_DATA (buffer)[offset] = 0; 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; /* 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_BASE_RTP_PAYLOAD_MTU (rtpasfpay), 0, 0); rtpasfpay->cur_off = gst_rtp_buffer_get_header_len (rtpasfpay->current); rtpasfpay->has_ts = FALSE; rtpasfpay->marker = FALSE; } data = GST_BUFFER_DATA (rtpasfpay->current) + rtpasfpay->cur_off; size_left = GST_BUFFER_SIZE (rtpasfpay->current) - rtpasfpay->cur_off; GST_DEBUG_OBJECT (rtpasfpay, "Input buffer bytes consumed: %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, packet_offset, GST_BUFFER_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 (GST_BUFFER_SIZE (rtpasfpay->current) - rtpasfpay->cur_off >= 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); memcpy (data + 8, GST_BUFFER_DATA (buffer) + packet_offset, 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); memcpy (data + 8, GST_BUFFER_DATA (buffer) + packet_offset, 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) { if (size_left != 0) { /* trim remaining bytes not used */ GstBuffer *aux = gst_buffer_create_sub (rtpasfpay->current, 0, GST_BUFFER_SIZE (rtpasfpay->current) - size_left); gst_buffer_unref (rtpasfpay->current); rtpasfpay->current = aux; } gst_rtp_buffer_set_ssrc (rtpasfpay->current, rtppay->current_ssrc); gst_rtp_buffer_set_marker (rtpasfpay->current, rtpasfpay->marker); gst_rtp_buffer_set_payload_type (rtpasfpay->current, GST_BASE_RTP_PAYLOAD_PT (rtppay)); gst_rtp_buffer_set_seq (rtpasfpay->current, rtppay->seqnum + 1); gst_rtp_buffer_set_timestamp (rtpasfpay->current, packetinfo->send_time); GST_BUFFER_TIMESTAMP (rtpasfpay->current) = GST_BUFFER_TIMESTAMP (buffer); gst_buffer_set_caps (rtpasfpay->current, GST_PAD_CAPS (GST_BASE_RTP_PAYLOAD_SRCPAD (rtppay))); rtppay->seqnum++; rtppay->timestamp = packetinfo->send_time; GST_DEBUG_OBJECT (rtpasfpay, "Pushing rtp buffer"); ret = gst_pad_push (GST_BASE_RTP_PAYLOAD_SRCPAD (rtppay), rtpasfpay->current); rtpasfpay->current = NULL; if (ret != GST_FLOW_OK) { gst_buffer_unref (buffer); return ret; } } } gst_buffer_unref (buffer); return ret; }