static GstFlowReturn gst_interleave_collected (GstCollectPads * pads, GstInterleave * self) { guint size; GstBuffer *outbuf = NULL; GstFlowReturn ret = GST_FLOW_OK; GSList *collected; guint nsamples; guint ncollected = 0; gboolean empty = TRUE; gint width = self->width / 8; GstMapInfo write_info; GstClockTime timestamp = -1; /* FIXME: send caps and tags after stream-start */ #if 0 if (self->send_stream_start) { gchar s_id[32]; /* stream-start (FIXME: create id based on input ids) */ g_snprintf (s_id, sizeof (s_id), "interleave-%08x", g_random_int ()); gst_pad_push_event (self->src, gst_event_new_stream_start (s_id)); self->send_stream_start = FALSE; } #endif size = gst_collect_pads_available (pads); if (size == 0) goto eos; g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (self->width > 0, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (self->channels > 0, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (self->rate > 0, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (size % width == 0, GST_FLOW_ERROR); GST_DEBUG_OBJECT (self, "Starting to collect %u bytes from %d channels", size, self->channels); nsamples = size / width; outbuf = gst_buffer_new_allocate (NULL, size * self->channels, NULL); if (outbuf == NULL || gst_buffer_get_size (outbuf) < size * self->channels) { gst_buffer_unref (outbuf); return GST_FLOW_NOT_NEGOTIATED; } gst_buffer_map (outbuf, &write_info, GST_MAP_WRITE); memset (write_info.data, 0, size * self->channels); for (collected = pads->data; collected != NULL; collected = collected->next) { GstCollectData *cdata; GstBuffer *inbuf; guint8 *outdata; GstMapInfo input_info; cdata = (GstCollectData *) collected->data; inbuf = gst_collect_pads_take_buffer (pads, cdata, size); if (inbuf == NULL) { GST_DEBUG_OBJECT (cdata->pad, "No buffer available"); goto next; } ncollected++; gst_buffer_map (inbuf, &input_info, GST_MAP_READ); if (timestamp == -1) timestamp = GST_BUFFER_TIMESTAMP (inbuf); if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) goto next; empty = FALSE; outdata = write_info.data + width * GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel; self->func (outdata, input_info.data, self->channels, nsamples); gst_buffer_unmap (inbuf, &input_info); next: if (inbuf) gst_buffer_unref (inbuf); } if (ncollected == 0) { gst_buffer_unmap (outbuf, &write_info); goto eos; } GST_OBJECT_LOCK (self); if (self->pending_segment) { GstEvent *event; GstSegment segment; event = self->pending_segment; self->pending_segment = NULL; GST_OBJECT_UNLOCK (self); /* convert the input segment to time now */ gst_event_copy_segment (event, &segment); if (segment.format != GST_FORMAT_TIME) { gst_event_unref (event); /* not time, convert */ switch (segment.format) { case GST_FORMAT_BYTES: segment.start *= width; if (segment.stop != -1) segment.stop *= width; if (segment.position != -1) segment.position *= width; /* fallthrough for the samples case */ case GST_FORMAT_DEFAULT: segment.start = gst_util_uint64_scale_int (segment.start, GST_SECOND, self->rate); if (segment.stop != -1) segment.stop = gst_util_uint64_scale_int (segment.stop, GST_SECOND, self->rate); if (segment.position != -1) segment.position = gst_util_uint64_scale_int (segment.position, GST_SECOND, self->rate); break; default: GST_WARNING ("can't convert segment values"); segment.start = 0; segment.stop = -1; segment.position = 0; break; } event = gst_event_new_segment (&segment); } gst_pad_push_event (self->src, event); GST_OBJECT_LOCK (self); } GST_OBJECT_UNLOCK (self); if (timestamp != -1) { self->offset = gst_util_uint64_scale_int (timestamp, self->rate, GST_SECOND); self->timestamp = timestamp; } GST_BUFFER_TIMESTAMP (outbuf) = self->timestamp; GST_BUFFER_OFFSET (outbuf) = self->offset; self->offset += nsamples; self->timestamp = gst_util_uint64_scale_int (self->offset, GST_SECOND, self->rate); GST_BUFFER_DURATION (outbuf) = self->timestamp - GST_BUFFER_TIMESTAMP (outbuf); if (empty) GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP); gst_buffer_unmap (outbuf, &write_info); GST_LOG_OBJECT (self, "pushing outbuf, timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); ret = gst_pad_push (self->src, outbuf); return ret; eos: { GST_DEBUG_OBJECT (self, "no data available, must be EOS"); if (outbuf) gst_buffer_unref (outbuf); gst_pad_push_event (self->src, gst_event_new_eos ()); return GST_FLOW_EOS; } }
static GstFlowReturn gst_interleave_collected (GstCollectPads * pads, GstInterleave * self) { guint size; GstBuffer *outbuf; GstFlowReturn ret = GST_FLOW_OK; GSList *collected; guint nsamples; guint ncollected = 0; gboolean empty = TRUE; gint width = self->width / 8; g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (self->width > 0, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (self->channels > 0, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (self->rate > 0, GST_FLOW_NOT_NEGOTIATED); size = gst_collect_pads_available (pads); g_return_val_if_fail (size % width == 0, GST_FLOW_ERROR); GST_DEBUG_OBJECT (self, "Starting to collect %u bytes from %d channels", size, self->channels); nsamples = size / width; ret = gst_pad_alloc_buffer (self->src, GST_BUFFER_OFFSET_NONE, size * self->channels, GST_PAD_CAPS (self->src), &outbuf); if (ret != GST_FLOW_OK) { return ret; } else if (outbuf == NULL || GST_BUFFER_SIZE (outbuf) < size * self->channels) { gst_buffer_unref (outbuf); return GST_FLOW_NOT_NEGOTIATED; } else if (!gst_caps_is_equal (GST_BUFFER_CAPS (outbuf), GST_PAD_CAPS (self->src))) { gst_buffer_unref (outbuf); return GST_FLOW_NOT_NEGOTIATED; } memset (GST_BUFFER_DATA (outbuf), 0, size * self->channels); for (collected = pads->data; collected != NULL; collected = collected->next) { GstCollectData *cdata; GstBuffer *inbuf; guint8 *outdata; cdata = (GstCollectData *) collected->data; inbuf = gst_collect_pads_take_buffer (pads, cdata, size); if (inbuf == NULL) { GST_DEBUG_OBJECT (cdata->pad, "No buffer available"); goto next; } ncollected++; if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) goto next; empty = FALSE; outdata = GST_BUFFER_DATA (outbuf) + width * GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel; self->func (outdata, GST_BUFFER_DATA (inbuf), self->channels, nsamples); next: if (inbuf) gst_buffer_unref (inbuf); } if (ncollected == 0) goto eos; if (self->segment_pending) { GstEvent *event; event = gst_event_new_new_segment_full (FALSE, self->segment_rate, 1.0, GST_FORMAT_TIME, self->timestamp, -1, self->segment_position); gst_pad_push_event (self->src, event); self->segment_pending = FALSE; self->segment_position = 0; } GST_BUFFER_TIMESTAMP (outbuf) = self->timestamp; GST_BUFFER_OFFSET (outbuf) = self->offset; self->offset += nsamples; self->timestamp = gst_util_uint64_scale_int (self->offset, GST_SECOND, self->rate); GST_BUFFER_DURATION (outbuf) = self->timestamp - GST_BUFFER_TIMESTAMP (outbuf); if (empty) GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP); GST_LOG_OBJECT (self, "pushing outbuf, timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); ret = gst_pad_push (self->src, outbuf); return ret; eos: { GST_DEBUG_OBJECT (self, "no data available, must be EOS"); gst_buffer_unref (outbuf); gst_pad_push_event (self->src, gst_event_new_eos ()); return GST_FLOW_UNEXPECTED; } }