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 void flush_packets (GstRtpQCELPDepay * depay) { guint i, size; GST_DEBUG_OBJECT (depay, "flushing packets"); size = depay->packets->len; for (i = 0; i < size; i++) { GstBuffer *outbuf; outbuf = g_ptr_array_index (depay->packets, i); g_ptr_array_index (depay->packets, i) = NULL; gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (depay), outbuf); } /* and reset interleaving state */ depay->interleaved = FALSE; depay->bundling = 0; }
static GstFlowReturn gst_rtp_j2k_depay_flush_frame (GstBaseRTPDepayload * depayload) { GstRtpJ2KDepay *rtpj2kdepay; guint8 end[2]; guint8 *data; guint avail; GstFlowReturn ret = GST_FLOW_OK; rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload); /* flush pending tile */ gst_rtp_j2k_depay_flush_tile (depayload); /* last buffer take all data out of the adapter */ avail = gst_adapter_available (rtpj2kdepay->f_adapter); if (avail == 0) goto done; if (avail > 2) { GstBuffer *outbuf; /* take the last bytes of the JPEG 2000 data to see if there is an EOC * marker */ gst_adapter_copy (rtpj2kdepay->f_adapter, end, avail - 2, 2); if (end[0] != 0xff && end[1] != 0xd9) { GST_DEBUG_OBJECT (rtpj2kdepay, "no EOC marker, adding one"); /* no EOI marker, add one */ outbuf = gst_buffer_new_and_alloc (2); data = GST_BUFFER_DATA (outbuf); data[0] = 0xff; data[1] = 0xd9; gst_adapter_push (rtpj2kdepay->f_adapter, outbuf); avail += 2; } if (rtpj2kdepay->buffer_list) { GList *list; GstBufferList *buflist; GstBufferListIterator *it; GST_DEBUG_OBJECT (rtpj2kdepay, "pushing buffer list of %u bytes", avail); list = gst_adapter_take_list (rtpj2kdepay->f_adapter, avail); buflist = gst_buffer_list_new (); it = gst_buffer_list_iterate (buflist); gst_buffer_list_iterator_add_group (it); gst_buffer_list_iterator_add_list (it, list); gst_buffer_list_iterator_free (it); ret = gst_base_rtp_depayload_push_list (depayload, buflist); } else { GST_DEBUG_OBJECT (rtpj2kdepay, "pushing buffer of %u bytes", avail); outbuf = gst_adapter_take_buffer (rtpj2kdepay->f_adapter, avail); ret = gst_base_rtp_depayload_push (depayload, outbuf); } } else { GST_WARNING_OBJECT (rtpj2kdepay, "empty packet"); gst_adapter_clear (rtpj2kdepay->f_adapter); } /* we accept any mh_id now */ rtpj2kdepay->last_mh_id = -1; /* reset state */ rtpj2kdepay->next_frag = 0; rtpj2kdepay->have_sync = FALSE; done: /* we can't keep headers with mh_id of 0 */ store_mheader (rtpj2kdepay, 0, NULL); return ret; }
static GstBuffer * gst_rtp_qcelp_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpQCELPDepay *depay; GstBuffer *outbuf; GstClockTime timestamp; guint payload_len, offset, index; guint8 *payload; guint RR, LLL, NNN; depay = GST_RTP_QCELP_DEPAY (depayload); payload_len = gst_rtp_buffer_get_payload_len (buf); if (payload_len < 2) goto too_small; timestamp = GST_BUFFER_TIMESTAMP (buf); payload = gst_rtp_buffer_get_payload (buf); /* 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * |RR | LLL | NNN | * +-+-+-+-+-+-+-+-+ */ RR = payload[0] >> 6; LLL = (payload[0] & 0x38) >> 3; NNN = (payload[0] & 0x07); payload_len--; payload++; GST_DEBUG_OBJECT (depay, "LLL %u, NNN %u", LLL, NNN); if (LLL > 5) goto invalid_lll; if (NNN > LLL) goto invalid_nnn; if (LLL != 0) { /* we are interleaved */ if (!depay->interleaved) { guint size; GST_DEBUG_OBJECT (depay, "starting interleaving group"); /* bundling is not allowed to change in one interleave group */ depay->bundling = count_packets (depay, payload, payload_len); GST_DEBUG_OBJECT (depay, "got bundling of %u", depay->bundling); /* we have one bundle where NNN goes from 0 to L, we don't store the index * 0 frames, so L+1 packets. Each packet has 'bundling - 1' packets */ size = (depay->bundling - 1) * (LLL + 1); /* create the array to hold the packets */ if (depay->packets == NULL) depay->packets = g_ptr_array_sized_new (size); GST_DEBUG_OBJECT (depay, "created packet array of size %u", size); g_ptr_array_set_size (depay->packets, size); /* we were previously not interleaved, figure out how much space we * need to deinterleave */ depay->interleaved = TRUE; } } else { /* we are not interleaved */ if (depay->interleaved) { GST_DEBUG_OBJECT (depay, "stopping interleaving"); /* flush packets if we were previously interleaved */ flush_packets (depay); } depay->bundling = 0; } index = 0; offset = 1; while (payload_len > 0) { gint frame_len; gboolean do_erasure; frame_len = get_frame_len (depay, payload[0]); GST_DEBUG_OBJECT (depay, "got frame len %d", frame_len); if (frame_len == 0) goto invalid_frame; if (frame_len < 0) { /* need to add an erasure frame but we can recover */ frame_len = -frame_len; do_erasure = TRUE; } else { do_erasure = FALSE; } if (frame_len > payload_len) goto invalid_frame; if (do_erasure) { /* create erasure frame */ outbuf = create_erasure_buffer (depay); } else { /* each frame goes into its buffer */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, offset, frame_len); } GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = FRAME_DURATION; if (!depay->interleaved || index == 0) { /* not interleaved or first frame in packet, just push */ gst_base_rtp_depayload_push (depayload, outbuf); if (timestamp != -1) timestamp += FRAME_DURATION; } else { /* put in interleave buffer */ add_packet (depay, LLL, NNN, index, outbuf); if (timestamp != -1) timestamp += (FRAME_DURATION * (LLL + 1)); } payload_len -= frame_len; payload += frame_len; offset += frame_len; index++; /* discard excess packets */ if (depay->bundling > 0 && depay->bundling <= index) break; } while (index < depay->bundling) { GST_DEBUG_OBJECT (depay, "filling with erasure buffer"); /* fill remainder with erasure packets */ outbuf = create_erasure_buffer (depay); add_packet (depay, LLL, NNN, index, outbuf); index++; } if (depay->interleaved && LLL == NNN) { GST_DEBUG_OBJECT (depay, "interleave group ended, flushing"); /* we have the complete interleave group, flush */ flush_packets (depay); } return NULL; /* ERRORS */ too_small: { GST_ELEMENT_WARNING (depay, STREAM, DECODE, (NULL), ("QCELP RTP payload too small (%d)", payload_len)); return NULL; } invalid_lll: { GST_ELEMENT_WARNING (depay, STREAM, DECODE, (NULL), ("QCELP RTP invalid LLL received (%d)", LLL)); return NULL; } invalid_nnn: { GST_ELEMENT_WARNING (depay, STREAM, DECODE, (NULL), ("QCELP RTP invalid NNN received (%d)", NNN)); return NULL; } invalid_frame: { GST_ELEMENT_WARNING (depay, STREAM, DECODE, (NULL), ("QCELP RTP invalid frame received")); return NULL; } }
static gboolean gst_rtp_celt_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) { GstStructure *structure; GstRtpCELTDepay *rtpceltdepay; gint clock_rate, nb_channels, frame_size; GstBuffer *buf; guint8 *data; const gchar *params; GstCaps *srccaps; gboolean res; rtpceltdepay = GST_RTP_CELT_DEPAY (depayload); structure = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (structure, "clock-rate", &clock_rate)) goto no_clockrate; depayload->clock_rate = clock_rate; if (!(params = gst_structure_get_string (structure, "encoding-params"))) nb_channels = 1; else { nb_channels = atoi (params); } if (!(params = gst_structure_get_string (structure, "frame-size"))) frame_size = 480; else { frame_size = atoi (params); } /* construct minimal header and comment packet for the decoder */ buf = gst_buffer_new_and_alloc (60); data = GST_BUFFER_DATA (buf); memcpy (data, "CELT ", 8); data += 8; memcpy (data, "1.1.12", 7); data += 20; GST_WRITE_UINT32_LE (data, 0x80000006); /* version */ data += 4; GST_WRITE_UINT32_LE (data, 56); /* header_size */ data += 4; GST_WRITE_UINT32_LE (data, clock_rate); /* rate */ data += 4; GST_WRITE_UINT32_LE (data, nb_channels); /* channels */ data += 4; GST_WRITE_UINT32_LE (data, frame_size); /* frame-size */ data += 4; GST_WRITE_UINT32_LE (data, -1); /* overlap */ data += 4; GST_WRITE_UINT32_LE (data, -1); /* bytes_per_packet */ data += 4; GST_WRITE_UINT32_LE (data, 0); /* extra headers */ srccaps = gst_caps_new_simple ("audio/x-celt", NULL); res = gst_pad_set_caps (depayload->srcpad, srccaps); gst_caps_unref (srccaps); gst_buffer_set_caps (buf, GST_PAD_CAPS (depayload->srcpad)); gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (rtpceltdepay), buf); buf = gst_buffer_new_and_alloc (sizeof (gst_rtp_celt_comment)); memcpy (GST_BUFFER_DATA (buf), gst_rtp_celt_comment, sizeof (gst_rtp_celt_comment)); gst_buffer_set_caps (buf, GST_PAD_CAPS (depayload->srcpad)); gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (rtpceltdepay), buf); return res; /* ERRORS */ no_clockrate: { GST_DEBUG_OBJECT (depayload, "no clock-rate specified"); return FALSE; } }