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 int gst_ffmpeg_pipe_read (URLContext * h, unsigned char *buf, int size) { GstFFMpegPipe *ffpipe; guint available; ffpipe = (GstFFMpegPipe *) h->priv_data; GST_LOG ("requested size %d", size); GST_FFMPEG_PIPE_MUTEX_LOCK (ffpipe); GST_LOG ("requested size %d", size); while ((available = gst_adapter_available (ffpipe->adapter)) < size && !ffpipe->eos) { GST_DEBUG ("Available:%d, requested:%d", available, size); ffpipe->needed = size; GST_FFMPEG_PIPE_SIGNAL (ffpipe); GST_FFMPEG_PIPE_WAIT (ffpipe); } size = MIN (available, size); if (size) { GST_LOG ("Getting %d bytes", size); gst_adapter_copy (ffpipe->adapter, buf, 0, size); gst_adapter_flush (ffpipe->adapter, size); GST_LOG ("%d bytes left in adapter", gst_adapter_available (ffpipe->adapter)); ffpipe->needed = 0; } GST_FFMPEG_PIPE_MUTEX_UNLOCK (ffpipe); return size; }
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_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; }
/** * gst_adapter_copy_bytes: (rename-to gst_adapter_copy) * @adapter: a #GstAdapter * @offset: the bytes offset in the adapter to start from * @size: the number of bytes to copy * * Similar to gst_adapter_copy, but more suitable for language bindings. @size * bytes of data starting at @offset will be copied out of the buffers contained * in @adapter and into a new #GBytes structure which is returned. Depending on * the value of the @size argument an empty #GBytes structure may be returned. * * Returns: (transfer full): A new #GBytes structure containing the copied data. * * Since: 1.4 */ GBytes * gst_adapter_copy_bytes (GstAdapter * adapter, gsize offset, gsize size) { gpointer data; data = g_malloc (size); gst_adapter_copy (adapter, data, offset, size); return g_bytes_new_take (data, size); }
static int mpegts_demuxer_read_packet(void *opaque, uint8_t *buffer, int size) { MpegTSDemuxer *demuxer = MPEGTS_DEMUXER(opaque); int result = 0; g_mutex_lock(&demuxer->lock); gint available = gst_adapter_available(demuxer->sink_adapter); while (available < demuxer->offset + size && !demuxer->is_eos && !demuxer->is_flushing && demuxer->is_reading) { if (demuxer->adapter_limit_type == UNLIMITED && demuxer->adapter_limit_size - LIMIT_STEP < demuxer->offset + size) { demuxer->adapter_limit_size += LIMIT_STEP; g_cond_signal(&demuxer->del_cond); } else g_cond_wait(&demuxer->add_cond, &demuxer->lock); available = gst_adapter_available(demuxer->sink_adapter); } if (demuxer->is_reading && !demuxer->is_flushing) { if (demuxer->is_eos && available <= size) { demuxer->is_last_buffer_send = TRUE; // Last buffer size = available; } if (size > 0) { gst_adapter_copy(demuxer->sink_adapter, buffer, demuxer->offset, size); if (demuxer->flush_adapter) gst_adapter_flush(demuxer->sink_adapter, size); else demuxer->offset += size; g_cond_signal(&demuxer->del_cond); result = size; #ifdef FAKE_ERROR demuxer->read_bytes += size; #endif } } else result = 0; // No more data g_mutex_unlock(&demuxer->lock); #ifdef DEBUG_OUTPUT if (result <= 0) g_print("MpegTS: read_packet result = %d, is_eos=%s, is_reading=%s, is_flushing=%s\n", result, BV(demuxer->is_eos), BV(demuxer->is_reading), BV(demuxer->is_flushing)); #endif return result; }
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); }
static GstFlowReturn gst_dvd_sub_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstDvdSubParse *parse = GST_DVD_SUB_PARSE (parent); GstAdapter *adapter; GstBuffer *outbuf = NULL; GstFlowReturn ret = GST_FLOW_OK; adapter = parse->adapter; GST_LOG_OBJECT (parse, "%" G_GSIZE_FORMAT " bytes, ts: %" GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); gst_adapter_push (adapter, buf); if (!parse->needed) { guint8 data[2]; gst_adapter_copy (adapter, data, 0, 2); parse->needed = GST_READ_UINT16_BE (data); } if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { if (GST_CLOCK_TIME_IS_VALID (parse->stamp)) /* normally, we expect only the first fragment to carry a timestamp */ GST_WARNING_OBJECT (parse, "Received more timestamps than expected."); else parse->stamp = GST_BUFFER_TIMESTAMP (buf); } if (parse->needed) { guint av; av = gst_adapter_available (adapter); if (av >= parse->needed) { if (av > parse->needed) { /* normally, we expect several fragment, boundary aligned */ GST_WARNING_OBJECT (parse, "Unexpected: needed %d, " "but more (%d) is available.", parse->needed, av); } outbuf = gst_adapter_take_buffer (adapter, parse->needed); /* decorate buffer */ GST_BUFFER_TIMESTAMP (outbuf) = parse->stamp; /* reset state */ parse->stamp = GST_CLOCK_TIME_NONE; parse->needed = 0; /* and send along */ ret = gst_pad_push (parse->srcpad, outbuf); } } return ret; }
static void copyGStreamerBuffersToAudioChannel(GstAdapter* adapter, AudioBus* bus , int channelNumber, size_t framesToProcess) { if (!gst_adapter_available(adapter)) { bus->zero(); return; } size_t bytes = framesToProcess * sizeof(float); if (gst_adapter_available(adapter) >= bytes) { gst_adapter_copy(adapter, bus->channel(channelNumber)->mutableData(), 0, bytes); gst_adapter_flush(adapter, bytes); } }
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; }
long AudioStream::read_bytes (void *data, long length) { gssize len = gst_adapter_available (adapter); if (len < length) length = len; GST_LOG ("Reading %d bytes from adapter", (int) length); gst_adapter_copy (adapter, data, 0, length); gst_adapter_flush (adapter, length); return length; }
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 GstFlowReturn gst_schro_dec_push_all (GstSchroDec *schro_dec, gboolean at_eos) { GstBuffer *parse_buf; SchroBuffer *input_buffer; GstFlowReturn ret = GST_FLOW_OK; while (TRUE) { gint size; unsigned char header[SCHRO_PARSE_HEADER_SIZE]; if (gst_adapter_available (schro_dec->adapter) < SCHRO_PARSE_HEADER_SIZE) { /* Need more data */ return GST_FLOW_OK; } gst_adapter_copy (schro_dec->adapter, header, 0, SCHRO_PARSE_HEADER_SIZE); if (memcmp (header, "BBCD", 4) != 0) { /* bad header or lost sync */ /* FIXME: we should handle this */ return GST_FLOW_ERROR; } size = GST_READ_UINT32_BE(header + 5); if (size == 0) size = 13; if (size < 13) { /* FIXME: should handle this by resyncing. */ return GST_FLOW_ERROR; } if (gst_adapter_available (schro_dec->adapter) < size) { return GST_FLOW_OK; } GST_LOG ("Have complete parse unit of %d bytes", size); parse_buf = gst_adapter_take_buffer (schro_dec->adapter, size); input_buffer = gst_schro_wrap_gst_buffer (parse_buf); ret = gst_schro_dec_process_buffer (schro_dec, input_buffer); if (ret != GST_FLOW_OK) { return ret; } } return GST_FLOW_OK; }
void metadataparse_util_tag_list_add_chunk (GstTagList * taglist, GstTagMergeMode mode, const gchar * name, GstAdapter * adapter) { GstBuffer *buf; guint size; if (adapter && (size = gst_adapter_available (adapter))) { buf = gst_buffer_new_and_alloc (size); gst_adapter_copy (adapter, GST_BUFFER_DATA (buf), 0, size); gst_tag_list_add (taglist, mode, name, buf, NULL); gst_buffer_unref (buf); } }
static gboolean gst_real_audio_demux_get_data_offset_from_header (GstRealAudioDemux * demux) { guint8 data[16]; gst_adapter_copy (demux->adapter, data, 0, 16); switch (demux->ra_version) { case 3: demux->data_offset = GST_READ_UINT16_BE (data) + 8; break; case 4: demux->data_offset = GST_READ_UINT32_BE (data + 12) + 16; break; default: demux->data_offset = 0; g_return_val_if_reached (FALSE); } return TRUE; }
static GstBaseVideoDecoderScanResult gst_vdp_mpeg_dec_scan_for_packet_end (GstBaseVideoDecoder * base_video_decoder, GstAdapter * adapter, guint * size, gboolean at_eos) { guint8 *data; guint32 sync_code; data = g_slice_alloc (SYNC_CODE_SIZE); gst_adapter_copy (adapter, data, 0, SYNC_CODE_SIZE); sync_code = ((data[0] << 16) | (data[1] << 8) | data[2]); if (sync_code != 0x000001) return GST_BASE_VIDEO_DECODER_SCAN_RESULT_LOST_SYNC; *size = gst_adapter_masked_scan_uint32 (adapter, 0xffffff00, 0x00000100, SYNC_CODE_SIZE, gst_adapter_available (adapter) - SYNC_CODE_SIZE); if (*size == -1) return GST_BASE_VIDEO_DECODER_SCAN_RESULT_NEED_DATA; return GST_BASE_VIDEO_DECODER_SCAN_RESULT_OK; }
static GstFlowReturn gst_real_audio_demux_parse_marker (GstRealAudioDemux * demux) { guint8 data[6]; if (gst_adapter_available (demux->adapter) < 6) { GST_LOG_OBJECT (demux, "need at least 6 bytes, waiting for more data"); return GST_FLOW_OK; } gst_adapter_copy (demux->adapter, data, 0, 6); if (memcmp (data, ".ra\375", 4) != 0) goto wrong_format; demux->ra_version = GST_READ_UINT16_BE (data + 4); GST_DEBUG_OBJECT (demux, "ra_version = %u", demux->ra_version); if (demux->ra_version != 4 && demux->ra_version != 3) goto unsupported_ra_version; gst_adapter_flush (demux->adapter, 6); demux->state = REAL_AUDIO_DEMUX_STATE_HEADER; return GST_FLOW_OK; /* ERRORS */ wrong_format: { GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, WRONG_TYPE, (NULL), (NULL)); return GST_FLOW_ERROR; } unsupported_ra_version: { GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE, ("Cannot decode this RealAudio file, please file a bug"), ("ra_version = %u", demux->ra_version)); return GST_FLOW_ERROR; } }
static FLAC__StreamDecoderReadStatus gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder, FLAC__byte buffer[], size_t * bytes, void *client_data) { GstFlacDec *dec = GST_FLAC_DEC (client_data); guint len; len = MIN (gst_adapter_available (dec->adapter), *bytes); if (len == 0) { GST_LOG_OBJECT (dec, "0 bytes available at the moment"); return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } GST_LOG_OBJECT (dec, "feeding %u bytes to decoder " "(available=%" G_GSIZE_FORMAT ", bytes=%u)", len, gst_adapter_available (dec->adapter), (guint) * bytes); gst_adapter_copy (dec->adapter, buffer, 0, len); *bytes = len; gst_adapter_flush (dec->adapter, len); return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; }
static GstFlowReturn gst_rtp_j2k_depay_flush_tile (GstBaseRTPDepayload * depayload) { GstRtpJ2KDepay *rtpj2kdepay; guint avail, mh_id; GList *packets, *walk; guint8 end[2]; GstFlowReturn ret = GST_FLOW_OK; rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload); /* flush pending PU */ gst_rtp_j2k_depay_flush_pu (depayload); /* take all available buffers */ avail = gst_adapter_available (rtpj2kdepay->t_adapter); if (avail == 0) goto done; mh_id = rtpj2kdepay->last_mh_id; GST_DEBUG_OBJECT (rtpj2kdepay, "flushing tile of size %u", avail); if (gst_adapter_available (rtpj2kdepay->f_adapter) == 0) { GstBuffer *mheader; /* we need a header now */ if ((mheader = rtpj2kdepay->MH[mh_id]) == NULL) goto waiting_header; /* push header in the adapter */ GST_DEBUG_OBJECT (rtpj2kdepay, "pushing header %u", mh_id); gst_adapter_push (rtpj2kdepay->f_adapter, gst_buffer_ref (mheader)); } /* check for last bytes */ gst_adapter_copy (rtpj2kdepay->t_adapter, end, avail - 2, 2); /* now append the tile packets to the frame */ packets = gst_adapter_take_list (rtpj2kdepay->t_adapter, avail); for (walk = packets; walk; walk = g_list_next (walk)) { GstBuffer *buf = GST_BUFFER_CAST (walk->data); if (walk == packets) { guint8 *data; guint size; /* first buffer should contain the SOT */ data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); if (size < 12) goto invalid_tile; if (data[0] == 0xff && data[1] == J2K_MARKER_SOT) { guint Psot, nPsot; if (end[0] == 0xff && end[1] == J2K_MARKER_EOC) nPsot = avail - 2; else nPsot = avail; Psot = GST_READ_UINT32_BE (&data[6]); if (Psot != nPsot && Psot != 0) { /* Psot must match the size of the tile */ GST_DEBUG_OBJECT (rtpj2kdepay, "set Psot from %u to %u", Psot, nPsot); buf = gst_buffer_make_writable (buf); data = GST_BUFFER_DATA (buf); GST_WRITE_UINT32_BE (&data[6], nPsot); } } } GST_DEBUG_OBJECT (rtpj2kdepay, "append pu packet of size %u", GST_BUFFER_SIZE (buf)); gst_adapter_push (rtpj2kdepay->f_adapter, buf); } g_list_free (packets); done: rtpj2kdepay->last_tile = -1; return ret; /* errors */ waiting_header: { GST_DEBUG_OBJECT (rtpj2kdepay, "waiting for header %u", mh_id); gst_adapter_clear (rtpj2kdepay->t_adapter); rtpj2kdepay->last_tile = -1; return ret; } invalid_tile: { GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Invalid tile"), (NULL)); gst_adapter_clear (rtpj2kdepay->t_adapter); rtpj2kdepay->last_tile = -1; return ret; } }
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 GstFlowReturn gst_rtp_j2k_depay_flush_frame (GstRTPBaseDepayload * depayload) { GstRtpJ2KDepay *rtpj2kdepay; guint8 end[2]; 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) { 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); gst_buffer_fill (outbuf, 0, end, 2); gst_adapter_push (rtpj2kdepay->f_adapter, outbuf); avail += 2; } GST_DEBUG_OBJECT (rtpj2kdepay, "pushing buffer of %u bytes", avail); outbuf = gst_adapter_take_buffer (rtpj2kdepay->f_adapter, avail); gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf, g_quark_from_static_string (GST_META_TAG_VIDEO_STR)); ret = gst_rtp_base_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_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) { GstRtpJPEGDepay *rtpjpegdepay; GstBuffer *outbuf; gint payload_len, header_len; guint8 *payload; guint frag_offset; gint Q; guint type, width, height; guint16 dri, precision, length; guint8 *qtable; rtpjpegdepay = GST_RTP_JPEG_DEPAY (depayload); if (GST_BUFFER_IS_DISCONT (rtp->buffer)) { GST_DEBUG_OBJECT (depayload, "DISCONT, reset adapter"); gst_adapter_clear (rtpjpegdepay->adapter); rtpjpegdepay->discont = TRUE; } payload_len = gst_rtp_buffer_get_payload_len (rtp); if (payload_len < 8) goto empty_packet; payload = gst_rtp_buffer_get_payload (rtp); header_len = 0; /* 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type-specific | Fragment Offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type | Q | Width | Height | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ frag_offset = (payload[1] << 16) | (payload[2] << 8) | payload[3]; type = payload[4]; Q = payload[5]; width = payload[6] * 8; height = payload[7] * 8; /* saw a packet with fragment offset > 0 and we don't already have data queued * up (most importantly, we don't have a header for this data) -- drop it * XXX: maybe we can check if the jpeg is progressive and salvage the data? * XXX: not implemented yet because jpegenc can't create progressive jpegs */ if (frag_offset > 0 && gst_adapter_available (rtpjpegdepay->adapter) == 0) goto no_header_packet; /* allow frame dimensions > 2040, passed in SDP session or media attributes * from gstrtspsrc.c (gst_rtspsrc_sdp_attributes_to_caps), or in caps */ if (!width) width = rtpjpegdepay->media_width; if (!height) height = rtpjpegdepay->media_height; if (width == 0 || height == 0) goto invalid_dimension; GST_DEBUG_OBJECT (rtpjpegdepay, "frag %u, type %u, Q %d, width %u, height %u", frag_offset, type, Q, width, height); header_len += 8; payload += 8; payload_len -= 8; dri = 0; if (type > 63) { if (payload_len < 4) goto empty_packet; /* 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Restart Interval |F|L| Restart Count | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ dri = (payload[0] << 8) | payload[1]; GST_DEBUG_OBJECT (rtpjpegdepay, "DRI %" G_GUINT16_FORMAT, dri); payload += 4; header_len += 4; payload_len -= 4; } if (Q >= 128 && frag_offset == 0) { if (payload_len < 4) goto empty_packet; /* 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 | Precision | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Quantization Table Data | * | ... | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ precision = payload[1]; length = (payload[2] << 8) | payload[3]; GST_DEBUG_OBJECT (rtpjpegdepay, "precision %04x, length %" G_GUINT16_FORMAT, precision, length); if (Q == 255 && length == 0) goto empty_packet; payload += 4; header_len += 4; payload_len -= 4; if (length > payload_len) goto empty_packet; if (length > 0) qtable = payload; else qtable = rtpjpegdepay->qtables[Q]; payload += length; header_len += length; payload_len -= length; } else { length = 0; qtable = NULL; precision = 0; } if (frag_offset == 0) { GstMapInfo map; guint size; if (rtpjpegdepay->width != width || rtpjpegdepay->height != height) { GstCaps *outcaps; outcaps = gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION, rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); gst_pad_set_caps (depayload->srcpad, outcaps); gst_caps_unref (outcaps); rtpjpegdepay->width = width; rtpjpegdepay->height = height; } GST_LOG_OBJECT (rtpjpegdepay, "first packet, length %" G_GUINT16_FORMAT, length); /* first packet */ if (length == 0) { if (Q < 128) { /* no quant table, see if we have one cached */ qtable = rtpjpegdepay->qtables[Q]; if (!qtable) { GST_DEBUG_OBJECT (rtpjpegdepay, "making Q %d table", Q); /* make and cache the table */ qtable = g_new (guint8, 128); MakeTables (rtpjpegdepay, Q, qtable); rtpjpegdepay->qtables[Q] = qtable; } else { GST_DEBUG_OBJECT (rtpjpegdepay, "using cached table for Q %d", Q); } /* all 8 bit quantizers */ precision = 0; } else { if (!qtable) goto no_qtable; } } /* I think we can get here with a NULL qtable, so make sure we don't go dereferencing it in MakeHeaders if we do */ if (!qtable) goto no_qtable; /* max header length, should be big enough */ outbuf = gst_buffer_new_and_alloc (1000); gst_buffer_map (outbuf, &map, GST_MAP_WRITE); size = MakeHeaders (map.data, type, width, height, qtable, precision, dri); gst_buffer_unmap (outbuf, &map); gst_buffer_resize (outbuf, 0, size); GST_DEBUG_OBJECT (rtpjpegdepay, "pushing %u bytes of header", size); gst_adapter_push (rtpjpegdepay->adapter, outbuf); } /* take JPEG data, push in the adapter */ GST_DEBUG_OBJECT (rtpjpegdepay, "pushing data at offset %d", header_len); outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, header_len, -1); gst_adapter_push (rtpjpegdepay->adapter, outbuf); outbuf = NULL; if (gst_rtp_buffer_get_marker (rtp)) { guint avail; guint8 end[2]; GstMapInfo map; /* last buffer take all data out of the adapter */ avail = gst_adapter_available (rtpjpegdepay->adapter); GST_DEBUG_OBJECT (rtpjpegdepay, "marker set, last buffer"); if (avail < 2) goto invalid_packet; /* take the last bytes of the jpeg data to see if there is an EOI * marker */ gst_adapter_copy (rtpjpegdepay->adapter, end, avail - 2, 2); if (end[0] != 0xff && end[1] != 0xd9) { GST_DEBUG_OBJECT (rtpjpegdepay, "no EOI marker, adding one"); /* no EOI marker, add one */ outbuf = gst_buffer_new_and_alloc (2); gst_buffer_map (outbuf, &map, GST_MAP_WRITE); map.data[0] = 0xff; map.data[1] = 0xd9; gst_buffer_unmap (outbuf, &map); gst_adapter_push (rtpjpegdepay->adapter, outbuf); avail += 2; } outbuf = gst_adapter_take_buffer (rtpjpegdepay->adapter, avail); if (rtpjpegdepay->discont) { GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); rtpjpegdepay->discont = FALSE; } gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpjpegdepay), outbuf, g_quark_from_static_string (GST_META_TAG_VIDEO_STR)); GST_DEBUG_OBJECT (rtpjpegdepay, "returning %u bytes", avail); } return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } invalid_dimension: { GST_ELEMENT_WARNING (rtpjpegdepay, STREAM, FORMAT, ("Invalid Dimension %dx%d.", width, height), (NULL)); return NULL; } no_qtable: { GST_WARNING_OBJECT (rtpjpegdepay, "no qtable"); return NULL; } invalid_packet: { GST_WARNING_OBJECT (rtpjpegdepay, "invalid packet"); gst_adapter_flush (rtpjpegdepay->adapter, gst_adapter_available (rtpjpegdepay->adapter)); return NULL; } no_header_packet: { GST_WARNING_OBJECT (rtpjpegdepay, "discarding data packets received when we have no header"); return NULL; } }
static GstFlowReturn gst_vcd_parse_chain (GstPad * pad, GstBuffer * buf) { GstVcdParse *vcd = GST_VCD_PARSE (GST_PAD_PARENT (pad)); GstFlowReturn flow = GST_FLOW_OK; gst_adapter_push (vcd->adapter, buf); buf = NULL; while (gst_adapter_available (vcd->adapter) >= GST_CDXA_SECTOR_SIZE) { const guint8 *data; guint8 header[4 + 8]; gint sync_offset; /* find sync (we could peek any size though really) */ data = gst_adapter_peek (vcd->adapter, GST_CDXA_SECTOR_SIZE); sync_offset = gst_vcd_parse_sync (data, GST_CDXA_SECTOR_SIZE); GST_LOG_OBJECT (vcd, "sync offset = %d", sync_offset); if (sync_offset < 0) { gst_adapter_flush (vcd->adapter, GST_CDXA_SECTOR_SIZE - 12); continue; /* try again */ } gst_adapter_flush (vcd->adapter, sync_offset); if (gst_adapter_available (vcd->adapter) < GST_CDXA_SECTOR_SIZE) { GST_LOG_OBJECT (vcd, "not enough data in adapter, waiting for more"); break; } GST_LOG_OBJECT (vcd, "have full sector"); /* have one sector: a sector is 2352 bytes long and is composed of: * * +-------------------------------------------------------+ * ! sync ! header ! subheader ! data ... ! edc ! * ! 12 bytes ! 4 bytes ! 8 bytes ! 2324 bytes ! 4 bytes ! * +-------------------------------------------------------+ * * We strip the data out of it and send it to the srcpad. * * sync : 00 FF FF FF FF FF FF FF FF FF FF 00 * header : hour minute second mode * sub-header : track channel sub_mode coding repeat (4 bytes) * edc : checksum */ /* Skip CDXA header and edc footer, only keep data in the middle */ gst_adapter_copy (vcd->adapter, header, 12, sizeof (header)); gst_adapter_flush (vcd->adapter, GST_CDXA_HEADER_SIZE); buf = gst_adapter_take_buffer (vcd->adapter, GST_CDXA_DATA_SIZE); gst_adapter_flush (vcd->adapter, 4); /* we could probably do something clever to keep track of buffer offsets */ buf = gst_buffer_make_metadata_writable (buf); GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE; gst_buffer_set_caps (buf, GST_PAD_CAPS (vcd->srcpad)); flow = gst_pad_push (vcd->srcpad, buf); buf = NULL; if (G_UNLIKELY (flow != GST_FLOW_OK)) { GST_DEBUG_OBJECT (vcd, "flow: %s", gst_flow_get_name (flow)); break; } } return flow; }
static GstBuffer * gst_rtp_j2k_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpJ2KDepay *rtpj2kdepay; GstBuffer *outbuf; guint8 *payload; guint frag_offset; rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload); /* flush everything on discont for now */ if (GST_BUFFER_IS_DISCONT (buf)) { GST_DEBUG_OBJECT (rtpj2kdepay, "DISCONT, flushing data"); gst_adapter_clear (rtpj2kdepay->adapter); rtpj2kdepay->need_header = TRUE; } if (gst_rtp_buffer_get_payload_len (buf) < 8) goto empty_packet; payload = gst_rtp_buffer_get_payload (buf); /* * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |tp |MHF|mh_id|T| priority | tile number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |reserved | fragment offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ frag_offset = (payload[5] << 16) | (payload[6] << 8) | payload[7]; GST_DEBUG_OBJECT (rtpj2kdepay, "frag %u", frag_offset); if (rtpj2kdepay->need_header) { if (frag_offset != 0) goto waiting_header; rtpj2kdepay->need_header = FALSE; } /* take JPEG 2000 data, push in the adapter */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 8, -1); gst_adapter_push (rtpj2kdepay->adapter, outbuf); outbuf = NULL; if (gst_rtp_buffer_get_marker (buf)) { guint avail; guint8 end[2]; guint8 *data; /* last buffer take all data out of the adapter */ avail = gst_adapter_available (rtpj2kdepay->adapter); GST_DEBUG_OBJECT (rtpj2kdepay, "marker set, last buffer"); /* take the last bytes of the JPEG 2000 data to see if there is an EOC * marker */ gst_adapter_copy (rtpj2kdepay->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->adapter, outbuf); avail += 2; } outbuf = gst_adapter_take_buffer (rtpj2kdepay->adapter, avail); GST_DEBUG_OBJECT (rtpj2kdepay, "returning %u bytes", avail); } return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } waiting_header: { GST_DEBUG_OBJECT (rtpj2kdepay, "we are waiting for a header"); return NULL; } }
static GstBuffer * gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstBuffer * buf) { GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay); GstBuffer *payload; guint8 *data; guint hdrsize; guint size; GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) { GST_LOG_OBJECT (self, "Discontinuity, flushing adapter"); gst_adapter_clear (self->adapter); self->started = FALSE; } gst_rtp_buffer_map (buf, GST_MAP_READ, &rtpbuffer); size = gst_rtp_buffer_get_payload_len (&rtpbuffer); /* At least one header and one vp8 byte */ if (G_UNLIKELY (size < 2)) goto too_small; data = gst_rtp_buffer_get_payload (&rtpbuffer); if (G_UNLIKELY (!self->started)) { /* Check if this is the start of a VP8 frame, otherwise bail */ /* S=1 and PartID= 0 */ if ((data[0] & 0x1F) != 0x10) goto done; self->started = TRUE; } hdrsize = 1; /* Check X optional header */ if ((data[0] & 0x80) != 0) { hdrsize++; /* Check I optional header */ if ((data[1] & 0x80) != 0) { if (G_UNLIKELY (size < 3)) goto too_small; hdrsize++; /* Check for 16 bits PictureID */ if ((data[2] & 0x80) != 0) hdrsize++; } /* Check L optional header */ if ((data[1] & 0x40) != 0) hdrsize++; /* Check T or K optional headers */ if ((data[1] & 0x20) != 0 || (data[1] & 0x10) != 0) hdrsize++; } GST_DEBUG_OBJECT (depay, "hdrsize %u, size %u", hdrsize, size); if (G_UNLIKELY (hdrsize >= size)) goto too_small; payload = gst_rtp_buffer_get_payload_subbuffer (&rtpbuffer, hdrsize, -1); gst_adapter_push (self->adapter, payload); /* Marker indicates that it was the last rtp packet for this frame */ if (gst_rtp_buffer_get_marker (&rtpbuffer)) { GstBuffer *out; guint8 flag0; gst_adapter_copy (self->adapter, &flag0, 0, 1); out = gst_adapter_take_buffer (self->adapter, gst_adapter_available (self->adapter)); self->started = FALSE; gst_rtp_buffer_unmap (&rtpbuffer); /* mark keyframes */ out = gst_buffer_make_writable (out); if ((flag0 & 0x01)) GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT); else GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT); return out; } done: gst_rtp_buffer_unmap (&rtpbuffer); return NULL; too_small: GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring"); gst_adapter_clear (self->adapter); self->started = FALSE; goto done; }
static GstBaseVideoDecoderScanResult gst_vdp_h264_dec_scan_for_packet_end (GstBaseVideoDecoder * base_video_decoder, GstAdapter * adapter, guint * size, gboolean at_eos) { GstVdpH264Dec *h264_dec = GST_VDP_H264_DEC (base_video_decoder); guint avail; avail = gst_adapter_available (adapter); if (avail < h264_dec->nal_length_size) return GST_BASE_VIDEO_DECODER_SCAN_RESULT_NEED_DATA; if (h264_dec->packetized) { guint8 *data; gint i; guint32 nal_length = 0; data = g_slice_alloc (h264_dec->nal_length_size); gst_adapter_copy (adapter, data, 0, h264_dec->nal_length_size); for (i = 0; i < h264_dec->nal_length_size; i++) nal_length = (nal_length << 8) | data[i]; g_slice_free1 (h264_dec->nal_length_size, data); nal_length += h264_dec->nal_length_size; /* check for invalid NALU sizes, assume the size if the available bytes * when something is fishy */ if (nal_length <= 1 || nal_length > avail) { nal_length = avail - h264_dec->nal_length_size; GST_DEBUG ("fixing invalid NALU size to %u", nal_length); } *size = nal_length; } else { guint8 *data; guint32 start_code; guint n; data = g_slice_alloc (SYNC_CODE_SIZE); gst_adapter_copy (adapter, data, 0, SYNC_CODE_SIZE); start_code = ((data[0] << 16) && (data[1] << 8) && data[2]); g_slice_free1 (SYNC_CODE_SIZE, data); GST_DEBUG ("start_code: %d", start_code); if (start_code == 0x000001) return GST_BASE_VIDEO_DECODER_SCAN_RESULT_LOST_SYNC; n = gst_adapter_masked_scan_uint32 (adapter, 0xffffff00, 0x00000100, SYNC_CODE_SIZE, avail - SYNC_CODE_SIZE); if (n == -1) return GST_BASE_VIDEO_DECODER_SCAN_RESULT_NEED_DATA; *size = n; } GST_DEBUG ("NAL size: %d", *size); return GST_BASE_VIDEO_DECODER_SCAN_RESULT_OK; }
static GstFlowReturn gst_y4m_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstY4mDec *y4mdec; int n_avail; GstFlowReturn flow_ret = GST_FLOW_OK; #define MAX_HEADER_LENGTH 80 char header[MAX_HEADER_LENGTH]; int i; int len; y4mdec = GST_Y4M_DEC (parent); GST_DEBUG_OBJECT (y4mdec, "chain"); if (GST_BUFFER_IS_DISCONT (buffer)) { GST_DEBUG ("got discont"); gst_adapter_clear (y4mdec->adapter); } gst_adapter_push (y4mdec->adapter, buffer); n_avail = gst_adapter_available (y4mdec->adapter); if (!y4mdec->have_header) { gboolean ret; GstCaps *caps; if (n_avail < MAX_HEADER_LENGTH) return GST_FLOW_OK; gst_adapter_copy (y4mdec->adapter, (guint8 *) header, 0, MAX_HEADER_LENGTH); header[MAX_HEADER_LENGTH - 1] = 0; for (i = 0; i < MAX_HEADER_LENGTH; i++) { if (header[i] == 0x0a) header[i] = 0; } ret = gst_y4m_dec_parse_header (y4mdec, header); if (!ret) { GST_ELEMENT_ERROR (y4mdec, STREAM, DECODE, ("Failed to parse YUV4MPEG header"), (NULL)); return GST_FLOW_ERROR; } y4mdec->header_size = strlen (header) + 1; gst_adapter_flush (y4mdec->adapter, y4mdec->header_size); caps = gst_video_info_to_caps (&y4mdec->info); ret = gst_pad_set_caps (y4mdec->srcpad, caps); gst_caps_unref (caps); if (!ret) { GST_DEBUG_OBJECT (y4mdec, "Couldn't set caps on src pad"); return GST_FLOW_ERROR; } y4mdec->have_header = TRUE; } if (y4mdec->have_new_segment) { GstEvent *event; GstClockTime start = gst_y4m_dec_bytes_to_timestamp (y4mdec, y4mdec->segment.start); GstClockTime stop = gst_y4m_dec_bytes_to_timestamp (y4mdec, y4mdec->segment.stop); GstClockTime time = gst_y4m_dec_bytes_to_timestamp (y4mdec, y4mdec->segment.time); GstSegment seg; gst_segment_init (&seg, GST_FORMAT_TIME); seg.start = start; seg.stop = stop; seg.time = time; event = gst_event_new_segment (&seg); gst_pad_push_event (y4mdec->srcpad, event); //gst_event_unref (event); y4mdec->have_new_segment = FALSE; y4mdec->frame_index = gst_y4m_dec_bytes_to_frames (y4mdec, y4mdec->segment.time); GST_DEBUG ("new frame_index %d", y4mdec->frame_index); } while (1) { n_avail = gst_adapter_available (y4mdec->adapter); if (n_avail < MAX_HEADER_LENGTH) break; gst_adapter_copy (y4mdec->adapter, (guint8 *) header, 0, MAX_HEADER_LENGTH); header[MAX_HEADER_LENGTH - 1] = 0; for (i = 0; i < MAX_HEADER_LENGTH; i++) { if (header[i] == 0x0a) header[i] = 0; } if (memcmp (header, "FRAME", 5) != 0) { GST_ELEMENT_ERROR (y4mdec, STREAM, DECODE, ("Failed to parse YUV4MPEG frame"), (NULL)); flow_ret = GST_FLOW_ERROR; break; } len = strlen (header); if (n_avail < y4mdec->info.size + len + 1) { /* not enough data */ GST_DEBUG ("not enough data for frame %d < %" G_GSIZE_FORMAT, n_avail, y4mdec->info.size + len + 1); break; } gst_adapter_flush (y4mdec->adapter, len + 1); buffer = gst_adapter_take_buffer (y4mdec->adapter, y4mdec->info.size); GST_BUFFER_TIMESTAMP (buffer) = gst_y4m_dec_frames_to_timestamp (y4mdec, y4mdec->frame_index); GST_BUFFER_DURATION (buffer) = gst_y4m_dec_frames_to_timestamp (y4mdec, y4mdec->frame_index + 1) - GST_BUFFER_TIMESTAMP (buffer); y4mdec->frame_index++; flow_ret = gst_pad_push (y4mdec->srcpad, buffer); if (flow_ret != GST_FLOW_OK) break; } GST_DEBUG ("returning %d", flow_ret); return flow_ret; }
static GstFlowReturn gst_gdp_depay_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstGDPDepay *this; GstFlowReturn ret = GST_FLOW_OK; GstCaps *caps; GstBuffer *buf; GstEvent *event; guint available; this = GST_GDP_DEPAY (parent); /* On DISCONT, get rid of accumulated data. We assume a buffer after the * DISCONT contains (part of) a new valid header, if not we error because we * lost sync */ if (GST_BUFFER_IS_DISCONT (buffer)) { gst_adapter_clear (this->adapter); this->state = GST_GDP_DEPAY_STATE_HEADER; } gst_adapter_push (this->adapter, buffer); while (TRUE) { switch (this->state) { case GST_GDP_DEPAY_STATE_HEADER: { guint8 *header; /* collect a complete header, validate and store the header. Figure out * the payload length and switch to the PAYLOAD state */ available = gst_adapter_available (this->adapter); if (available < GST_DP_HEADER_LENGTH) goto done; GST_LOG_OBJECT (this, "reading GDP header from adapter"); header = gst_adapter_take (this->adapter, GST_DP_HEADER_LENGTH); if (!gst_dp_validate_header (GST_DP_HEADER_LENGTH, header)) { g_free (header); goto header_validate_error; } /* store types and payload length. Also store the header, which we need * to make the payload. */ this->payload_length = gst_dp_header_payload_length (header); this->payload_type = gst_dp_header_payload_type (header); /* free previous header and store new one. */ g_free (this->header); this->header = header; GST_LOG_OBJECT (this, "read GDP header, payload size %d, payload type %d, switching to state PAYLOAD", this->payload_length, this->payload_type); this->state = GST_GDP_DEPAY_STATE_PAYLOAD; break; } case GST_GDP_DEPAY_STATE_PAYLOAD: { /* in this state we wait for all the payload data to be available in the * adapter. Then we switch to the state where we actually process the * payload. */ available = gst_adapter_available (this->adapter); if (available < this->payload_length) goto done; /* change state based on type */ if (this->payload_type == GST_DP_PAYLOAD_BUFFER) { GST_LOG_OBJECT (this, "switching to state BUFFER"); this->state = GST_GDP_DEPAY_STATE_BUFFER; } else if (this->payload_type == GST_DP_PAYLOAD_CAPS) { GST_LOG_OBJECT (this, "switching to state CAPS"); this->state = GST_GDP_DEPAY_STATE_CAPS; } else if (this->payload_type >= GST_DP_PAYLOAD_EVENT_NONE) { GST_LOG_OBJECT (this, "switching to state EVENT"); this->state = GST_GDP_DEPAY_STATE_EVENT; } else { goto wrong_type; } if (this->payload_length) { const guint8 *data; gboolean res; data = gst_adapter_map (this->adapter, this->payload_length); res = gst_dp_validate_payload (GST_DP_HEADER_LENGTH, this->header, data); gst_adapter_unmap (this->adapter); if (!res) goto payload_validate_error; } break; } case GST_GDP_DEPAY_STATE_BUFFER: { /* if we receive a buffer without caps first, we error out */ if (!this->caps) goto no_caps; GST_LOG_OBJECT (this, "reading GDP buffer from adapter"); buf = gst_dp_buffer_from_header (GST_DP_HEADER_LENGTH, this->header); if (!buf) goto buffer_failed; /* now take the payload if there is any */ if (this->payload_length > 0) { GstMapInfo map; gst_buffer_map (buf, &map, GST_MAP_WRITE); gst_adapter_copy (this->adapter, map.data, 0, this->payload_length); gst_buffer_unmap (buf, &map); gst_adapter_flush (this->adapter, this->payload_length); } /* set caps and push */ GST_LOG_OBJECT (this, "deserialized buffer %p, pushing, timestamp %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT ", size %" G_GSIZE_FORMAT ", flags 0x%x", buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf), gst_buffer_get_size (buf), GST_BUFFER_FLAGS (buf)); ret = gst_pad_push (this->srcpad, buf); if (ret != GST_FLOW_OK) goto push_error; GST_LOG_OBJECT (this, "switching to state HEADER"); this->state = GST_GDP_DEPAY_STATE_HEADER; break; } case GST_GDP_DEPAY_STATE_CAPS: { guint8 *payload; /* take the payload of the caps */ GST_LOG_OBJECT (this, "reading GDP caps from adapter"); payload = gst_adapter_take (this->adapter, this->payload_length); caps = gst_dp_caps_from_packet (GST_DP_HEADER_LENGTH, this->header, payload); g_free (payload); if (!caps) goto caps_failed; GST_DEBUG_OBJECT (this, "deserialized caps %" GST_PTR_FORMAT, caps); gst_caps_replace (&(this->caps), caps); gst_pad_set_caps (this->srcpad, caps); /* drop the creation ref we still have */ gst_caps_unref (caps); GST_LOG_OBJECT (this, "switching to state HEADER"); this->state = GST_GDP_DEPAY_STATE_HEADER; break; } case GST_GDP_DEPAY_STATE_EVENT: { guint8 *payload; GST_LOG_OBJECT (this, "reading GDP event from adapter"); /* adapter doesn't like 0 length payload */ if (this->payload_length > 0) payload = gst_adapter_take (this->adapter, this->payload_length); else payload = NULL; event = gst_dp_event_from_packet (GST_DP_HEADER_LENGTH, this->header, payload); g_free (payload); if (!event) goto event_failed; GST_DEBUG_OBJECT (this, "deserialized event %p of type %s, pushing", event, gst_event_type_get_name (event->type)); gst_pad_push_event (this->srcpad, event); GST_LOG_OBJECT (this, "switching to state HEADER"); this->state = GST_GDP_DEPAY_STATE_HEADER; break; } } } done: return ret; /* ERRORS */ header_validate_error: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("GDP packet header does not validate")); ret = GST_FLOW_ERROR; goto done; } payload_validate_error: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("GDP packet payload does not validate")); ret = GST_FLOW_ERROR; goto done; } wrong_type: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("GDP packet header is of wrong type")); ret = GST_FLOW_ERROR; goto done; } no_caps: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("Received a buffer without first receiving caps")); ret = GST_FLOW_NOT_NEGOTIATED; goto done; } buffer_failed: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("could not create buffer from GDP packet")); ret = GST_FLOW_ERROR; goto done; } push_error: { GST_WARNING_OBJECT (this, "pushing depayloaded buffer returned %d", ret); goto done; } caps_failed: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("could not create caps from GDP packet")); ret = GST_FLOW_ERROR; goto done; } event_failed: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("could not create event from GDP packet")); ret = GST_FLOW_ERROR; goto done; } }
static GstFlowReturn gst_rtp_h263p_pay_flush (GstRtpH263PPay * rtph263ppay) { guint avail; GstBuffer *outbuf; GstFlowReturn ret; gboolean fragmented; 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; guint payload_len; gint header_len; guint next_gop = 0; gboolean found_gob = FALSE; GstRTPBuffer rtp = { NULL }; if (rtph263ppay->fragmentation_mode == GST_FRAGMENTATION_MODE_SYNC) { /* start after 1st gop possible */ guint parsed_len = 3; const guint8 *parse_data = NULL; parse_data = gst_adapter_map (rtph263ppay->adapter, avail); /* Check if we have a gob or eos , eossbs */ /* FIXME EOS and EOSSBS packets should never contain any gobs and vice-versa */ if (avail >= 3 && *parse_data == 0 && *(parse_data + 1) == 0 && *(parse_data + 2) >= 0x80) { 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 */ while (parsed_len + 2 < avail) { if (parse_data[parsed_len] == 0 && parse_data[parsed_len + 1] == 0 && parse_data[parsed_len + 2] >= 0x80) { next_gop = parsed_len; GST_DEBUG_OBJECT (rtph263ppay, " Next GOB Detected at : %d", next_gop); break; } parsed_len++; } gst_adapter_unmap (rtph263ppay->adapter); } /* for picture start frames (non-fragmented), we need to remove the first * two 0x00 bytes and set P=1 */ header_len = (fragmented && !found_gob) ? 2 : 0; 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); payload_len = header_len + towrite; outbuf = gst_rtp_buffer_new_allocate (payload_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); gst_adapter_copy (rtph263ppay->adapter, &payload[header_len], 0, towrite); /* 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_TIMESTAMP (outbuf) = rtph263ppay->first_timestamp; GST_BUFFER_DURATION (outbuf) = rtph263ppay->first_duration; gst_rtp_buffer_unmap (&rtp); gst_adapter_flush (rtph263ppay->adapter, towrite); ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtph263ppay), outbuf); avail -= towrite; fragmented = TRUE; } return ret; }