static void feed_textbuf (GstSubParse * self, GstBuffer * buf) { gboolean discont; discont = GST_BUFFER_IS_DISCONT (buf); if (GST_BUFFER_OFFSET_IS_VALID (buf) && GST_BUFFER_OFFSET (buf) != self->offset) { self->offset = GST_BUFFER_OFFSET (buf); discont = TRUE; } if (discont) { GST_INFO ("discontinuity"); /* flush the parser state */ parser_state_init (&self->state); g_string_truncate (self->textbuf, 0); sami_context_reset (&self->state); /* we could set a flag to make sure that the next buffer we push out also * has the DISCONT flag set, but there's no point really given that it's * subtitles which are discontinuous by nature. */ } self->textbuf = g_string_append_len (self->textbuf, (gchar *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); self->offset = GST_BUFFER_OFFSET (buf) + GST_BUFFER_SIZE (buf); self->next_offset = self->offset; gst_buffer_unref (buf); }
GstFlowReturn got_data(GstPad *pad, GstObject *parent, GstBuffer *buf) { GstTfImpl *This = gst_pad_get_element_private(pad); IMediaSample *sample = (IMediaSample *) gst_mini_object_get_qdata(GST_MINI_OBJECT(buf), g_quark_from_static_string(media_quark_string)); REFERENCE_TIME tStart, tStop; HRESULT hr; TRACE("%p, %p\n", pad, buf); if(!sample){ GstMapInfo info; BYTE *ptr; gst_buffer_map(buf, &info, GST_MAP_READ); hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->tf.ppPins[1], &sample, NULL, NULL, 0); if (FAILED(hr)) { ERR("Could not get output buffer: %08x\n", hr); return GST_FLOW_FLUSHING; } IMediaSample_SetActualDataLength(sample, info.size); IMediaSample_GetPointer(sample, &ptr); memcpy(ptr, info.data, info.size); gst_buffer_unmap(buf, &info); } if (GST_BUFFER_PTS_IS_VALID(buf) && GST_BUFFER_DURATION_IS_VALID(buf)) { tStart = buf->pts / 100; tStop = tStart + buf->duration / 100; IMediaSample_SetTime(sample, &tStart, &tStop); } else IMediaSample_SetTime(sample, NULL, NULL); if (GST_BUFFER_OFFSET_IS_VALID(buf) && GST_BUFFER_OFFSET_END_IS_VALID(buf)) { tStart = buf->offset / 100; tStop = buf->offset_end / 100; IMediaSample_SetMediaTime(sample, &tStart, &tStop); } else IMediaSample_SetMediaTime(sample, NULL, NULL); IMediaSample_SetDiscontinuity(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT)); IMediaSample_SetPreroll(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_LIVE)); IMediaSample_SetSyncPoint(sample, !GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT)); IMediaSample_SetActualDataLength(sample, gst_buffer_get_size(buf)); hr = BaseOutputPinImpl_Deliver((BaseOutputPin*)This->tf.ppPins[1], sample); IMediaSample_Release(sample); gst_buffer_unref(buf); if (FAILED(hr)) return GST_FLOW_FLUSHING; return GST_FLOW_OK; }
static GstFlowReturn gst_hls_demux_data_received (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream, GstBuffer * buffer) { GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux); if (hlsdemux->current_offset == -1) hlsdemux->current_offset = GST_BUFFER_OFFSET_IS_VALID (buffer) ? GST_BUFFER_OFFSET (buffer) : 0; /* Is it encrypted? */ if (hlsdemux->current_key) { GError *err = NULL; gsize size; GstBuffer *tmp_buffer; gst_adapter_push (hlsdemux->pending_encrypted_data, buffer); size = gst_adapter_available (hlsdemux->pending_encrypted_data); /* must be a multiple of 16 */ size = size & (~0xF); if (size == 0) { return GST_FLOW_OK; } buffer = gst_adapter_take_buffer (hlsdemux->pending_encrypted_data, size); buffer = gst_hls_demux_decrypt_fragment (hlsdemux, buffer, &err); if (buffer == NULL) { GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Failed to decrypt buffer"), ("decryption failed %s", err->message)); g_error_free (err); return GST_FLOW_ERROR; } tmp_buffer = hlsdemux->pending_decrypted_buffer; hlsdemux->pending_decrypted_buffer = buffer; buffer = tmp_buffer; } return gst_hls_demux_handle_buffer (demux, stream, buffer, FALSE); }
static void got_buffer (GstElement * fakesink, GstBuffer * buf, GstPad * pad, GstBuffer ** p_buf) { gint64 off; GstMapInfo map; off = GST_BUFFER_OFFSET (buf); gst_buffer_map (buf, &map, GST_MAP_READ); GST_LOG ("got buffer, size=%u, offset=%" G_GINT64_FORMAT, map.size, off); fail_unless (GST_BUFFER_OFFSET_IS_VALID (buf)); if (*p_buf == NULL || (off + map.size) > gst_buffer_get_size (*p_buf)) { GstBuffer *newbuf; /* not very elegant, but who cares */ newbuf = gst_buffer_new_and_alloc (off + map.size); if (*p_buf) { GstMapInfo pmap; gst_buffer_map (*p_buf, &pmap, GST_MAP_READ); gst_buffer_fill (newbuf, 0, pmap.data, pmap.size); gst_buffer_unmap (*p_buf, &pmap); } gst_buffer_fill (newbuf, off, map.data, map.size); if (*p_buf) gst_buffer_unref (*p_buf); *p_buf = newbuf; } else { gst_buffer_fill (*p_buf, off, map.data, map.size); } gst_buffer_unmap (buf, &map); }
static GstFlowReturn got_data(GstPad *pad, GstBuffer *buf) { GstTfImpl *This = gst_pad_get_element_private(pad); IMediaSample *sample = GST_APP_BUFFER(buf)->priv; REFERENCE_TIME tStart, tStop; HRESULT hr; if (GST_BUFFER_TIMESTAMP_IS_VALID(buf) && GST_BUFFER_DURATION_IS_VALID(buf)) { tStart = buf->timestamp / 100; tStop = tStart + buf->duration / 100; IMediaSample_SetTime(sample, &tStart, &tStop); } else IMediaSample_SetTime(sample, NULL, NULL); if (GST_BUFFER_OFFSET_IS_VALID(buf) && GST_BUFFER_OFFSET_END_IS_VALID(buf)) { tStart = buf->offset / 100; tStop = buf->offset_end / 100; IMediaSample_SetMediaTime(sample, &tStart, &tStop); } else IMediaSample_SetMediaTime(sample, NULL, NULL); IMediaSample_SetDiscontinuity(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT)); IMediaSample_SetPreroll(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_PREROLL)); IMediaSample_SetSyncPoint(sample, !GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT)); IMediaSample_SetActualDataLength(sample, GST_BUFFER_SIZE(buf)); hr = BaseOutputPinImpl_Deliver((BaseOutputPin*)This->tf.ppPins[1], sample); gst_buffer_unref(buf); if (FAILED(hr)) return GST_FLOW_WRONG_STATE; if (hr != S_OK) return GST_FLOW_RESEND; return GST_FLOW_OK; }
static void do_perfect_stream_test (guint rate, guint width, gdouble drop_probability, gdouble inject_probability) { GstElement *pipe, *src, *conv, *filter, *injector, *audiorate, *sink; GstMessage *msg; GstCaps *caps; GstPad *srcpad; GList *l, *bufs = NULL; GstClockTime next_time = GST_CLOCK_TIME_NONE; guint64 next_offset = GST_BUFFER_OFFSET_NONE; caps = gst_caps_new_simple ("audio/x-raw-int", "rate", G_TYPE_INT, rate, "width", G_TYPE_INT, width, NULL); GST_INFO ("-------- drop=%.0f%% caps = %" GST_PTR_FORMAT " ---------- ", drop_probability * 100.0, caps); g_assert (drop_probability >= 0.0 && drop_probability <= 1.0); g_assert (inject_probability >= 0.0 && inject_probability <= 1.0); g_assert (width > 0 && (width % 8) == 0); pipe = gst_pipeline_new ("pipeline"); fail_unless (pipe != NULL); src = gst_element_factory_make ("audiotestsrc", "audiotestsrc"); fail_unless (src != NULL); g_object_set (src, "num-buffers", 100, NULL); conv = gst_element_factory_make ("audioconvert", "audioconvert"); fail_unless (conv != NULL); filter = gst_element_factory_make ("capsfilter", "capsfilter"); fail_unless (filter != NULL); g_object_set (filter, "caps", caps, NULL); injector_inject_probability = inject_probability; injector = GST_ELEMENT (g_object_new (test_injector_get_type (), NULL)); srcpad = gst_element_get_pad (injector, "src"); fail_unless (srcpad != NULL); gst_pad_add_buffer_probe (srcpad, G_CALLBACK (probe_cb), &drop_probability); gst_object_unref (srcpad); audiorate = gst_element_factory_make ("audiorate", "audiorate"); fail_unless (audiorate != NULL); sink = gst_element_factory_make ("fakesink", "fakesink"); fail_unless (sink != NULL); g_object_set (sink, "signal-handoffs", TRUE, NULL); g_signal_connect (sink, "handoff", G_CALLBACK (got_buf), &bufs); gst_bin_add_many (GST_BIN (pipe), src, conv, filter, injector, audiorate, sink, NULL); gst_element_link_many (src, conv, filter, injector, audiorate, sink, NULL); fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_PLAYING), GST_STATE_CHANGE_ASYNC); fail_unless_equals_int (gst_element_get_state (pipe, NULL, NULL, -1), GST_STATE_CHANGE_SUCCESS); msg = gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1); fail_unless_equals_string (GST_MESSAGE_TYPE_NAME (msg), "eos"); for (l = bufs; l != NULL; l = l->next) { GstBuffer *buf = GST_BUFFER (l->data); guint num_samples; fail_unless (GST_BUFFER_TIMESTAMP_IS_VALID (buf)); fail_unless (GST_BUFFER_DURATION_IS_VALID (buf)); fail_unless (GST_BUFFER_OFFSET_IS_VALID (buf)); fail_unless (GST_BUFFER_OFFSET_END_IS_VALID (buf)); GST_LOG ("buffer: ts=%" GST_TIME_FORMAT ", end_ts=%" GST_TIME_FORMAT " off=%" G_GINT64_FORMAT ", end_off=%" G_GINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf)); if (GST_CLOCK_TIME_IS_VALID (next_time)) { fail_unless_equals_uint64 (next_time, GST_BUFFER_TIMESTAMP (buf)); } if (next_offset != GST_BUFFER_OFFSET_NONE) { fail_unless_equals_uint64 (next_offset, GST_BUFFER_OFFSET (buf)); } /* check buffer size for sanity */ fail_unless_equals_int (GST_BUFFER_SIZE (buf) % (width / 8), 0); /* check there is actually as much data as there should be */ num_samples = GST_BUFFER_OFFSET_END (buf) - GST_BUFFER_OFFSET (buf); fail_unless_equals_int (GST_BUFFER_SIZE (buf), num_samples * (width / 8)); next_time = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf); next_offset = GST_BUFFER_OFFSET_END (buf); } gst_message_unref (msg); gst_element_set_state (pipe, GST_STATE_NULL); gst_object_unref (pipe); g_list_foreach (bufs, (GFunc) gst_mini_object_unref, NULL); g_list_free (bufs); gst_caps_unref (caps); }
static GstFlowReturn test_injector_chain (GstPad * pad, GstBuffer * buf) { GstFlowReturn ret; GstPad *srcpad; srcpad = gst_element_get_pad (GST_ELEMENT (GST_PAD_PARENT (pad)), "src"); /* since we're increasing timestamp/offsets, push this one first */ GST_LOG (" passing buffer [t=%" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "], offset=%" G_GINT64_FORMAT ", offset_end=%" G_GINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf)); gst_buffer_ref (buf); ret = gst_pad_push (srcpad, buf); if (g_random_double () < injector_inject_probability) { GstBuffer *ibuf; ibuf = gst_buffer_copy (buf); if (GST_BUFFER_OFFSET_IS_VALID (buf) && GST_BUFFER_OFFSET_END_IS_VALID (buf)) { guint64 delta; delta = GST_BUFFER_OFFSET_END (buf) - GST_BUFFER_OFFSET (buf); GST_BUFFER_OFFSET (ibuf) += delta / 4; GST_BUFFER_OFFSET_END (ibuf) += delta / 4; } else { GST_BUFFER_OFFSET (ibuf) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_OFFSET_END (ibuf) = GST_BUFFER_OFFSET_NONE; } if (GST_BUFFER_TIMESTAMP_IS_VALID (buf) && GST_BUFFER_DURATION_IS_VALID (buf)) { GstClockTime delta; delta = GST_BUFFER_DURATION (buf); GST_BUFFER_TIMESTAMP (ibuf) += delta / 4; } else { GST_BUFFER_TIMESTAMP (ibuf) = GST_CLOCK_TIME_NONE; GST_BUFFER_DURATION (ibuf) = GST_CLOCK_TIME_NONE; } if (GST_BUFFER_TIMESTAMP_IS_VALID (ibuf) || GST_BUFFER_OFFSET_IS_VALID (ibuf)) { GST_LOG ("injecting buffer [t=%" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "], offset=%" G_GINT64_FORMAT ", offset_end=%" G_GINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (ibuf)), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (ibuf) + GST_BUFFER_DURATION (ibuf)), GST_BUFFER_OFFSET (ibuf), GST_BUFFER_OFFSET_END (ibuf)); if (gst_pad_push (srcpad, ibuf) != GST_FLOW_OK) { /* ignore return value */ } } else { GST_WARNING ("couldn't inject buffer, no incoming timestamps or offsets"); gst_buffer_unref (ibuf); } } gst_buffer_unref (buf); return ret; }
EXPORT_C #endif GstBuffer * gst_audio_buffer_clip (GstBuffer * buffer, GstSegment * segment, gint rate, gint frame_size) { GstBuffer *ret; GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE; guint64 offset = GST_BUFFER_OFFSET_NONE, offset_end = GST_BUFFER_OFFSET_NONE; guint8 *data; guint size; gboolean change_duration = TRUE, change_offset = TRUE, change_offset_end = TRUE; g_return_val_if_fail (segment->format == GST_FORMAT_TIME || segment->format == GST_FORMAT_DEFAULT, buffer); g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL); if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) /* No timestamp - assume the buffer is completely in the segment */ return buffer; /* Get copies of the buffer metadata to change later. * Calculate the missing values for the calculations, * they won't be changed later though. */ data = GST_BUFFER_DATA (buffer); size = GST_BUFFER_SIZE (buffer); timestamp = GST_BUFFER_TIMESTAMP (buffer); if (GST_BUFFER_DURATION_IS_VALID (buffer)) { duration = GST_BUFFER_DURATION (buffer); } else { change_duration = FALSE; duration = gst_util_uint64_scale (size / frame_size, GST_SECOND, rate); } if (GST_BUFFER_OFFSET_IS_VALID (buffer)) { offset = GST_BUFFER_OFFSET (buffer); } else { change_offset = FALSE; offset = 0; } if (GST_BUFFER_OFFSET_END_IS_VALID (buffer)) { offset_end = GST_BUFFER_OFFSET_END (buffer); } else { change_offset_end = FALSE; offset_end = offset + size / frame_size; } if (segment->format == GST_FORMAT_TIME) { /* Handle clipping for GST_FORMAT_TIME */ gint64 start, stop, cstart, cstop, diff; start = timestamp; stop = timestamp + duration; if (gst_segment_clip (segment, GST_FORMAT_TIME, start, stop, &cstart, &cstop)) { diff = cstart - start; if (diff > 0) { timestamp = cstart; if (change_duration) duration -= diff; diff = gst_util_uint64_scale (diff, rate, GST_SECOND); if (change_offset) offset += diff; data += diff * frame_size; size -= diff * frame_size; } diff = stop - cstop; if (diff > 0) { /* duration is always valid if stop is valid */ duration -= diff; diff = gst_util_uint64_scale (diff, rate, GST_SECOND); if (change_offset_end) offset_end -= diff; size -= diff * frame_size; } } else { gst_buffer_unref (buffer); return NULL; } } else { /* Handle clipping for GST_FORMAT_DEFAULT */ gint64 start, stop, cstart, cstop, diff; g_return_val_if_fail (GST_BUFFER_OFFSET_IS_VALID (buffer), buffer); start = offset; stop = offset_end; if (gst_segment_clip (segment, GST_FORMAT_DEFAULT, start, stop, &cstart, &cstop)) { diff = cstart - start; if (diff > 0) { offset = cstart; timestamp = gst_util_uint64_scale (cstart, GST_SECOND, rate); if (change_duration) duration -= gst_util_uint64_scale (diff, GST_SECOND, rate); data += diff * frame_size; size -= diff * frame_size; } diff = stop - cstop; if (diff > 0) { offset_end = cstop; if (change_duration) duration -= gst_util_uint64_scale (diff, GST_SECOND, rate); size -= diff * frame_size; } } else { gst_buffer_unref (buffer); return NULL; } } /* Get a metadata writable buffer and apply all changes */ ret = gst_buffer_make_metadata_writable (buffer); GST_BUFFER_TIMESTAMP (ret) = timestamp; GST_BUFFER_SIZE (ret) = size; GST_BUFFER_DATA (ret) = data; if (change_duration) GST_BUFFER_DURATION (ret) = duration; if (change_offset) GST_BUFFER_OFFSET (ret) = offset; if (change_offset_end) GST_BUFFER_OFFSET_END (ret) = offset_end; return ret; }
static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf) { GstV4l2Src *v4l2src = GST_V4L2SRC (src); GstV4l2Object *obj = v4l2src->v4l2object; GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL_CAST (obj->pool); GstFlowReturn ret; GstClock *clock; GstClockTime abs_time, base_time, timestamp, duration; GstClockTime delay; GstMessage *qos_msg; do { ret = GST_BASE_SRC_CLASS (parent_class)->alloc (GST_BASE_SRC (src), 0, obj->info.size, buf); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto alloc_failed; ret = gst_v4l2_buffer_pool_process (pool, buf); } while (ret == GST_V4L2_FLOW_CORRUPTED_BUFFER); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto error; timestamp = GST_BUFFER_TIMESTAMP (*buf); duration = obj->duration; /* timestamps, LOCK to get clock and base time. */ /* FIXME: element clock and base_time is rarely changing */ GST_OBJECT_LOCK (v4l2src); if ((clock = GST_ELEMENT_CLOCK (v4l2src))) { /* we have a clock, get base time and ref clock */ base_time = GST_ELEMENT (v4l2src)->base_time; gst_object_ref (clock); } else { /* no clock, can't set timestamps */ base_time = GST_CLOCK_TIME_NONE; } GST_OBJECT_UNLOCK (v4l2src); /* sample pipeline clock */ if (clock) { abs_time = gst_clock_get_time (clock); gst_object_unref (clock); } else { abs_time = GST_CLOCK_TIME_NONE; } retry: if (!v4l2src->has_bad_timestamp && timestamp != GST_CLOCK_TIME_NONE) { struct timespec now; GstClockTime gstnow; /* v4l2 specs say to use the system time although many drivers switched to * the more desirable monotonic time. We first try to use the monotonic time * and see how that goes */ clock_gettime (CLOCK_MONOTONIC, &now); gstnow = GST_TIMESPEC_TO_TIME (now); if (timestamp > gstnow || (gstnow - timestamp) > (10 * GST_SECOND)) { GTimeVal now; /* very large diff, fall back to system time */ g_get_current_time (&now); gstnow = GST_TIMEVAL_TO_TIME (now); } /* Detect buggy drivers here, and stop using their timestamp. Failing any * of these condition would imply a very buggy driver: * - Timestamp in the future * - Timestamp is going backward compare to last seen timestamp * - Timestamp is jumping forward for less then a frame duration * - Delay is bigger then the actual timestamp * */ if (timestamp > gstnow) { GST_WARNING_OBJECT (v4l2src, "Timestamp in the future detected, ignoring driver timestamps"); v4l2src->has_bad_timestamp = TRUE; goto retry; } if (v4l2src->last_timestamp > timestamp) { GST_WARNING_OBJECT (v4l2src, "Timestamp going backward, ignoring driver timestamps"); v4l2src->has_bad_timestamp = TRUE; goto retry; } delay = gstnow - timestamp; if (delay > timestamp) { GST_WARNING_OBJECT (v4l2src, "Timestamp does not correlate with any clock, ignoring driver timestamps"); v4l2src->has_bad_timestamp = TRUE; goto retry; } /* Save last timestamp for sanity checks */ v4l2src->last_timestamp = timestamp; GST_DEBUG_OBJECT (v4l2src, "ts: %" GST_TIME_FORMAT " now %" GST_TIME_FORMAT " delay %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (gstnow), GST_TIME_ARGS (delay)); } else { /* we assume 1 frame latency otherwise */ if (GST_CLOCK_TIME_IS_VALID (duration)) delay = duration; else delay = 0; } /* set buffer metadata */ if (G_LIKELY (abs_time != GST_CLOCK_TIME_NONE)) { /* the time now is the time of the clock minus the base time */ timestamp = abs_time - base_time; /* adjust for delay in the device */ if (timestamp > delay) timestamp -= delay; else timestamp = 0; } else { timestamp = GST_CLOCK_TIME_NONE; } /* activate settings for next frame */ if (GST_CLOCK_TIME_IS_VALID (duration)) { v4l2src->ctrl_time += duration; } else { /* this is not very good (as it should be the next timestamp), * still good enough for linear fades (as long as it is not -1) */ v4l2src->ctrl_time = timestamp; } gst_object_sync_values (GST_OBJECT (src), v4l2src->ctrl_time); GST_INFO_OBJECT (src, "sync to %" GST_TIME_FORMAT " out ts %" GST_TIME_FORMAT, GST_TIME_ARGS (v4l2src->ctrl_time), GST_TIME_ARGS (timestamp)); /* use generated offset values only if there are not already valid ones * set by the v4l2 device */ if (!GST_BUFFER_OFFSET_IS_VALID (*buf) || !GST_BUFFER_OFFSET_END_IS_VALID (*buf)) { GST_BUFFER_OFFSET (*buf) = v4l2src->offset++; GST_BUFFER_OFFSET_END (*buf) = v4l2src->offset; } else { /* adjust raw v4l2 device sequence, will restart at null in case of renegotiation * (streamoff/streamon) */ GST_BUFFER_OFFSET (*buf) += v4l2src->renegotiation_adjust; GST_BUFFER_OFFSET_END (*buf) += v4l2src->renegotiation_adjust; /* check for frame loss with given (from v4l2 device) buffer offset */ if ((v4l2src->offset != 0) && (GST_BUFFER_OFFSET (*buf) != (v4l2src->offset + 1))) { guint64 lost_frame_count = GST_BUFFER_OFFSET (*buf) - v4l2src->offset - 1; GST_WARNING_OBJECT (v4l2src, "lost frames detected: count = %" G_GUINT64_FORMAT " - ts: %" GST_TIME_FORMAT, lost_frame_count, GST_TIME_ARGS (timestamp)); qos_msg = gst_message_new_qos (GST_OBJECT_CAST (v4l2src), TRUE, GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, timestamp, GST_CLOCK_TIME_IS_VALID (duration) ? lost_frame_count * duration : GST_CLOCK_TIME_NONE); gst_element_post_message (GST_ELEMENT_CAST (v4l2src), qos_msg); } v4l2src->offset = GST_BUFFER_OFFSET (*buf); } GST_BUFFER_TIMESTAMP (*buf) = timestamp; GST_BUFFER_DURATION (*buf) = duration; return ret; /* ERROR */ alloc_failed: { if (ret != GST_FLOW_FLUSHING) GST_ELEMENT_ERROR (src, RESOURCE, NO_SPACE_LEFT, ("Failed to allocate a buffer"), (NULL)); return ret; } error: { if (ret == GST_V4L2_FLOW_LAST_BUFFER) { GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Driver returned a buffer with no payload, this most likely " "indicate a bug in the driver."), (NULL)); ret = GST_FLOW_ERROR; } else { GST_DEBUG_OBJECT (src, "error processing buffer %d (%s)", ret, gst_flow_get_name (ret)); } return ret; } }
/** * gst_audio_buffer_clip: * @buffer: (transfer full): The buffer to clip. * @segment: Segment in %GST_FORMAT_TIME or %GST_FORMAT_DEFAULT to which * the buffer should be clipped. * @rate: sample rate. * @bpf: size of one audio frame in bytes. This is the size of one sample * * channels. * * Clip the buffer to the given %GstSegment. * * After calling this function the caller does not own a reference to * @buffer anymore. * * Returns: (transfer full): %NULL if the buffer is completely outside the configured segment, * otherwise the clipped buffer is returned. * * If the buffer has no timestamp, it is assumed to be inside the segment and * is not clipped */ GstBuffer * gst_audio_buffer_clip (GstBuffer * buffer, GstSegment * segment, gint rate, gint bpf) { GstBuffer *ret; GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE; guint64 offset = GST_BUFFER_OFFSET_NONE, offset_end = GST_BUFFER_OFFSET_NONE; gsize trim, size, osize; gboolean change_duration = TRUE, change_offset = TRUE, change_offset_end = TRUE; g_return_val_if_fail (segment->format == GST_FORMAT_TIME || segment->format == GST_FORMAT_DEFAULT, buffer); g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL); if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) /* No timestamp - assume the buffer is completely in the segment */ return buffer; /* Get copies of the buffer metadata to change later. * Calculate the missing values for the calculations, * they won't be changed later though. */ trim = 0; osize = size = gst_buffer_get_size (buffer); /* no data, nothing to clip */ if (!size) return buffer; timestamp = GST_BUFFER_TIMESTAMP (buffer); GST_DEBUG ("timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); if (GST_BUFFER_DURATION_IS_VALID (buffer)) { duration = GST_BUFFER_DURATION (buffer); } else { change_duration = FALSE; duration = gst_util_uint64_scale (size / bpf, GST_SECOND, rate); } if (GST_BUFFER_OFFSET_IS_VALID (buffer)) { offset = GST_BUFFER_OFFSET (buffer); } else { change_offset = FALSE; offset = 0; } if (GST_BUFFER_OFFSET_END_IS_VALID (buffer)) { offset_end = GST_BUFFER_OFFSET_END (buffer); } else { change_offset_end = FALSE; offset_end = offset + size / bpf; } if (segment->format == GST_FORMAT_TIME) { /* Handle clipping for GST_FORMAT_TIME */ guint64 start, stop, cstart, cstop, diff; start = timestamp; stop = timestamp + duration; if (gst_segment_clip (segment, GST_FORMAT_TIME, start, stop, &cstart, &cstop)) { diff = cstart - start; if (diff > 0) { timestamp = cstart; if (change_duration) duration -= diff; diff = gst_util_uint64_scale (diff, rate, GST_SECOND); if (change_offset) offset += diff; trim += diff * bpf; size -= diff * bpf; } diff = stop - cstop; if (diff > 0) { /* duration is always valid if stop is valid */ duration -= diff; diff = gst_util_uint64_scale (diff, rate, GST_SECOND); if (change_offset_end) offset_end -= diff; size -= diff * bpf; } } else { gst_buffer_unref (buffer); return NULL; } } else { /* Handle clipping for GST_FORMAT_DEFAULT */ guint64 start, stop, cstart, cstop, diff; g_return_val_if_fail (GST_BUFFER_OFFSET_IS_VALID (buffer), buffer); start = offset; stop = offset_end; if (gst_segment_clip (segment, GST_FORMAT_DEFAULT, start, stop, &cstart, &cstop)) { diff = cstart - start; if (diff > 0) { offset = cstart; timestamp = gst_util_uint64_scale (cstart, GST_SECOND, rate); if (change_duration) duration -= gst_util_uint64_scale (diff, GST_SECOND, rate); trim += diff * bpf; size -= diff * bpf; } diff = stop - cstop; if (diff > 0) { offset_end = cstop; if (change_duration) duration -= gst_util_uint64_scale (diff, GST_SECOND, rate); size -= diff * bpf; } } else { gst_buffer_unref (buffer); return NULL; } } if (trim == 0 && size == osize) { ret = buffer; if (GST_BUFFER_TIMESTAMP (ret) != timestamp) { ret = gst_buffer_make_writable (ret); GST_BUFFER_TIMESTAMP (ret) = timestamp; } if (GST_BUFFER_DURATION (ret) != duration) { ret = gst_buffer_make_writable (ret); GST_BUFFER_DURATION (ret) = duration; } } else { /* Get a writable buffer and apply all changes */ GST_DEBUG ("trim %" G_GSIZE_FORMAT " size %" G_GSIZE_FORMAT, trim, size); ret = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, trim, size); gst_buffer_unref (buffer); GST_DEBUG ("timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); GST_BUFFER_TIMESTAMP (ret) = timestamp; if (change_duration) GST_BUFFER_DURATION (ret) = duration; if (change_offset) GST_BUFFER_OFFSET (ret) = offset; if (change_offset_end) GST_BUFFER_OFFSET_END (ret) = offset_end; } return ret; }
void FarsightChannel::OnFakeSinkHandoff(GstElement *fakesink, GstBuffer *buffer, GstPad *pad, gpointer user_data) { FarsightChannel* self = (FarsightChannel*)user_data; static GStaticMutex mutex = G_STATIC_MUTEX_INIT; g_static_mutex_lock (&mutex); gst_buffer_ref(buffer); int rate = 0; int channels = 0; int width = 0; GstCaps *caps; GstStructure *structure; caps = gst_buffer_get_caps(buffer); structure = gst_caps_get_structure(caps, 0); gst_structure_get_int(structure, "rate", &rate); gst_structure_get_int(structure, "channels", &channels); gst_structure_get_int(structure, "width", &width); gst_caps_unref(caps); if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_PREROLL)) { LogInfo("Drop fakesink buffer: Preroll audio data packet."); gst_buffer_unref(buffer); g_static_mutex_unlock (&mutex); return; } if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_GAP)) { LogInfo("Drop fakesink buffer: Caps audio data packet."); gst_buffer_unref(buffer); g_static_mutex_unlock (&mutex); return; } if (GST_BUFFER_DURATION(buffer) == 0) { LogInfo("Drop fakesink buffer: Got audio data packet with 0 duration"); gst_buffer_unref(buffer); g_static_mutex_unlock (&mutex); return; } if (GST_BUFFER_IS_DISCONT(buffer)) { LogInfo("Drop fakesink buffer: Got disconnect audio data packet."); gst_buffer_unref(buffer); g_static_mutex_unlock (&mutex); return; } if (GST_BUFFER_OFFSET_IS_VALID(buffer)) { guint64 offset = GST_BUFFER_OFFSET (buffer); } if (GST_BUFFER_OFFSET_END_IS_VALID(buffer)) { guint64 offset = GST_BUFFER_OFFSET_END(buffer); } u8* data = GST_BUFFER_DATA(buffer); u32 size = GST_BUFFER_SIZE(buffer); self->HandleAudioData(data, size, rate, width, channels); gst_buffer_unref(buffer); g_static_mutex_unlock (&mutex); }
GstPadProbeReturn GstEnginePipeline::HandoffCallback(GstPad*, GstPadProbeInfo* info, gpointer self) { GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self); GstBuffer* buf = gst_pad_probe_info_get_buffer(info); QList<BufferConsumer*> consumers; { QMutexLocker l(&instance->buffer_consumers_mutex_); consumers = instance->buffer_consumers_; } for (BufferConsumer* consumer : consumers) { gst_buffer_ref(buf); consumer->ConsumeBuffer(buf, instance->id()); } // Calculate the end time of this buffer so we can stop playback if it's // after the end time of this song. if (instance->end_offset_nanosec_ > 0) { quint64 start_time = GST_BUFFER_TIMESTAMP(buf) - instance->segment_start_; quint64 duration = GST_BUFFER_DURATION(buf); quint64 end_time = start_time + duration; if (end_time > instance->end_offset_nanosec_) { if (instance->has_next_valid_url()) { if (instance->next_url_ == instance->url_ && instance->next_beginning_offset_nanosec_ == instance->end_offset_nanosec_) { // The "next" song is actually the next segment of this file - so // cheat and keep on playing, but just tell the Engine we've moved on. instance->end_offset_nanosec_ = instance->next_end_offset_nanosec_; instance->next_url_ = QUrl(); instance->next_beginning_offset_nanosec_ = 0; instance->next_end_offset_nanosec_ = 0; // GstEngine will try to seek to the start of the new section, but // we're already there so ignore it. instance->ignore_next_seek_ = true; emit instance->EndOfStreamReached(instance->id(), true); } else { // We have a next song but we can't cheat, so move to it normally. instance->TransitionToNext(); } } else { // There's no next song emit instance->EndOfStreamReached(instance->id(), false); } } } if (instance->emit_track_ended_on_time_discontinuity_) { if (GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT) || GST_BUFFER_OFFSET(buf) < instance->last_buffer_offset_ || !GST_BUFFER_OFFSET_IS_VALID(buf)) { qLog(Debug) << "Buffer discontinuity - emitting EOS"; instance->emit_track_ended_on_time_discontinuity_ = false; emit instance->EndOfStreamReached(instance->id(), true); } } instance->last_buffer_offset_ = GST_BUFFER_OFFSET(buf); return GST_PAD_PROBE_OK; }
static GstFlowReturn gst_audio_fx_base_fir_filter_transform (GstBaseTransform * base, GstBuffer * inbuf, GstBuffer * outbuf) { GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base); GstClockTime timestamp; gint channels = GST_AUDIO_FILTER (self)->format.channels; gint rate = GST_AUDIO_FILTER (self)->format.rate; gint input_samples = GST_BUFFER_SIZE (outbuf) / (GST_AUDIO_FILTER (self)->format.width / 8); gint output_samples = input_samples; gint diff = 0; timestamp = GST_BUFFER_TIMESTAMP (outbuf); if (!GST_CLOCK_TIME_IS_VALID (timestamp)) { GST_ERROR_OBJECT (self, "Invalid timestamp"); return GST_FLOW_ERROR; } gst_object_sync_values (G_OBJECT (self), timestamp); g_return_val_if_fail (self->kernel != NULL, GST_FLOW_ERROR); g_return_val_if_fail (channels != 0, GST_FLOW_ERROR); if (!self->residue) self->residue = g_new0 (gdouble, self->kernel_length * channels); /* Reset the residue if already existing on discont buffers */ if (GST_BUFFER_IS_DISCONT (inbuf) || (GST_CLOCK_TIME_IS_VALID (self->next_ts) && timestamp - gst_util_uint64_scale (MIN (self->latency, self->residue_length / channels), GST_SECOND, rate) - self->next_ts > 5 * GST_MSECOND)) { GST_DEBUG_OBJECT (self, "Discontinuity detected - flushing"); if (GST_CLOCK_TIME_IS_VALID (self->next_ts)) gst_audio_fx_base_fir_filter_push_residue (self); self->residue_length = 0; self->next_ts = timestamp; self->next_off = GST_BUFFER_OFFSET (inbuf); } else if (!GST_CLOCK_TIME_IS_VALID (self->next_ts)) { self->next_ts = timestamp; self->next_off = GST_BUFFER_OFFSET (inbuf); } /* Calculate the number of samples we can push out now without outputting * latency zeros in the beginning */ diff = self->latency * channels - self->residue_length; if (diff > 0) output_samples -= diff; self->process (self, GST_BUFFER_DATA (inbuf), GST_BUFFER_DATA (outbuf), input_samples); if (output_samples <= 0) { return GST_BASE_TRANSFORM_FLOW_DROPPED; } GST_BUFFER_TIMESTAMP (outbuf) = self->next_ts; GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale (output_samples / channels, GST_SECOND, rate); GST_BUFFER_OFFSET (outbuf) = self->next_off; if (GST_BUFFER_OFFSET_IS_VALID (outbuf)) GST_BUFFER_OFFSET_END (outbuf) = self->next_off + output_samples / channels; else GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE; if (output_samples < input_samples) { GST_BUFFER_DATA (outbuf) += diff * (GST_AUDIO_FILTER (self)->format.width / 8); GST_BUFFER_SIZE (outbuf) -= diff * (GST_AUDIO_FILTER (self)->format.width / 8); } self->next_ts += GST_BUFFER_DURATION (outbuf); self->next_off = GST_BUFFER_OFFSET_END (outbuf); GST_DEBUG_OBJECT (self, "Pushing buffer of size %d with timestamp: %" GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %lld," " offset_end: %lld, nsamples: %d", GST_BUFFER_SIZE (outbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf), output_samples / channels); return GST_FLOW_OK; }
bool nvxio::GStreamerBaseRenderImpl::flush() { if (!pipeline) return false; glfwMakeContextCurrent(window_); if (glfwWindowShouldClose(window_)) return false; gl_->PixelStorei(GL_PACK_ALIGNMENT, 1); gl_->PixelStorei(GL_PACK_ROW_LENGTH, wndWidth_); { GstClockTime duration = GST_SECOND / (double)GSTREAMER_DEFAULT_FPS; GstClockTime timestamp = num_frames * duration; #if GST_VERSION_MAJOR == 0 GstBuffer * buffer = gst_buffer_try_new_and_alloc(wndHeight_ * wndWidth_ * 4); if (!buffer) { NVXIO_PRINT("Cannot create GStreamer buffer"); FinalizeGStreamerPipeline(); return false; } gl_->ReadPixels(0, 0, wndWidth_, wndHeight_, GL_RGBA, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buffer)); GST_BUFFER_TIMESTAMP(buffer) = timestamp; if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer)) NVXIO_PRINT("Failed to setup timestamp"); #else GstBuffer * buffer = gst_buffer_new_allocate(NULL, wndHeight_ * wndWidth_ * 4, NULL); GstMapInfo info; gst_buffer_map(buffer, &info, GST_MAP_READ); gl_->ReadPixels(0, 0, wndWidth_, wndHeight_, GL_RGBA, GL_UNSIGNED_BYTE, info.data); gst_buffer_unmap(buffer, &info); GST_BUFFER_PTS(buffer) = timestamp; if (!GST_BUFFER_PTS_IS_VALID(buffer)) NVXIO_PRINT("Failed to setup PTS"); GST_BUFFER_DTS(buffer) = timestamp; if (!GST_BUFFER_DTS_IS_VALID(buffer)) NVXIO_PRINT("Failed to setup DTS"); #endif GST_BUFFER_DURATION(buffer) = duration; if (!GST_BUFFER_DURATION_IS_VALID(buffer)) NVXIO_PRINT("Failed to setup duration"); GST_BUFFER_OFFSET(buffer) = num_frames++; if (!GST_BUFFER_OFFSET_IS_VALID(buffer)) NVXIO_PRINT("Failed to setup offset"); if (gst_app_src_push_buffer(appsrc, buffer) != GST_FLOW_OK) { NVXIO_PRINT("Error pushing buffer to GStreamer pipeline"); FinalizeGStreamerPipeline(); return false; } } // reset state gl_->PixelStorei(GL_PACK_ALIGNMENT, 4); gl_->PixelStorei(GL_PACK_ROW_LENGTH, 0); glfwSwapBuffers(window_); clearGlBuffer(); return true; }