static GstBuffer * mpegpsmux_queue_buffer_for_stream (MpegPsMux * mux, MpegPsPadData * ps_data) { GstCollectData *c_data = (GstCollectData *) ps_data; GstBuffer *buf; g_assert (ps_data->queued.buf == NULL); buf = gst_collect_pads_peek (mux->collect, c_data); if (buf == NULL) return NULL; ps_data->queued.buf = buf; /* do any raw -> byte-stream format conversions (e.g. for H.264, AAC) */ if (ps_data->prepare_func) { buf = ps_data->prepare_func (buf, ps_data, mux); if (buf) { /* Take the prepared buffer instead */ gst_buffer_unref (ps_data->queued.buf); ps_data->queued.buf = buf; } else { /* If data preparation returned NULL, use unprepared one */ buf = ps_data->queued.buf; } } ps_data->queued.pts = GST_BUFFER_PTS (buf); if (GST_CLOCK_TIME_IS_VALID (ps_data->queued.pts)) { ps_data->queued.pts = gst_segment_to_running_time (&c_data->segment, GST_FORMAT_TIME, ps_data->queued.pts); } ps_data->queued.dts = GST_BUFFER_DTS (buf); if (GST_CLOCK_TIME_IS_VALID (ps_data->queued.dts)) { ps_data->queued.dts = gst_segment_to_running_time (&c_data->segment, GST_FORMAT_TIME, ps_data->queued.dts); } if (GST_BUFFER_PTS_IS_VALID (buf) && GST_BUFFER_DTS_IS_VALID (buf)) { ps_data->queued.ts = MIN (ps_data->queued.dts, ps_data->queued.pts); } else if (GST_BUFFER_PTS_IS_VALID (buf) && !GST_BUFFER_DTS_IS_VALID (buf)) { ps_data->queued.ts = ps_data->queued.pts; } else if (GST_BUFFER_DTS_IS_VALID (buf) && !GST_BUFFER_PTS_IS_VALID (buf)) { GST_WARNING_OBJECT (c_data->pad, "got DTS without PTS"); ps_data->queued.ts = ps_data->queued.dts; } else { ps_data->queued.ts = GST_CLOCK_TIME_NONE; } GST_DEBUG_OBJECT (mux, "Queued buffer with ts %" GST_TIME_FORMAT ": " "uncorrected pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT ", " "buffer pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " for PID 0x%04x", GST_TIME_ARGS (ps_data->queued.ts), GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_TIME_ARGS (GST_BUFFER_DTS (buf)), GST_TIME_ARGS (ps_data->queued.pts), GST_TIME_ARGS (ps_data->queued.dts), ps_data->stream_id); return buf; }
static GstFlowReturn splitmux_part_pad_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstSplitMuxPartPad *part_pad = SPLITMUX_PART_PAD_CAST (pad); GstSplitMuxPartReader *reader = part_pad->reader; GstDataQueueItem *item; GstClockTimeDiff offset; GST_LOG_OBJECT (reader, "Pad %" GST_PTR_FORMAT " %" GST_PTR_FORMAT, pad, buf); SPLITMUX_PART_LOCK (reader); if (reader->prep_state == PART_STATE_PREPARING_COLLECT_STREAMS || reader->prep_state == PART_STATE_PREPARING_MEASURE_STREAMS) { handle_buffer_measuring (reader, part_pad, buf); gst_buffer_unref (buf); SPLITMUX_PART_UNLOCK (reader); return GST_FLOW_OK; } if (!block_until_can_push (reader)) { /* Flushing */ SPLITMUX_PART_UNLOCK (reader); gst_buffer_unref (buf); return GST_FLOW_FLUSHING; } /* Adjust buffer timestamps */ offset = reader->start_offset + part_pad->segment.base; offset -= part_pad->initial_ts_offset; if (GST_BUFFER_PTS_IS_VALID (buf)) GST_BUFFER_PTS (buf) += offset; if (GST_BUFFER_DTS_IS_VALID (buf)) GST_BUFFER_DTS (buf) += offset; /* We are active, and one queue is empty, place this buffer in * the dataqueue */ GST_LOG_OBJECT (reader, "Enqueueing buffer %" GST_PTR_FORMAT, buf); item = g_slice_new (GstDataQueueItem); item->destroy = (GDestroyNotify) splitmux_part_free_queue_item; item->object = GST_MINI_OBJECT (buf); item->size = gst_buffer_get_size (buf); item->duration = GST_BUFFER_DURATION (buf); if (item->duration == GST_CLOCK_TIME_NONE) item->duration = 0; item->visible = TRUE; gst_object_ref (part_pad); SPLITMUX_PART_UNLOCK (reader); if (!gst_data_queue_push (part_pad->queue, item)) { splitmux_part_free_queue_item (item); gst_object_unref (part_pad); return GST_FLOW_FLUSHING; } gst_object_unref (part_pad); return GST_FLOW_OK; }
static gboolean process_list_item (GstBuffer ** buffer, guint idx, gpointer user_data) { struct BufferListData *bd = user_data; GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; *buffer = gst_buffer_make_writable (*buffer); gst_rtp_buffer_map (*buffer, GST_MAP_READWRITE, &rtpbuffer); bd->drop = !process_buffer_locked (bd->rtp_mux, bd->padpriv, &rtpbuffer); gst_rtp_buffer_unmap (&rtpbuffer); if (bd->drop) return FALSE; if (GST_BUFFER_DURATION_IS_VALID (*buffer) && GST_BUFFER_PTS_IS_VALID (*buffer)) bd->rtp_mux->last_stop = GST_BUFFER_PTS (*buffer) + GST_BUFFER_DURATION (*buffer); else bd->rtp_mux->last_stop = GST_CLOCK_TIME_NONE; return TRUE; }
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 void test_position (InsanityTest * test, GstBuffer * buf) { GstQuery *query; GstClockTimeDiff diff; if (GST_BUFFER_PTS_IS_VALID (buf) == FALSE) return; if (GST_CLOCK_TIME_IS_VALID (glob_first_pos_point) == FALSE) { glob_first_pos_point = gst_segment_to_stream_time (&glob_last_segment, glob_last_segment.format, GST_BUFFER_PTS (buf)); } glob_expected_pos = gst_segment_to_stream_time (&glob_last_segment, glob_last_segment.format, GST_BUFFER_PTS (buf)); diff = ABS (GST_CLOCK_DIFF (glob_expected_pos, glob_first_pos_point)); if (diff < glob_playback_duration * GST_SECOND) return; query = gst_query_new_position (GST_FORMAT_TIME); if (gst_element_query (glob_pipeline, query)) { gint64 pos; GstFormat fmt; GstClockTimeDiff diff; gst_query_parse_position (query, &fmt, &pos); diff = ABS (GST_CLOCK_DIFF (glob_expected_pos, pos)); if (diff <= POSITION_THRESHOLD) { insanity_test_validate_checklist_item (test, "position-detection", TRUE, NULL); } else { gchar *validate_msg = g_strdup_printf ("Found position: %" GST_TIME_FORMAT " expected: %" GST_TIME_FORMAT, GST_TIME_ARGS (pos), GST_TIME_ARGS (glob_expected_pos)); insanity_test_validate_checklist_item (test, "position-detection", FALSE, validate_msg); g_free (validate_msg); } } else { LOG (test, "%s Does not handle position queries (position-detection \"SKIP\")", gst_element_factory_get_metadata (gst_element_get_factory (glob_demuxer), GST_ELEMENT_METADATA_LONGNAME)); } next_test (test); }
static void handle_buffer_measuring (GstSplitMuxPartReader * reader, GstSplitMuxPartPad * part_pad, GstBuffer * buf) { GstClockTime ts = GST_CLOCK_TIME_NONE; GstClockTimeDiff offset; if (reader->prep_state == PART_STATE_PREPARING_COLLECT_STREAMS && !part_pad->seen_buffer) { /* If this is the first buffer on the pad in the collect_streams state, * then calculate inital offset based on running time of this segment */ part_pad->initial_ts_offset = part_pad->orig_segment.start + part_pad->orig_segment.base - part_pad->orig_segment.time; GST_DEBUG_OBJECT (reader, "Initial TS offset for pad %" GST_PTR_FORMAT " now %" GST_TIME_FORMAT, part_pad, GST_TIME_ARGS (part_pad->initial_ts_offset)); } part_pad->seen_buffer = TRUE; /* Adjust buffer timestamps */ offset = reader->start_offset + part_pad->segment.base; offset -= part_pad->initial_ts_offset; /* Update the stored max duration on the pad, * always preferring making DTS contiguous * where possible */ if (GST_BUFFER_DTS_IS_VALID (buf)) ts = GST_BUFFER_DTS (buf) + offset; else if (GST_BUFFER_PTS_IS_VALID (buf)) ts = GST_BUFFER_PTS (buf) + offset; GST_DEBUG_OBJECT (reader, "Pad %" GST_PTR_FORMAT " incoming PTS %" GST_TIME_FORMAT " DTS %" GST_TIME_FORMAT " offset by %" GST_STIME_FORMAT " to %" GST_TIME_FORMAT, part_pad, GST_TIME_ARGS (GST_BUFFER_DTS (buf)), GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_STIME_ARGS (offset), GST_TIME_ARGS (ts)); if (GST_CLOCK_TIME_IS_VALID (ts)) { if (GST_BUFFER_DURATION_IS_VALID (buf)) ts += GST_BUFFER_DURATION (buf); if (GST_CLOCK_TIME_IS_VALID (ts) && ts > part_pad->max_ts) { part_pad->max_ts = ts; GST_LOG_OBJECT (reader, "pad %" GST_PTR_FORMAT " max TS now %" GST_TIME_FORMAT, part_pad, GST_TIME_ARGS (part_pad->max_ts)); } } /* Is it time to move to measuring state yet? */ check_if_pads_collected (reader); }
static CMSampleBufferRef cm_sample_buffer_from_gst_buffer (GstVtdec * vtdec, GstBuffer * buf) { OSStatus status; CMBlockBufferRef bbuf = NULL; CMSampleBufferRef sbuf = NULL; CMSampleTimingInfo sample_timing; CMSampleTimingInfo time_array[1]; g_return_val_if_fail (vtdec->format_description, NULL); /* create a block buffer */ bbuf = cm_block_buffer_from_gst_buffer (buf, GST_MAP_READ); if (bbuf == NULL) { GST_ELEMENT_ERROR (vtdec, RESOURCE, FAILED, (NULL), ("failed creating CMBlockBuffer")); return NULL; } /* create a sample buffer */ if (GST_BUFFER_DURATION_IS_VALID (buf)) sample_timing.duration = CMTimeMake (GST_BUFFER_DURATION (buf), GST_SECOND); else sample_timing.duration = kCMTimeInvalid; if (GST_BUFFER_PTS_IS_VALID (buf)) sample_timing.presentationTimeStamp = CMTimeMake (GST_BUFFER_PTS (buf), GST_SECOND); else sample_timing.presentationTimeStamp = kCMTimeInvalid; if (GST_BUFFER_DTS_IS_VALID (buf)) sample_timing.decodeTimeStamp = CMTimeMake (GST_BUFFER_DTS (buf), GST_SECOND); else sample_timing.decodeTimeStamp = kCMTimeInvalid; time_array[0] = sample_timing; status = CMSampleBufferCreate (NULL, bbuf, TRUE, 0, 0, vtdec->format_description, 1, 1, time_array, 0, NULL, &sbuf); CFRelease (bbuf); if (status != noErr) { GST_ELEMENT_ERROR (vtdec, RESOURCE, FAILED, (NULL), ("CMSampleBufferCreate returned %d", (int) status)); return NULL; } return sbuf; }
static GstPadProbeReturn handle_output (GstPad * pad, GstPadProbeInfo * info, StreamInfo * si) { GstClockTime start, end; GstBuffer *buf; GST_LOG_OBJECT (pad, "Fired probe type 0x%x", info->type); if (info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST) { g_warning ("Buffer list handling not implemented"); return GST_PAD_PROBE_DROP; } if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) { GstEvent *event = gst_pad_probe_info_get_event (info); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEGMENT: gst_event_copy_segment (event, &si->seg); break; case GST_EVENT_EOS: dump_times (si); break; default: break; } return GST_PAD_PROBE_PASS; } buf = gst_pad_probe_info_get_buffer (info); if (!GST_BUFFER_PTS_IS_VALID (buf)) goto done; end = start = GST_BUFFER_PTS (buf); if (GST_BUFFER_DURATION_IS_VALID (buf)) end += GST_BUFFER_DURATION (buf); gst_segment_clip (&si->seg, GST_FORMAT_TIME, start, end, &start, &end); start = gst_segment_to_stream_time (&si->seg, GST_FORMAT_TIME, start); end = gst_segment_to_stream_time (&si->seg, GST_FORMAT_TIME, end); GST_DEBUG_OBJECT (pad, "new buffer %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end)); /* Now extend measured time range to include new times */ extend_times (si, start, end); done: return GST_PAD_PROBE_PASS; }
static gboolean kms_av_muxer_check_pts (GstBuffer ** buffer, GstClockTime * lastPts) { if (G_UNLIKELY (!GST_BUFFER_PTS_IS_VALID ((*buffer)))) { return TRUE; } else if (G_LIKELY (*lastPts <= (*buffer)->pts)) { *lastPts = (*buffer)->pts; return TRUE; } else { GST_WARNING ("Buffer pts %" G_GUINT64_FORMAT " is older than last pts %" G_GUINT64_FORMAT, GST_BUFFER_PTS (*buffer), *lastPts); return FALSE; } }
static gboolean gst_rtp_dtmf_mux_accept_buffer_locked (GstRTPMux * rtp_mux, GstRTPMuxPadPrivate * padpriv, GstRTPBuffer * rtpbuffer) { GstRTPDTMFMux *mux = GST_RTP_DTMF_MUX (rtp_mux); GstClockTime running_ts; running_ts = GST_BUFFER_PTS (rtpbuffer->buffer); if (GST_CLOCK_TIME_IS_VALID (running_ts)) { if (padpriv && padpriv->segment.format == GST_FORMAT_TIME) running_ts = gst_segment_to_running_time (&padpriv->segment, GST_FORMAT_TIME, GST_BUFFER_PTS (rtpbuffer->buffer)); if (padpriv && padpriv->priority) { if (GST_BUFFER_PTS_IS_VALID (rtpbuffer->buffer)) { if (GST_CLOCK_TIME_IS_VALID (mux->last_priority_end)) mux->last_priority_end = MAX (running_ts + GST_BUFFER_DURATION (rtpbuffer->buffer), mux->last_priority_end); else mux->last_priority_end = running_ts + GST_BUFFER_DURATION (rtpbuffer->buffer); GST_LOG_OBJECT (mux, "Got buffer %p on priority pad, " " blocking regular pads until %" GST_TIME_FORMAT, rtpbuffer->buffer, GST_TIME_ARGS (mux->last_priority_end)); } else { GST_WARNING_OBJECT (mux, "Buffer %p has an invalid duration," " not blocking other pad", rtpbuffer->buffer); } } else { if (GST_CLOCK_TIME_IS_VALID (mux->last_priority_end) && running_ts < mux->last_priority_end) { GST_LOG_OBJECT (mux, "Dropping buffer %p because running time" " %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT, rtpbuffer->buffer, GST_TIME_ARGS (running_ts), GST_TIME_ARGS (mux->last_priority_end)); return FALSE; } } } else { GST_LOG_OBJECT (mux, "Buffer %p has an invalid timestamp," " letting through", rtpbuffer->buffer); } return TRUE; }
/* Called with the object lock for both the element and pad held, * as well as the aagg lock */ static gboolean gst_audio_aggregator_fill_buffer (GstAudioAggregator * aagg, GstAudioAggregatorPad * pad, GstBuffer * inbuf) { GstClockTime start_time, end_time; gboolean discont = FALSE; guint64 start_offset, end_offset; gint rate, bpf; GstAggregator *agg = GST_AGGREGATOR (aagg); GstAggregatorPad *aggpad = GST_AGGREGATOR_PAD (pad); g_assert (pad->priv->buffer == NULL); rate = GST_AUDIO_INFO_RATE (&pad->info); bpf = GST_AUDIO_INFO_BPF (&pad->info); pad->priv->position = 0; pad->priv->size = gst_buffer_get_size (inbuf) / bpf; if (!GST_BUFFER_PTS_IS_VALID (inbuf)) { if (pad->priv->output_offset == -1) pad->priv->output_offset = aagg->priv->offset; if (pad->priv->next_offset == -1) pad->priv->next_offset = pad->priv->size; else pad->priv->next_offset += pad->priv->size; goto done; } start_time = GST_BUFFER_PTS (inbuf); end_time = start_time + gst_util_uint64_scale_ceil (pad->priv->size, GST_SECOND, rate); /* Clipping should've ensured this */ g_assert (start_time >= aggpad->segment.start); start_offset = gst_util_uint64_scale (start_time - aggpad->segment.start, rate, GST_SECOND); end_offset = start_offset + pad->priv->size; if (GST_BUFFER_IS_DISCONT (inbuf) || GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_RESYNC) || pad->priv->new_segment || pad->priv->next_offset == -1) { discont = TRUE; pad->priv->new_segment = FALSE; } else { guint64 diff, max_sample_diff; /* Check discont, based on audiobasesink */ if (start_offset <= pad->priv->next_offset) diff = pad->priv->next_offset - start_offset; else diff = start_offset - pad->priv->next_offset; max_sample_diff = gst_util_uint64_scale_int (aagg->priv->alignment_threshold, rate, GST_SECOND); /* Discont! */ if (G_UNLIKELY (diff >= max_sample_diff)) { if (aagg->priv->discont_wait > 0) { if (pad->priv->discont_time == GST_CLOCK_TIME_NONE) { pad->priv->discont_time = start_time; } else if (start_time - pad->priv->discont_time >= aagg->priv->discont_wait) { discont = TRUE; pad->priv->discont_time = GST_CLOCK_TIME_NONE; } } else { discont = TRUE; } } else if (G_UNLIKELY (pad->priv->discont_time != GST_CLOCK_TIME_NONE)) { /* we have had a discont, but are now back on track! */ pad->priv->discont_time = GST_CLOCK_TIME_NONE; } } if (discont) { /* Have discont, need resync */ if (pad->priv->next_offset != -1) GST_INFO_OBJECT (pad, "Have discont. Expected %" G_GUINT64_FORMAT ", got %" G_GUINT64_FORMAT, pad->priv->next_offset, start_offset); pad->priv->output_offset = -1; pad->priv->next_offset = end_offset; } else { pad->priv->next_offset += pad->priv->size; } if (pad->priv->output_offset == -1) { GstClockTime start_running_time; GstClockTime end_running_time; guint64 start_output_offset; guint64 end_output_offset; start_running_time = gst_segment_to_running_time (&aggpad->segment, GST_FORMAT_TIME, start_time); end_running_time = gst_segment_to_running_time (&aggpad->segment, GST_FORMAT_TIME, end_time); /* Convert to position in the output segment */ start_output_offset = gst_segment_to_position (&agg->segment, GST_FORMAT_TIME, start_running_time); if (start_output_offset != -1) start_output_offset = gst_util_uint64_scale (start_output_offset - agg->segment.start, rate, GST_SECOND); end_output_offset = gst_segment_to_position (&agg->segment, GST_FORMAT_TIME, end_running_time); if (end_output_offset != -1) end_output_offset = gst_util_uint64_scale (end_output_offset - agg->segment.start, rate, GST_SECOND); if (start_output_offset == -1 && end_output_offset == -1) { /* Outside output segment, drop */ gst_buffer_unref (inbuf); pad->priv->buffer = NULL; pad->priv->position = 0; pad->priv->size = 0; pad->priv->output_offset = -1; GST_DEBUG_OBJECT (pad, "Buffer outside output segment"); return FALSE; } /* Calculate end_output_offset if it was outside the output segment */ if (end_output_offset == -1) end_output_offset = start_output_offset + pad->priv->size; if (end_output_offset < aagg->priv->offset) { /* Before output segment, drop */ gst_buffer_unref (inbuf); pad->priv->buffer = NULL; pad->priv->position = 0; pad->priv->size = 0; pad->priv->output_offset = -1; GST_DEBUG_OBJECT (pad, "Buffer before segment or current position: %" G_GUINT64_FORMAT " < %" G_GINT64_FORMAT, end_output_offset, aagg->priv->offset); return FALSE; } if (start_output_offset == -1 || start_output_offset < aagg->priv->offset) { guint diff; if (start_output_offset == -1 && end_output_offset < pad->priv->size) { diff = pad->priv->size - end_output_offset + aagg->priv->offset; } else if (start_output_offset == -1) { start_output_offset = end_output_offset - pad->priv->size; if (start_output_offset < aagg->priv->offset) diff = aagg->priv->offset - start_output_offset; else diff = 0; } else { diff = aagg->priv->offset - start_output_offset; } pad->priv->position += diff; if (pad->priv->position >= pad->priv->size) { /* Empty buffer, drop */ gst_buffer_unref (inbuf); pad->priv->buffer = NULL; pad->priv->position = 0; pad->priv->size = 0; pad->priv->output_offset = -1; GST_DEBUG_OBJECT (pad, "Buffer before segment or current position: %" G_GUINT64_FORMAT " < %" G_GINT64_FORMAT, end_output_offset, aagg->priv->offset); return FALSE; } } if (start_output_offset == -1 || start_output_offset < aagg->priv->offset) pad->priv->output_offset = aagg->priv->offset; else pad->priv->output_offset = start_output_offset; GST_DEBUG_OBJECT (pad, "Buffer resynced: Pad offset %" G_GUINT64_FORMAT ", current audio aggregator offset %" G_GINT64_FORMAT, pad->priv->output_offset, aagg->priv->offset); } done: GST_LOG_OBJECT (pad, "Queued new buffer at offset %" G_GUINT64_FORMAT, pad->priv->output_offset); pad->priv->buffer = inbuf; return TRUE; }
static GstFlowReturn recv_sample (GstAppSink * appsink, gpointer user_data) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (GST_OBJECT_PARENT (appsink)); GstAppSrc *appsrc = GST_APP_SRC (user_data); KmsUriEndpointState state; GstFlowReturn ret; GstSample *sample; GstSegment *segment; GstBuffer *buffer; BaseTimeType *base_time; GstClockTime offset; g_signal_emit_by_name (appsink, "pull-sample", &sample); if (sample == NULL) return GST_FLOW_OK; buffer = gst_sample_get_buffer (sample); if (buffer == NULL) { ret = GST_FLOW_OK; goto end; } segment = gst_sample_get_segment (sample); g_object_get (G_OBJECT (self), "state", &state, NULL); if (state != KMS_URI_ENDPOINT_STATE_START) { GST_WARNING ("Dropping buffer received in invalid state %" GST_PTR_FORMAT, buffer); // TODO: Add a flag to discard buffers until keyframe ret = GST_FLOW_OK; goto end; } gst_buffer_ref (buffer); buffer = gst_buffer_make_writable (buffer); if (GST_BUFFER_PTS_IS_VALID (buffer)) buffer->pts = gst_segment_to_running_time (segment, GST_FORMAT_TIME, buffer->pts); if (GST_BUFFER_DTS_IS_VALID (buffer)) buffer->dts = gst_segment_to_running_time (segment, GST_FORMAT_TIME, buffer->dts); BASE_TIME_LOCK (self); base_time = g_object_get_data (G_OBJECT (self), BASE_TIME_DATA); if (base_time == NULL) { base_time = g_slice_new0 (BaseTimeType); base_time->pts = buffer->pts; base_time->dts = buffer->dts; GST_DEBUG_OBJECT (appsrc, "Setting pts base time to: %" G_GUINT64_FORMAT, base_time->pts); g_object_set_data_full (G_OBJECT (self), BASE_TIME_DATA, base_time, release_base_time_type); } if (!GST_CLOCK_TIME_IS_VALID (base_time->pts) && GST_BUFFER_PTS_IS_VALID (buffer)) { base_time->pts = buffer->pts; GST_DEBUG_OBJECT (appsrc, "Setting pts base time to: %" G_GUINT64_FORMAT, base_time->pts); base_time->dts = buffer->dts; } if (GST_CLOCK_TIME_IS_VALID (base_time->pts)) { if (GST_BUFFER_PTS_IS_VALID (buffer)) { offset = base_time->pts + self->priv->paused_time; if (buffer->pts > offset) { buffer->pts -= offset; } else { buffer->pts = 0; } } } if (GST_CLOCK_TIME_IS_VALID (base_time->dts)) { if (GST_BUFFER_DTS_IS_VALID (buffer)) { offset = base_time->dts + self->priv->paused_time; if (buffer->dts > offset) { buffer->dts -= offset; } else { buffer->dts = 0; } } } BASE_TIME_UNLOCK (GST_OBJECT_PARENT (appsink)); GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_LIVE); if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_HEADER)) GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); ret = gst_app_src_push_buffer (appsrc, buffer); if (ret != GST_FLOW_OK) { /* something wrong */ GST_ERROR ("Could not send buffer to appsrc %s. Cause: %s", GST_ELEMENT_NAME (appsrc), gst_flow_get_name (ret)); } end: if (sample != NULL) { gst_sample_unref (sample); } return ret; }
static GstFlowReturn new_sample_post_handler (GstElement * appsink, gpointer user_data) { GstElement *appsrc = GST_ELEMENT (user_data); GstSample *sample = NULL; GstBuffer *buffer; GstFlowReturn ret; GstClockTime *base_time; g_signal_emit_by_name (appsink, "pull-sample", &sample); if (sample == NULL) return GST_FLOW_OK; buffer = gst_sample_get_buffer (sample); if (buffer == NULL) { ret = GST_FLOW_OK; goto end; } gst_buffer_ref (buffer); buffer = gst_buffer_make_writable (buffer); BASE_TIME_LOCK (GST_OBJECT_PARENT (appsrc)); base_time = g_object_get_qdata (G_OBJECT (GST_OBJECT_PARENT (appsrc)), base_time_data_quark ()); if (base_time == NULL) { GstClock *clock; clock = gst_element_get_clock (appsrc); base_time = g_slice_new0 (GstClockTime); g_object_set_qdata_full (G_OBJECT (GST_OBJECT_PARENT (appsrc)), base_time_data_quark (), base_time, release_gst_clock); *base_time = gst_clock_get_time (clock) - gst_element_get_base_time (appsrc); g_object_unref (clock); GST_DEBUG ("Setting base time to: %" G_GUINT64_FORMAT, *base_time); } if (GST_BUFFER_PTS_IS_VALID (buffer)) buffer->pts += *base_time; if (GST_BUFFER_DTS_IS_VALID (buffer)) buffer->dts += *base_time; BASE_TIME_UNLOCK (GST_OBJECT_PARENT (appsrc)); /* Pass the buffer through appsrc element which is */ /* placed in a different pipeline */ g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret); gst_buffer_unref (buffer); if (ret != GST_FLOW_OK) { /* something went wrong */ GST_ERROR ("Could not send buffer to appsrc %s. Cause %s", GST_ELEMENT_NAME (appsrc), gst_flow_get_name (ret)); } end: if (sample != NULL) gst_sample_unref (sample); return ret; }
static GstFlowReturn new_sample_cb (GstElement * appsink, gpointer user_data) { GstElement *appsrc = GST_ELEMENT (user_data); GstFlowReturn ret; GstSample *sample; GstBuffer *buffer; GstClockTime *base_time; GstPad *src, *sink; g_signal_emit_by_name (appsink, "pull-sample", &sample); if (sample == NULL) return GST_FLOW_OK; buffer = gst_sample_get_buffer (sample); if (buffer == NULL) { ret = GST_FLOW_OK; goto end; } gst_buffer_ref (buffer); buffer = gst_buffer_make_writable (buffer); KMS_ELEMENT_LOCK (GST_OBJECT_PARENT (appsrc)); base_time = g_object_get_data (G_OBJECT (GST_OBJECT_PARENT (appsrc)), BASE_TIME_DATA); if (base_time == NULL) { GstClock *clock; clock = gst_element_get_clock (appsrc); base_time = g_slice_new0 (GstClockTime); g_object_set_data_full (G_OBJECT (GST_OBJECT_PARENT (appsrc)), BASE_TIME_DATA, base_time, release_gst_clock); *base_time = gst_clock_get_time (clock) - gst_element_get_base_time (appsrc); g_object_unref (clock); GST_DEBUG ("Setting base time to: %" G_GUINT64_FORMAT, *base_time); } src = gst_element_get_static_pad (appsrc, "src"); sink = gst_pad_get_peer (src); if (sink != NULL) { if (GST_OBJECT_FLAG_IS_SET (sink, GST_PAD_FLAG_EOS)) { GST_INFO_OBJECT (sink, "Sending flush events"); gst_pad_send_event (sink, gst_event_new_flush_start ()); gst_pad_send_event (sink, gst_event_new_flush_stop (FALSE)); } g_object_unref (sink); } g_object_unref (src); if (GST_BUFFER_PTS_IS_VALID (buffer)) buffer->pts += *base_time; if (GST_BUFFER_DTS_IS_VALID (buffer)) buffer->dts += *base_time; KMS_ELEMENT_UNLOCK (GST_OBJECT_PARENT (appsrc)); // TODO: Do something to fix a possible previous EOS event g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret); gst_buffer_unref (buffer); if (ret != GST_FLOW_OK) { /* something wrong */ GST_ERROR ("Could not send buffer to appsrc %s. Cause: %s", GST_ELEMENT_NAME (appsrc), gst_flow_get_name (ret)); } end: if (sample != NULL) gst_sample_unref (sample); return ret; }
static GstFlowReturn gst_multi_file_sink_write_buffer (GstMultiFileSink * multifilesink, GstBuffer * buffer) { GstMapInfo map; gboolean ret; gboolean first_file = TRUE; gst_buffer_map (buffer, &map, GST_MAP_READ); switch (multifilesink->next_file) { case GST_MULTI_FILE_SINK_NEXT_BUFFER: if (multifilesink->files != NULL) first_file = FALSE; if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; if (first_file == FALSE) gst_multi_file_sink_write_stream_headers (multifilesink); GST_DEBUG_OBJECT (multifilesink, "Writing buffer data (%" G_GSIZE_FORMAT " bytes) to new file", map.size); ret = fwrite (map.data, map.size, 1, multifilesink->file); if (ret != 1) goto stdio_write_error; gst_multi_file_sink_close_file (multifilesink, buffer); break; case GST_MULTI_FILE_SINK_NEXT_DISCONT: if (GST_BUFFER_IS_DISCONT (buffer)) { if (multifilesink->file) gst_multi_file_sink_close_file (multifilesink, buffer); } if (multifilesink->file == NULL) { if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; } ret = fwrite (map.data, map.size, 1, multifilesink->file); if (ret != 1) goto stdio_write_error; break; case GST_MULTI_FILE_SINK_NEXT_KEY_FRAME: if (multifilesink->next_segment == GST_CLOCK_TIME_NONE) { if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { multifilesink->next_segment = GST_BUFFER_TIMESTAMP (buffer) + 10 * GST_SECOND; } } if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && GST_BUFFER_TIMESTAMP (buffer) >= multifilesink->next_segment && !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) { if (multifilesink->file) { first_file = FALSE; gst_multi_file_sink_close_file (multifilesink, buffer); } multifilesink->next_segment += 10 * GST_SECOND; } if (multifilesink->file == NULL) { if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; if (!first_file) gst_multi_file_sink_write_stream_headers (multifilesink); } ret = fwrite (map.data, map.size, 1, multifilesink->file); if (ret != 1) goto stdio_write_error; break; case GST_MULTI_FILE_SINK_NEXT_KEY_UNIT_EVENT: if (multifilesink->file == NULL) { if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; /* we don't need to write stream headers here, they will be inserted in * the stream by upstream elements if key unit events have * all_headers=true set */ } ret = fwrite (map.data, map.size, 1, multifilesink->file); if (ret != 1) goto stdio_write_error; break; case GST_MULTI_FILE_SINK_NEXT_MAX_SIZE:{ guint64 new_size; new_size = multifilesink->cur_file_size + map.size; if (new_size > multifilesink->max_file_size) { GST_INFO_OBJECT (multifilesink, "current size: %" G_GUINT64_FORMAT ", new_size: %" G_GUINT64_FORMAT ", max. size %" G_GUINT64_FORMAT, multifilesink->cur_file_size, new_size, multifilesink->max_file_size); if (multifilesink->file != NULL) { first_file = FALSE; gst_multi_file_sink_close_file (multifilesink, buffer); } } if (multifilesink->file == NULL) { if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; if (!first_file) gst_multi_file_sink_write_stream_headers (multifilesink); } ret = fwrite (map.data, map.size, 1, multifilesink->file); if (ret != 1) goto stdio_write_error; multifilesink->cur_file_size += map.size; break; } case GST_MULTI_FILE_SINK_NEXT_MAX_DURATION:{ GstClockTime new_duration = 0; if (GST_BUFFER_PTS_IS_VALID (buffer) && GST_CLOCK_TIME_IS_VALID (multifilesink->file_pts)) { /* The new duration will extend to this new buffer pts ... */ new_duration = GST_BUFFER_PTS (buffer) - multifilesink->file_pts; /* ... and duration (if it has one) */ if (GST_BUFFER_DURATION_IS_VALID (buffer)) new_duration += GST_BUFFER_DURATION (buffer); } if (new_duration > multifilesink->max_file_duration) { GST_INFO_OBJECT (multifilesink, "new_duration: %" G_GUINT64_FORMAT ", max. duration %" G_GUINT64_FORMAT, new_duration, multifilesink->max_file_duration); if (multifilesink->file != NULL) { first_file = FALSE; gst_multi_file_sink_close_file (multifilesink, buffer); } } if (multifilesink->file == NULL) { if (!gst_multi_file_sink_open_next_file (multifilesink)) goto stdio_write_error; multifilesink->file_pts = GST_BUFFER_PTS (buffer); if (!first_file) gst_multi_file_sink_write_stream_headers (multifilesink); } ret = fwrite (map.data, map.size, 1, multifilesink->file); if (ret != 1) goto stdio_write_error; break; } default: g_assert_not_reached (); } gst_buffer_unmap (buffer, &map); return GST_FLOW_OK; /* ERRORS */ stdio_write_error: switch (errno) { case ENOSPC: GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT, ("Error while writing to file."), ("%s", g_strerror (errno))); break; default: GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE, ("Error while writing to file."), ("%s", g_strerror (errno))); } gst_buffer_unmap (buffer, &map); return GST_FLOW_ERROR; }
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; }
static GstPadProbeReturn handle_mq_input (GstPad * pad, GstPadProbeInfo * info, MqStreamCtx * ctx) { GstSplitMuxSink *splitmux = ctx->splitmux; GstBuffer *buf; MqStreamBuf *buf_info = NULL; GstClockTime ts; gboolean loop_again; gboolean keyframe = FALSE; GST_LOG_OBJECT (pad, "Fired probe type 0x%x\n", info->type); /* FIXME: Handle buffer lists, until then make it clear they won't work */ if (info->type & GST_PAD_PROBE_TYPE_BUFFER_LIST) { g_warning ("Buffer list handling not implemented"); return GST_PAD_PROBE_DROP; } if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) { GstEvent *event = gst_pad_probe_info_get_event (info); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEGMENT: gst_event_copy_segment (event, &ctx->in_segment); break; case GST_EVENT_FLUSH_STOP: GST_SPLITMUX_LOCK (splitmux); gst_segment_init (&ctx->in_segment, GST_FORMAT_UNDEFINED); ctx->in_eos = FALSE; ctx->in_bytes = 0; ctx->in_running_time = 0; GST_SPLITMUX_UNLOCK (splitmux); break; case GST_EVENT_EOS: GST_SPLITMUX_LOCK (splitmux); ctx->in_eos = TRUE; if (splitmux->state == SPLITMUX_STATE_STOPPED) goto beach; if (ctx->is_video) { GST_INFO_OBJECT (splitmux, "Got Video EOS. Finishing up"); /* Act as if this is a new keyframe with infinite timestamp */ splitmux->max_in_running_time = GST_CLOCK_TIME_NONE; splitmux->state = SPLITMUX_STATE_WAITING_GOP_COMPLETE; /* Wake up other input pads to collect this GOP */ GST_SPLITMUX_BROADCAST (splitmux); check_completed_gop (splitmux, ctx); } else if (splitmux->state == SPLITMUX_STATE_WAITING_GOP_COMPLETE) { /* If we are waiting for a GOP to be completed (ie, for aux * pads to catch up), then this pad is complete, so check * if the whole GOP is. */ check_completed_gop (splitmux, ctx); } GST_SPLITMUX_UNLOCK (splitmux); break; default: break; } return GST_PAD_PROBE_PASS; } buf = gst_pad_probe_info_get_buffer (info); ctx->in_running_time = gst_segment_to_running_time (&ctx->in_segment, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf)); buf_info = mq_stream_buf_new (); if (GST_BUFFER_PTS_IS_VALID (buf)) ts = GST_BUFFER_PTS (buf); else ts = GST_BUFFER_DTS (buf); GST_SPLITMUX_LOCK (splitmux); if (splitmux->state == SPLITMUX_STATE_STOPPED) goto beach; /* If this buffer has a timestamp, advance the input timestamp of the * stream */ if (GST_CLOCK_TIME_IS_VALID (ts)) { GstClockTime running_time = gst_segment_to_running_time (&ctx->in_segment, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf)); if (GST_CLOCK_TIME_IS_VALID (running_time) && (ctx->in_running_time == GST_CLOCK_TIME_NONE || running_time > ctx->in_running_time)) ctx->in_running_time = running_time; } /* Try to make sure we have a valid running time */ if (!GST_CLOCK_TIME_IS_VALID (ctx->in_running_time)) { ctx->in_running_time = gst_segment_to_running_time (&ctx->in_segment, GST_FORMAT_TIME, ctx->in_segment.start); } buf_info->run_ts = ctx->in_running_time; buf_info->buf_size = gst_buffer_get_size (buf); /* Update total input byte counter for overflow detect */ ctx->in_bytes += buf_info->buf_size; GST_DEBUG_OBJECT (pad, "Buf TS %" GST_TIME_FORMAT " total in_bytes %" G_GSIZE_FORMAT, GST_TIME_ARGS (buf_info->run_ts), ctx->in_bytes); loop_again = TRUE; do { if (ctx->flushing) break; switch (splitmux->state) { case SPLITMUX_STATE_COLLECTING_GOP_START: if (ctx->is_video) { /* If a keyframe, we have a complete GOP */ if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) || !GST_CLOCK_TIME_IS_VALID (ctx->in_running_time) || splitmux->max_in_running_time >= ctx->in_running_time) { /* Pass this buffer through */ loop_again = FALSE; break; } GST_INFO_OBJECT (pad, "Have keyframe with running time %" GST_TIME_FORMAT, GST_TIME_ARGS (ctx->in_running_time)); keyframe = TRUE; splitmux->state = SPLITMUX_STATE_WAITING_GOP_COMPLETE; splitmux->max_in_running_time = ctx->in_running_time; /* Wake up other input pads to collect this GOP */ GST_SPLITMUX_BROADCAST (splitmux); check_completed_gop (splitmux, ctx); } else { /* We're still waiting for a keyframe on the video pad, sleep */ GST_LOG_OBJECT (pad, "Sleeping for GOP start"); GST_SPLITMUX_WAIT (splitmux); GST_LOG_OBJECT (pad, "Done sleeping for GOP start state now %d", splitmux->state); } break; case SPLITMUX_STATE_WAITING_GOP_COMPLETE: /* After a GOP start is found, this buffer might complete the GOP */ /* If we overran the target timestamp, it might be time to process * the GOP, otherwise bail out for more data */ GST_LOG_OBJECT (pad, "Checking TS %" GST_TIME_FORMAT " against max %" GST_TIME_FORMAT, GST_TIME_ARGS (ctx->in_running_time), GST_TIME_ARGS (splitmux->max_in_running_time)); if (ctx->in_running_time < splitmux->max_in_running_time) { loop_again = FALSE; break; } GST_LOG_OBJECT (pad, "Collected last packet of GOP. Checking other pads"); check_completed_gop (splitmux, ctx); break; case SPLITMUX_STATE_ENDING_FILE: case SPLITMUX_STATE_START_NEXT_FRAGMENT: /* A fragment is ending, wait until that's done before continuing */ GST_DEBUG_OBJECT (pad, "Sleeping for fragment restart"); GST_SPLITMUX_WAIT (splitmux); GST_DEBUG_OBJECT (pad, "Done sleeping for fragment restart state now %d", splitmux->state); break; default: loop_again = FALSE; break; } } while (loop_again); if (keyframe) { splitmux->queued_gops++; buf_info->keyframe = TRUE; } /* Now add this buffer to the queue just before returning */ g_queue_push_head (&ctx->queued_bufs, buf_info); /* Check the buffer will fit in the mq */ check_queue_length (splitmux, ctx); GST_LOG_OBJECT (pad, "Returning to queue buffer %" GST_PTR_FORMAT " run ts %" GST_TIME_FORMAT, buf, GST_TIME_ARGS (ctx->in_running_time)); GST_SPLITMUX_UNLOCK (splitmux); return GST_PAD_PROBE_PASS; beach: GST_SPLITMUX_UNLOCK (splitmux); if (buf_info) mq_stream_buf_free (buf_info); return GST_PAD_PROBE_PASS; }
/* Decode */ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { block_t *p_block; picture_t *p_pic = NULL; decoder_sys_t *p_sys = p_dec->p_sys; GstMessage *p_msg; GstBuffer *p_buf; if( !pp_block ) return NULL; p_block = *pp_block; if( !p_block ) goto check_messages; if( unlikely( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED ) ) ) { if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) Flush( p_dec ); if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) { block_Release( p_block ); goto done; } } if( likely( p_block->i_buffer ) ) { p_buf = gst_buffer_new_wrapped_full( GST_MEMORY_FLAG_READONLY, p_block->p_start, p_block->i_size, p_block->p_buffer - p_block->p_start, p_block->i_buffer, p_block, ( GDestroyNotify )block_Release ); if( unlikely( p_buf == NULL ) ) { msg_Err( p_dec, "failed to create input gstbuffer" ); p_dec->b_error = true; block_Release( p_block ); goto done; } if( p_block->i_dts > VLC_TS_INVALID ) GST_BUFFER_DTS( p_buf ) = gst_util_uint64_scale( p_block->i_dts, GST_SECOND, GST_MSECOND ); if( p_block->i_pts <= VLC_TS_INVALID ) GST_BUFFER_PTS( p_buf ) = GST_BUFFER_DTS( p_buf ); else GST_BUFFER_PTS( p_buf ) = gst_util_uint64_scale( p_block->i_pts, GST_SECOND, GST_MSECOND ); if( p_block->i_length > VLC_TS_INVALID ) GST_BUFFER_DURATION( p_buf ) = gst_util_uint64_scale( p_block->i_length, GST_SECOND, GST_MSECOND ); if( p_dec->fmt_in.video.i_frame_rate && p_dec->fmt_in.video.i_frame_rate_base ) GST_BUFFER_DURATION( p_buf ) = gst_util_uint64_scale( GST_SECOND, p_dec->fmt_in.video.i_frame_rate_base, p_dec->fmt_in.video.i_frame_rate ); /* Give the input buffer to GStreamer Bin. * * libvlc libvlc * \ (i/p) (o/p) ^ * \ / * ___v____GSTREAMER BIN_____/____ * | | * | appsrc-->decode-->vlcsink | * |_______________________________| * * * * * * * * * * * * * * * * * * * * * */ if( unlikely( gst_app_src_push_buffer( GST_APP_SRC_CAST( p_sys->p_decode_src ), p_buf ) != GST_FLOW_OK ) ) { /* block will be released internally, * when gst_buffer_unref() is called */ p_dec->b_error = true; msg_Err( p_dec, "failed to push buffer" ); goto done; } } else block_Release( p_block ); check_messages: /* Poll for any messages, errors */ p_msg = gst_bus_pop_filtered( p_sys->p_bus, GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR | GST_MESSAGE_EOS | GST_MESSAGE_WARNING | GST_MESSAGE_INFO ); if( p_msg ) { switch( GST_MESSAGE_TYPE( p_msg ) ){ case GST_MESSAGE_EOS: /* for debugging purpose */ msg_Warn( p_dec, "got unexpected eos" ); break; /* First buffer received */ case GST_MESSAGE_ASYNC_DONE: /* for debugging purpose */ p_sys->b_prerolled = true; msg_Dbg( p_dec, "Pipeline is prerolled" ); break; default: p_dec->b_error = default_msg_handler( p_dec, p_msg ); if( p_dec->b_error ) { gst_message_unref( p_msg ); goto done; } break; } gst_message_unref( p_msg ); } /* Look for any output buffers in the queue */ if( gst_atomic_queue_peek( p_sys->p_que ) ) { GstBuffer *p_buf = GST_BUFFER_CAST( gst_atomic_queue_pop( p_sys->p_que )); GstMemory *p_mem; if(( p_mem = gst_buffer_peek_memory( p_buf, 0 )) && GST_IS_VLC_PICTURE_PLANE_ALLOCATOR( p_mem->allocator )) { p_pic = picture_Hold(( (GstVlcPicturePlane*) p_mem )->p_pic ); } else { GstVideoFrame frame; /* Get a new picture */ p_pic = decoder_NewPicture( p_dec ); if( !p_pic ) goto done; if( unlikely( !gst_video_frame_map( &frame, &p_sys->vinfo, p_buf, GST_MAP_READ ) ) ) { msg_Err( p_dec, "failed to map gst video frame" ); gst_buffer_unref( p_buf ); p_dec->b_error = true; goto done; } gst_CopyPicture( p_pic, &frame ); gst_video_frame_unmap( &frame ); } if( likely( GST_BUFFER_PTS_IS_VALID( p_buf ) ) ) p_pic->date = gst_util_uint64_scale( GST_BUFFER_PTS( p_buf ), GST_MSECOND, GST_SECOND ); else msg_Warn( p_dec, "Gst Buffer has no timestamp" ); gst_buffer_unref( p_buf ); } done: *pp_block = NULL; return p_pic; }
static GstFlowReturn gst_rtp_mux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstRTPMux *rtp_mux; GstFlowReturn ret; GstRTPMuxPadPrivate *padpriv; gboolean drop; gboolean changed = FALSE; GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; rtp_mux = GST_RTP_MUX (parent); if (gst_pad_check_reconfigure (rtp_mux->srcpad)) { GstCaps *current_caps = gst_pad_get_current_caps (pad); if (!gst_rtp_mux_setcaps (pad, rtp_mux, current_caps)) { ret = GST_FLOW_NOT_NEGOTIATED; gst_buffer_unref (buffer); goto out; } gst_caps_unref (current_caps); } GST_OBJECT_LOCK (rtp_mux); padpriv = gst_pad_get_element_private (pad); if (!padpriv) { GST_OBJECT_UNLOCK (rtp_mux); gst_buffer_unref (buffer); return GST_FLOW_NOT_LINKED; } buffer = gst_buffer_make_writable (buffer); if (!gst_rtp_buffer_map (buffer, GST_MAP_READWRITE, &rtpbuffer)) { GST_OBJECT_UNLOCK (rtp_mux); gst_buffer_unref (buffer); GST_ERROR_OBJECT (rtp_mux, "Invalid RTP buffer"); return GST_FLOW_ERROR; } drop = !process_buffer_locked (rtp_mux, padpriv, &rtpbuffer); gst_rtp_buffer_unmap (&rtpbuffer); if (!drop) { if (pad != rtp_mux->last_pad) { changed = TRUE; g_clear_object (&rtp_mux->last_pad); rtp_mux->last_pad = g_object_ref (pad); } if (GST_BUFFER_DURATION_IS_VALID (buffer) && GST_BUFFER_PTS_IS_VALID (buffer)) rtp_mux->last_stop = GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer); else rtp_mux->last_stop = GST_CLOCK_TIME_NONE; } GST_OBJECT_UNLOCK (rtp_mux); if (changed) gst_pad_sticky_events_foreach (pad, resend_events, rtp_mux); if (drop) { gst_buffer_unref (buffer); ret = GST_FLOW_OK; } else { ret = gst_pad_push (rtp_mux->srcpad, buffer); } out: return ret; }
static GstFlowReturn recv_sample (GstElement * appsink, gpointer user_data) { KmsRecorderEndPoint *self = KMS_RECORDER_END_POINT (GST_OBJECT_PARENT (appsink)); GstElement *appsrc = GST_ELEMENT (user_data); KmsUriEndPointState state; GstFlowReturn ret; GstSample *sample; GstBuffer *buffer; GstCaps *caps; BaseTimeType *base_time; g_signal_emit_by_name (appsink, "pull-sample", &sample); if (sample == NULL) return GST_FLOW_OK; g_object_get (G_OBJECT (appsrc), "caps", &caps, NULL); if (caps == NULL) { /* Appsrc has not yet caps defined */ GstPad *sink_pad = gst_element_get_static_pad (appsink, "sink"); if (sink_pad != NULL) { caps = gst_pad_get_current_caps (sink_pad); g_object_unref (sink_pad); } if (caps == NULL) { GST_ELEMENT_ERROR (self, CORE, CAPS, ("No caps found for %s", GST_ELEMENT_NAME (appsrc)), GST_ERROR_SYSTEM); ret = GST_FLOW_ERROR; goto end; } g_object_set (appsrc, "caps", caps, NULL); } gst_caps_unref (caps); buffer = gst_sample_get_buffer (sample); if (buffer == NULL) { ret = GST_FLOW_OK; goto end; } g_object_get (G_OBJECT (self), "state", &state, NULL); if (state != KMS_URI_END_POINT_STATE_START) { GST_DEBUG ("Dropping buffer %" GST_PTR_FORMAT, buffer); ret = GST_FLOW_OK; goto end; } gst_buffer_ref (buffer); buffer = gst_buffer_make_writable (buffer); KMS_ELEMENT_LOCK (GST_OBJECT_PARENT (appsink)); base_time = g_object_get_data (G_OBJECT (appsrc), BASE_TIME_DATA); if (base_time == NULL) { base_time = g_slice_new0 (BaseTimeType); base_time->pts = GST_CLOCK_TIME_NONE; base_time->dts = GST_CLOCK_TIME_NONE; g_object_set_data_full (G_OBJECT (appsrc), BASE_TIME_DATA, base_time, release_base_time_type); } if (!GST_CLOCK_TIME_IS_VALID (base_time->pts) && GST_BUFFER_PTS_IS_VALID (buffer)) { base_time->pts = buffer->pts; GST_DEBUG_OBJECT (appsrc, "Setting pts base time to: %" G_GUINT64_FORMAT, base_time->pts); } if (!GST_CLOCK_TIME_IS_VALID (base_time->dts) && GST_BUFFER_DTS_IS_VALID (buffer)) { base_time->dts = buffer->dts; GST_DEBUG_OBJECT (appsrc, "Setting dts base time to: %" G_GUINT64_FORMAT, base_time->dts); } if (GST_CLOCK_TIME_IS_VALID (base_time->pts) && GST_BUFFER_PTS_IS_VALID (buffer)) { buffer->pts -= base_time->pts + self->priv->paused_time; buffer->dts = buffer->pts; } else if (GST_CLOCK_TIME_IS_VALID (base_time->dts) && GST_BUFFER_DTS_IS_VALID (buffer)) { buffer->dts -= base_time->dts + self->priv->paused_time; buffer->pts = buffer->dts; } g_object_set (self->priv->controller, "has_data", TRUE, NULL); KMS_ELEMENT_UNLOCK (GST_OBJECT_PARENT (appsink)); GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_LIVE); if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_HEADER)) GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret); gst_buffer_unref (buffer); if (ret != GST_FLOW_OK) { /* something wrong */ GST_ERROR ("Could not send buffer to appsrc %s. Cause: %s", GST_ELEMENT_NAME (appsrc), gst_flow_get_name (ret)); } end: if (sample != NULL) gst_sample_unref (sample); return ret; }