static gboolean gst_mimenc_event (GstPad * pad, GstEvent * event) { GstMimEnc *mimenc = GST_MIMENC (gst_pad_get_parent (pad)); gboolean ret = TRUE; gboolean forward = TRUE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NEWSEGMENT: { GstFormat format; gdouble rate, arate; gint64 start, stop, time; gboolean update; gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, &start, &stop, &time); /* we need time for now */ if (format != GST_FORMAT_TIME) goto newseg_wrong_format; GST_DEBUG_OBJECT (mimenc, "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time)); /* now configure the values, we need these to time the release of the * buffers on the srcpad. */ GST_OBJECT_LOCK (mimenc); gst_segment_set_newsegment_full (&mimenc->segment, update, rate, arate, format, start, stop, time); GST_OBJECT_UNLOCK (mimenc); forward = FALSE; break; } break; case GST_EVENT_FLUSH_STOP: GST_OBJECT_LOCK (mimenc); gst_segment_init (&mimenc->segment, GST_FORMAT_UNDEFINED); mimenc->need_newsegment = TRUE; GST_OBJECT_UNLOCK (mimenc); break; default: break; } if (forward) ret = gst_pad_push_event (mimenc->srcpad, event); else gst_event_unref (event); done: gst_object_unref (mimenc); return ret; newseg_wrong_format: { GST_DEBUG_OBJECT (mimenc, "received non TIME newsegment"); gst_event_unref (event); ret = FALSE; goto done; } }
guint gst_v4l2_allocator_start (GstV4l2Allocator * allocator, guint32 count, guint32 memory) { struct v4l2_requestbuffers breq = { count, allocator->type, memory }; gboolean can_allocate; gint i; g_return_val_if_fail (count != 0, 0); GST_OBJECT_LOCK (allocator); if (g_atomic_int_get (&allocator->active)) goto already_active; if (v4l2_ioctl (allocator->video_fd, VIDIOC_REQBUFS, &breq) < 0) goto reqbufs_failed; if (breq.count < 1) goto out_of_memory; switch (memory) { case V4L2_MEMORY_MMAP: can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (allocator, MMAP); break; case V4L2_MEMORY_USERPTR: can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (allocator, USERPTR); break; case V4L2_MEMORY_DMABUF: can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (allocator, DMABUF); break; default: can_allocate = FALSE; break; } GST_DEBUG_OBJECT (allocator, "allocated %u %s buffers out of %u requested", breq.count, memory_type_to_str (memory), count); allocator->can_allocate = can_allocate; allocator->count = breq.count; allocator->memory = memory; /* Create memory groups */ for (i = 0; i < allocator->count; i++) { allocator->groups[i] = gst_v4l2_memory_group_new (allocator, i); if (allocator->groups[i] == NULL) goto error; gst_atomic_queue_push (allocator->free_queue, allocator->groups[i]); } g_atomic_int_set (&allocator->active, TRUE); done: GST_OBJECT_UNLOCK (allocator); return breq.count; already_active: { GST_ERROR_OBJECT (allocator, "allocator already active"); goto error; } reqbufs_failed: { GST_ERROR_OBJECT (allocator, "error requesting %d buffers: %s", count, g_strerror (errno)); goto error; } out_of_memory: { GST_ERROR_OBJECT (allocator, "Not enough memory to allocate buffers"); goto error; } error: { breq.count = 0; goto done; } }
static GstFlowReturn gst_visual_gl_chain (GstPad * pad, GstBuffer * buffer) { GstGLBuffer *outbuf = NULL; GstVisualGL *visual = GST_VISUAL_GL (gst_pad_get_parent (pad)); GstFlowReturn ret = GST_FLOW_OK; guint avail; GST_DEBUG_OBJECT (visual, "chain function called"); /* If we don't have an output format yet, preallocate a buffer to try and * set one */ if (GST_PAD_CAPS (visual->srcpad) == NULL) { ret = get_buffer (visual, &outbuf); if (ret != GST_FLOW_OK) { gst_buffer_unref (buffer); goto beach; } } /* resync on DISCONT */ if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { gst_adapter_clear (visual->adapter); } GST_DEBUG_OBJECT (visual, "Input buffer has %d samples, time=%" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer) / visual->bps, GST_BUFFER_TIMESTAMP (buffer)); gst_adapter_push (visual->adapter, buffer); while (TRUE) { gboolean need_skip; guint64 dist, timestamp; GST_DEBUG_OBJECT (visual, "processing buffer"); avail = gst_adapter_available (visual->adapter); GST_DEBUG_OBJECT (visual, "avail now %u", avail); /* we need at least VISUAL_SAMPLES samples */ if (avail < VISUAL_SAMPLES * visual->bps) break; /* we need at least enough samples to make one frame */ if (avail < visual->spf * visual->bps) break; /* get timestamp of the current adapter byte */ timestamp = gst_adapter_prev_timestamp (visual->adapter, &dist); if (GST_CLOCK_TIME_IS_VALID (timestamp)) { /* convert bytes to time */ dist /= visual->bps; timestamp += gst_util_uint64_scale_int (dist, GST_SECOND, visual->rate); } if (timestamp != -1) { gint64 qostime; /* QoS is done on running time */ qostime = gst_segment_to_running_time (&visual->segment, GST_FORMAT_TIME, timestamp); qostime += visual->duration; GST_OBJECT_LOCK (visual); /* check for QoS, don't compute buffers that are known to be late */ need_skip = visual->earliest_time != -1 && qostime <= visual->earliest_time; GST_OBJECT_UNLOCK (visual); if (need_skip) { GST_WARNING_OBJECT (visual, "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (visual->earliest_time)); goto skip; } } /* alloc a buffer if we don't have one yet, this happens * when we pushed a buffer in this while loop before */ if (outbuf == NULL) { ret = get_buffer (visual, &outbuf); if (ret != GST_FLOW_OK) { goto beach; } } /* render libvisual plugin to our target */ gst_gl_display_use_fbo_v2 (visual->display, visual->width, visual->height, visual->fbo, visual->depthbuffer, visual->midtexture, (GLCB_V2) render_frame, (gpointer *) visual); /* gst video is top-down whereas opengl plan is bottom up */ gst_gl_display_use_fbo (visual->display, visual->width, visual->height, visual->fbo, visual->depthbuffer, outbuf->texture, (GLCB) bottom_up_to_top_down, visual->width, visual->height, visual->midtexture, 0, visual->width, 0, visual->height, GST_GL_DISPLAY_PROJECTION_ORTHO2D, (gpointer *) visual); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = visual->duration; ret = gst_pad_push (visual->srcpad, GST_BUFFER (outbuf)); outbuf = NULL; skip: GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input", visual->spf); /* Flush out the number of samples per frame */ gst_adapter_flush (visual->adapter, visual->spf * visual->bps); /* quit the loop if something was wrong */ if (ret != GST_FLOW_OK) break; } beach: if (outbuf != NULL) gst_gl_buffer_unref (outbuf); gst_object_unref (visual); return ret; }
static GstFlowReturn gst_curl_base_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstCurlBaseSink *sink; GstMapInfo map; guint8 *data; size_t size; GstFlowReturn ret; gchar *error; GST_LOG ("enter render"); sink = GST_CURL_BASE_SINK (bsink); GST_OBJECT_LOCK (sink); gst_buffer_map (buf, &map, GST_MAP_READ); data = map.data; size = map.size; /* check if the transfer thread has encountered problems while the * pipeline thread was working elsewhere */ if (sink->flow_ret != GST_FLOW_OK) { goto done; } g_assert (sink->transfer_cond->data_available == FALSE); /* if there is no transfer thread created, lets create one */ if (sink->transfer_thread == NULL) { if (!gst_curl_base_sink_transfer_start_unlocked (sink)) { sink->flow_ret = GST_FLOW_ERROR; goto done; } } /* make data available for the transfer thread and notify */ sink->transfer_buf->ptr = data; sink->transfer_buf->len = size; sink->transfer_buf->offset = 0; gst_curl_base_sink_transfer_thread_notify_unlocked (sink); /* wait for the transfer thread to send the data. This will be notified * either when transfer is completed by the curl read callback or by * the thread function if an error has occurred. */ gst_curl_base_sink_wait_for_transfer_thread_to_send_unlocked (sink); done: gst_buffer_unmap (buf, &map); /* Hand over error from transfer thread to streaming thread */ error = sink->error; sink->error = NULL; ret = sink->flow_ret; GST_OBJECT_UNLOCK (sink); if (error != NULL) { GST_ERROR_OBJECT (sink, "%s", error); GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("%s", error), (NULL)); g_free (error); } GST_LOG ("exit render"); return ret; }
static void handle_transfer (GstCurlBaseSink * sink) { GstCurlBaseSinkClass *klass = GST_CURL_BASE_SINK_GET_CLASS (sink); gint retval; gint activated_fds; gint running_handles; gint timeout; CURLMcode m_code; CURLcode e_code; GST_OBJECT_LOCK (sink); timeout = sink->timeout; GST_OBJECT_UNLOCK (sink); GST_DEBUG_OBJECT (sink, "handling transfers"); /* Receiving CURLM_CALL_MULTI_PERFORM means that libcurl may have more data available to send or receive - call simply curl_multi_perform before poll() on more actions */ do { m_code = curl_multi_perform (sink->multi_handle, &running_handles); } while (m_code == CURLM_CALL_MULTI_PERFORM); GST_DEBUG_OBJECT (sink, "running handles: %d", running_handles); while (running_handles && (m_code == CURLM_OK)) { if (klass->transfer_prepare_poll_wait) { klass->transfer_prepare_poll_wait (sink); } activated_fds = gst_poll_wait (sink->fdset, timeout * GST_SECOND); if (G_UNLIKELY (activated_fds == -1)) { if (errno == EAGAIN || errno == EINTR) { GST_DEBUG_OBJECT (sink, "interrupted by signal"); } else if (errno == EBUSY) { GST_DEBUG_OBJECT (sink, "poll stopped"); retval = GST_FLOW_EOS; GST_OBJECT_LOCK (sink); if (gst_curl_base_sink_has_buffered_data_unlocked (sink)) GST_WARNING_OBJECT (sink, "discarding render data due to thread close flag"); GST_OBJECT_UNLOCK (sink); goto fail; } else { sink->error = g_strdup_printf ("poll failed: %s", g_strerror (errno)); retval = GST_FLOW_ERROR; goto fail; } } else if (G_UNLIKELY (activated_fds == 0)) { sink->error = g_strdup_printf ("poll timed out after %" GST_TIME_FORMAT, GST_TIME_ARGS (timeout * GST_SECOND)); retval = GST_FLOW_ERROR; goto fail; } /* readable/writable sockets */ do { m_code = curl_multi_perform (sink->multi_handle, &running_handles); } while (m_code == CURLM_CALL_MULTI_PERFORM); GST_DEBUG_OBJECT (sink, "running handles: %d", running_handles); } if (m_code != CURLM_OK) { sink->error = g_strdup_printf ("failed to write data: %s", curl_multi_strerror (m_code)); retval = GST_FLOW_ERROR; goto fail; } /* problems still might have occurred on individual transfers even when * curl_multi_perform returns CURLM_OK */ if ((e_code = gst_curl_base_sink_transfer_check (sink)) != CURLE_OK) { sink->error = g_strdup_printf ("failed to transfer data: %s", curl_easy_strerror (e_code)); retval = GST_FLOW_ERROR; goto fail; } gst_curl_base_sink_got_response_notify (sink); GST_OBJECT_LOCK (sink); if (sink->socket_type == CURLSOCKTYPE_ACCEPT) { if (!gst_poll_remove_fd (sink->fdset, &sink->fd)) { sink->error = g_strdup_printf ("failed to remove fd"); retval = GST_FLOW_ERROR; GST_OBJECT_UNLOCK (sink); goto fail; } sink->fd.fd = -1; } GST_OBJECT_UNLOCK (sink); return; fail: GST_OBJECT_LOCK (sink); if (sink->flow_ret == GST_FLOW_OK) { sink->flow_ret = retval; } GST_OBJECT_UNLOCK (sink); return; }
static gboolean gst_audio_aggregator_src_event (GstAggregator * agg, GstEvent * event) { gboolean result; GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (agg); GST_DEBUG_OBJECT (agg->srcpad, "Got %s event on src pad", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_QOS: /* QoS might be tricky */ gst_event_unref (event); return FALSE; case GST_EVENT_NAVIGATION: /* navigation is rather pointless. */ gst_event_unref (event); return FALSE; break; case GST_EVENT_SEEK: { GstSeekFlags flags; gdouble rate; GstSeekType start_type, stop_type; gint64 start, stop; GstFormat seek_format, dest_format; /* parse the seek parameters */ gst_event_parse_seek (event, &rate, &seek_format, &flags, &start_type, &start, &stop_type, &stop); /* Check the seeking parametters before linking up */ if ((start_type != GST_SEEK_TYPE_NONE) && (start_type != GST_SEEK_TYPE_SET)) { result = FALSE; GST_DEBUG_OBJECT (aagg, "seeking failed, unhandled seek type for start: %d", start_type); goto done; } if ((stop_type != GST_SEEK_TYPE_NONE) && (stop_type != GST_SEEK_TYPE_SET)) { result = FALSE; GST_DEBUG_OBJECT (aagg, "seeking failed, unhandled seek type for end: %d", stop_type); goto done; } GST_OBJECT_LOCK (agg); dest_format = agg->segment.format; GST_OBJECT_UNLOCK (agg); if (seek_format != dest_format) { result = FALSE; GST_DEBUG_OBJECT (aagg, "seeking failed, unhandled seek format: %s", gst_format_get_name (seek_format)); goto done; } } break; default: break; } return GST_AGGREGATOR_CLASS (gst_audio_aggregator_parent_class)->src_event (agg, event); done: return result; }
void gst_gl_context_helper_ensure_context (GstGLContextHelper * ctxh) { GError *error = NULL; GstGLContext *context; g_return_if_fail (ctxh != NULL); if (!ctxh->display) gst_gl_ensure_element_data (ctxh->element, &ctxh->display, &ctxh->other_context); if (!ctxh->display) goto display_error; context = _find_local_gl_context (ctxh); if (context) { GST_INFO_OBJECT (ctxh->element, "found local context %p, old context %p", context, ctxh->context); if (ctxh->context) gst_object_unref (ctxh->context); ctxh->context = context; } if (!ctxh->context) { GST_OBJECT_LOCK (ctxh->display); do { if (ctxh->context) gst_object_unref (ctxh->context); ctxh->context = gst_gl_display_get_gl_context_for_thread (ctxh->display, NULL); if (!ctxh->context) { if (!gst_gl_display_create_context (ctxh->display, ctxh->other_context, &ctxh->context, &error)) { GST_OBJECT_UNLOCK (ctxh->display); goto context_error; } } } while (!gst_gl_display_add_context (ctxh->display, ctxh->context)); GST_OBJECT_UNLOCK (ctxh->display); } return; context_error: { GST_ELEMENT_ERROR (ctxh->element, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); g_clear_error (&error); return; } display_error: { GST_ELEMENT_ERROR (ctxh->element, RESOURCE, NOT_FOUND, ("Failed to obtain display"), (NULL)); return; } }
static GstFlowReturn gst_fake_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** ret) { GstFakeSrc *src; GstBuffer *buf; GstClockTime time; src = GST_FAKE_SRC (basesrc); buf = gst_fake_src_create_buffer (src); GST_BUFFER_OFFSET (buf) = src->buffer_count++; if (src->datarate > 0) { time = (src->bytes_sent * GST_SECOND) / src->datarate; GST_BUFFER_DURATION (buf) = GST_BUFFER_SIZE (buf) * GST_SECOND / src->datarate; } else if (gst_base_src_is_live (basesrc)) { GstClock *clock; clock = gst_element_get_clock (GST_ELEMENT (src)); if (clock) { time = gst_clock_get_time (clock); time -= gst_element_get_base_time (GST_ELEMENT (src)); gst_object_unref (clock); } else { /* not an error not to have a clock */ time = GST_CLOCK_TIME_NONE; } } else { time = GST_CLOCK_TIME_NONE; } GST_BUFFER_TIMESTAMP (buf) = time; if (!src->silent) { gchar ts_str[64], dur_str[64]; GST_OBJECT_LOCK (src); g_free (src->last_message); if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) { g_snprintf (ts_str, sizeof (ts_str), "%" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); } else { g_strlcpy (ts_str, "none", sizeof (ts_str)); } if (GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE) { g_snprintf (dur_str, sizeof (dur_str), "%" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); } else { g_strlcpy (dur_str, "none", sizeof (dur_str)); } src->last_message = g_strdup_printf ("get ******* > (%5d bytes, timestamp: %s" ", duration: %s, offset: %" G_GINT64_FORMAT ", offset_end: %" G_GINT64_FORMAT ", flags: %d) %p", GST_BUFFER_SIZE (buf), ts_str, dur_str, GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf), GST_MINI_OBJECT (buf)->flags, buf); GST_OBJECT_UNLOCK (src); g_object_notify (G_OBJECT (src), "last_message"); } if (src->signal_handoffs) { GST_LOG_OBJECT (src, "pre handoff emit"); g_signal_emit (G_OBJECT (src), gst_fake_src_signals[SIGNAL_HANDOFF], 0, buf, basesrc->srcpad); GST_LOG_OBJECT (src, "post handoff emit"); } src->bytes_sent += GST_BUFFER_SIZE (buf); *ret = buf; return GST_FLOW_OK; }
static GstFlowReturn gst_visual_chain (GstPad * pad, GstBuffer * buffer) { GstBuffer *outbuf = NULL; guint i; GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad)); GstFlowReturn ret = GST_FLOW_OK; guint avail; GST_DEBUG_OBJECT (visual, "chain function called"); /* If we don't have an output format yet, preallocate a buffer to try and * set one */ if (GST_PAD_CAPS (visual->srcpad) == NULL) { ret = get_buffer (visual, &outbuf); if (ret != GST_FLOW_OK) { gst_buffer_unref (buffer); goto beach; } } /* resync on DISCONT */ if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { gst_adapter_clear (visual->adapter); } GST_DEBUG_OBJECT (visual, "Input buffer has %d samples, time=%" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer) / visual->bps, GST_BUFFER_TIMESTAMP (buffer)); gst_adapter_push (visual->adapter, buffer); while (TRUE) { gboolean need_skip; const guint16 *data; guint64 dist, timestamp; GST_DEBUG_OBJECT (visual, "processing buffer"); avail = gst_adapter_available (visual->adapter); GST_DEBUG_OBJECT (visual, "avail now %u", avail); /* we need at least VISUAL_SAMPLES samples */ if (avail < VISUAL_SAMPLES * visual->bps) break; /* we need at least enough samples to make one frame */ if (avail < visual->spf * visual->bps) break; /* get timestamp of the current adapter byte */ timestamp = gst_adapter_prev_timestamp (visual->adapter, &dist); if (GST_CLOCK_TIME_IS_VALID (timestamp)) { /* convert bytes to time */ dist /= visual->bps; timestamp += gst_util_uint64_scale_int (dist, GST_SECOND, visual->rate); } if (timestamp != -1) { gint64 qostime; /* QoS is done on running time */ qostime = gst_segment_to_running_time (&visual->segment, GST_FORMAT_TIME, timestamp); qostime += visual->duration; GST_OBJECT_LOCK (visual); /* check for QoS, don't compute buffers that are known to be late */ need_skip = visual->earliest_time != -1 && qostime <= visual->earliest_time; GST_OBJECT_UNLOCK (visual); if (need_skip) { GST_WARNING_OBJECT (visual, "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (visual->earliest_time)); goto skip; } } /* Read VISUAL_SAMPLES samples per channel */ data = (const guint16 *) gst_adapter_peek (visual->adapter, VISUAL_SAMPLES * visual->bps); #if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000 { VisBuffer *lbuf, *rbuf; guint16 ldata[VISUAL_SAMPLES], rdata[VISUAL_SAMPLES]; VisAudioSampleRateType rate; lbuf = visual_buffer_new_with_buffer (ldata, sizeof (ldata), NULL); rbuf = visual_buffer_new_with_buffer (rdata, sizeof (rdata), NULL); if (visual->channels == 2) { for (i = 0; i < VISUAL_SAMPLES; i++) { ldata[i] = *data++; rdata[i] = *data++; } } else { for (i = 0; i < VISUAL_SAMPLES; i++) { ldata[i] = *data; rdata[i] = *data++; } } switch (visual->rate) { case 8000: rate = VISUAL_AUDIO_SAMPLE_RATE_8000; break; case 11250: rate = VISUAL_AUDIO_SAMPLE_RATE_11250; break; case 22500: rate = VISUAL_AUDIO_SAMPLE_RATE_22500; break; case 32000: rate = VISUAL_AUDIO_SAMPLE_RATE_32000; break; case 44100: rate = VISUAL_AUDIO_SAMPLE_RATE_44100; break; case 48000: rate = VISUAL_AUDIO_SAMPLE_RATE_48000; break; case 96000: rate = VISUAL_AUDIO_SAMPLE_RATE_96000; break; default: visual_object_unref (VISUAL_OBJECT (lbuf)); visual_object_unref (VISUAL_OBJECT (rbuf)); GST_ERROR_OBJECT (visual, "unsupported rate %d", visual->rate); ret = GST_FLOW_ERROR; goto beach; break; } visual_audio_samplepool_input_channel (visual->audio->samplepool, lbuf, rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, (char *) VISUAL_AUDIO_CHANNEL_LEFT); visual_audio_samplepool_input_channel (visual->audio->samplepool, rbuf, rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, (char *) VISUAL_AUDIO_CHANNEL_RIGHT); visual_object_unref (VISUAL_OBJECT (lbuf)); visual_object_unref (VISUAL_OBJECT (rbuf)); } #else if (visual->channels == 2) { for (i = 0; i < VISUAL_SAMPLES; i++) { visual->audio->plugpcm[0][i] = *data++; visual->audio->plugpcm[1][i] = *data++; } } else { for (i = 0; i < VISUAL_SAMPLES; i++) { visual->audio->plugpcm[0][i] = *data; visual->audio->plugpcm[1][i] = *data++; } } #endif /* alloc a buffer if we don't have one yet, this happens * when we pushed a buffer in this while loop before */ if (outbuf == NULL) { ret = get_buffer (visual, &outbuf); if (ret != GST_FLOW_OK) { goto beach; } } visual_video_set_buffer (visual->video, GST_BUFFER_DATA (outbuf)); visual_audio_analyze (visual->audio); visual_actor_run (visual->actor, visual->audio); visual_video_set_buffer (visual->video, NULL); GST_DEBUG_OBJECT (visual, "rendered one frame"); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = visual->duration; ret = gst_pad_push (visual->srcpad, outbuf); outbuf = NULL; skip: GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input", visual->spf); /* Flush out the number of samples per frame */ gst_adapter_flush (visual->adapter, visual->spf * visual->bps); /* quit the loop if something was wrong */ if (ret != GST_FLOW_OK) break; } beach: if (outbuf != NULL) gst_buffer_unref (outbuf); gst_object_unref (visual); return ret; }
static GstFlowReturn gst_v4l2src_fill (GstPushSrc * src, GstBuffer * buf) { GstV4l2Src *v4l2src = GST_V4L2SRC (src); GstV4l2Object *obj = v4l2src->v4l2object; GstFlowReturn ret; GstClock *clock; GstClockTime abs_time, base_time, timestamp, duration; GstClockTime delay; ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL_CAST (obj->pool), buf); 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; } if (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 (gstnow < timestamp && (timestamp - gstnow) > (10 * GST_SECOND)) { GTimeVal now; /* very large diff, fall back to system time */ g_get_current_time (&now); gstnow = GST_TIMEVAL_TO_TIME (now); } if (gstnow > timestamp) { delay = gstnow - timestamp; } else { delay = 0; } 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 */ GST_BUFFER_OFFSET (buf) = v4l2src->offset++; GST_BUFFER_OFFSET_END (buf) = v4l2src->offset; 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)); GST_BUFFER_TIMESTAMP (buf) = timestamp; GST_BUFFER_DURATION (buf) = duration; return ret; /* ERROR */ error: { GST_DEBUG_OBJECT (src, "error processing buffer %d (%s)", ret, gst_flow_get_name (ret)); return ret; } }
static void gst_fake_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstFakeSrc *src; GstBaseSrc *basesrc; g_return_if_fail (GST_IS_FAKE_SRC (object)); src = GST_FAKE_SRC (object); basesrc = GST_BASE_SRC (object); switch (prop_id) { case PROP_OUTPUT: g_value_set_enum (value, src->output); break; case PROP_DATA: g_value_set_enum (value, src->data); break; case PROP_SIZETYPE: g_value_set_enum (value, src->sizetype); break; case PROP_SIZEMIN: g_value_set_int (value, src->sizemin); break; case PROP_SIZEMAX: g_value_set_int (value, src->sizemax); break; case PROP_PARENTSIZE: g_value_set_int (value, src->parentsize); break; case PROP_FILLTYPE: g_value_set_enum (value, src->filltype); break; case PROP_DATARATE: g_value_set_int (value, src->datarate); break; case PROP_SYNC: g_value_set_boolean (value, src->sync); break; case PROP_PATTERN: g_value_set_string (value, src->pattern); break; case PROP_SILENT: g_value_set_boolean (value, src->silent); break; case PROP_SIGNAL_HANDOFFS: g_value_set_boolean (value, src->signal_handoffs); break; case PROP_DUMP: g_value_set_boolean (value, src->dump); break; case PROP_LAST_MESSAGE: GST_OBJECT_LOCK (src); g_value_set_string (value, src->last_message); GST_OBJECT_UNLOCK (src); break; case PROP_CAN_ACTIVATE_PUSH: g_value_set_boolean (value, GST_BASE_SRC (src)->can_activate_push); break; case PROP_CAN_ACTIVATE_PULL: g_value_set_boolean (value, src->can_activate_pull); break; case PROP_IS_LIVE: g_value_set_boolean (value, gst_base_src_is_live (basesrc)); break; case PROP_FORMAT: g_value_set_enum (value, src->format); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static GstCaps * gst_alsasink_getcaps (GstBaseSink * bsink, GstCaps * filter) { GstElementClass *element_class; GstPadTemplate *pad_template; GstAlsaSink *sink = GST_ALSA_SINK (bsink); GstCaps *caps, *templ_caps; GST_OBJECT_LOCK (sink); if (sink->handle == NULL) { GST_OBJECT_UNLOCK (sink); GST_DEBUG_OBJECT (sink, "device not open, using template caps"); return NULL; /* base class will get template caps for us */ } if (sink->cached_caps) { if (filter) { caps = gst_caps_intersect_full (filter, sink->cached_caps, GST_CAPS_INTERSECT_FIRST); GST_OBJECT_UNLOCK (sink); GST_LOG_OBJECT (sink, "Returning cached caps %" GST_PTR_FORMAT " with " "filter %" GST_PTR_FORMAT " applied: %" GST_PTR_FORMAT, sink->cached_caps, filter, caps); return caps; } else { caps = gst_caps_ref (sink->cached_caps); GST_OBJECT_UNLOCK (sink); GST_LOG_OBJECT (sink, "Returning cached caps %" GST_PTR_FORMAT, caps); return caps; } } element_class = GST_ELEMENT_GET_CLASS (sink); pad_template = gst_element_class_get_pad_template (element_class, "sink"); if (pad_template == NULL) { GST_OBJECT_UNLOCK (sink); g_assert_not_reached (); return NULL; } templ_caps = gst_pad_template_get_caps (pad_template); caps = gst_alsa_probe_supported_formats (GST_OBJECT (sink), sink->device, sink->handle, templ_caps); gst_caps_unref (templ_caps); if (caps) { sink->cached_caps = gst_caps_ref (caps); } GST_OBJECT_UNLOCK (sink); GST_INFO_OBJECT (sink, "returning caps %" GST_PTR_FORMAT, caps); if (filter) { GstCaps *intersection; intersection = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (caps); return intersection; } else { return caps; } }
static GstStateChangeReturn gst_mimenc_change_state (GstElement * element, GstStateChange transition) { GstMimEnc *mimenc = GST_MIMENC (element); GstStateChangeReturn ret; gboolean paused_mode; switch (transition) { case GST_STATE_CHANGE_READY_TO_NULL: GST_OBJECT_LOCK (element); if (mimenc->enc != NULL) { mimic_close (mimenc->enc); mimenc->enc = NULL; mimenc->buffer_size = -1; mimenc->frames = 0; } GST_OBJECT_UNLOCK (element); break; case GST_STATE_CHANGE_READY_TO_PAUSED: GST_OBJECT_LOCK (mimenc); gst_segment_init (&mimenc->segment, GST_FORMAT_UNDEFINED); mimenc->last_buffer = GST_CLOCK_TIME_NONE; mimenc->need_newsegment = TRUE; GST_OBJECT_UNLOCK (mimenc); break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: GST_OBJECT_LOCK (mimenc); if (mimenc->clock_id) gst_clock_id_unschedule (mimenc->clock_id); mimenc->stop_paused_mode = TRUE; GST_OBJECT_UNLOCK (mimenc); gst_pad_pause_task (mimenc->srcpad); break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_PLAYING: GST_OBJECT_LOCK (mimenc); mimenc->stop_paused_mode = FALSE; paused_mode = mimenc->paused_mode; if (paused_mode) { if (!GST_ELEMENT_CLOCK (mimenc)) { GST_OBJECT_UNLOCK (mimenc); GST_ELEMENT_ERROR (mimenc, RESOURCE, FAILED, ("Using paused-mode requires a clock, but no clock was provided" " to the element"), (NULL)); return GST_STATE_CHANGE_FAILURE; } if (mimenc->last_buffer == GST_CLOCK_TIME_NONE) mimenc->last_buffer = gst_clock_get_time (GST_ELEMENT_CLOCK (mimenc)) - GST_ELEMENT_CAST (mimenc)->base_time; } GST_OBJECT_UNLOCK (mimenc); if (paused_mode) { if (!gst_pad_start_task (mimenc->srcpad, paused_mode_task, mimenc)) { ret = GST_STATE_CHANGE_FAILURE; GST_ERROR_OBJECT (mimenc, "Can not start task"); } } break; default: break; } return ret; }
static void paused_mode_task (gpointer data) { GstMimEnc *mimenc = GST_MIMENC (data); GstClockTime now; GstClockTimeDiff diff; GstFlowReturn ret; if (!GST_ELEMENT_CLOCK (mimenc)) { GST_ERROR_OBJECT (mimenc, "Element has no clock"); gst_pad_pause_task (mimenc->srcpad); return; } GST_OBJECT_LOCK (mimenc); if (mimenc->stop_paused_mode) { GST_OBJECT_UNLOCK (mimenc); goto stop_task; } now = gst_clock_get_time (GST_ELEMENT_CLOCK (mimenc)); diff = now - GST_ELEMENT_CAST (mimenc)->base_time - mimenc->last_buffer; if (diff < 0) diff = 0; if (diff > 3.95 * GST_SECOND) { GstBuffer *buffer = gst_mimenc_create_tcp_header (mimenc, 0, mimenc->last_buffer + 4 * GST_SECOND, FALSE, TRUE); GstEvent *event = NULL; mimenc->last_buffer += 4 * GST_SECOND; if (mimenc->need_newsegment) { event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0); mimenc->need_newsegment = FALSE; } GST_OBJECT_UNLOCK (mimenc); GST_LOG_OBJECT (mimenc, "Haven't had an incoming buffer in 4 seconds," " sending out a pause frame"); if (event) { if (!gst_pad_push_event (mimenc->srcpad, event)) GST_WARNING_OBJECT (mimenc, "Failed to push NEWSEGMENT event"); } ret = gst_pad_push (mimenc->srcpad, buffer); if (ret < 0) { GST_WARNING_OBJECT (mimenc, "Error pushing paused header: %s", gst_flow_get_name (ret)); goto stop_task; } } else { GstClockTime next_stop; GstClockID id; next_stop = now + (4 * GST_SECOND - MIN (diff, 4 * GST_SECOND)); id = gst_clock_new_single_shot_id (GST_ELEMENT_CLOCK (mimenc), next_stop); if (mimenc->stop_paused_mode) { GST_OBJECT_UNLOCK (mimenc); goto stop_task; } mimenc->clock_id = id; GST_OBJECT_UNLOCK (mimenc); gst_clock_id_wait (id, NULL); GST_OBJECT_LOCK (mimenc); mimenc->clock_id = NULL; GST_OBJECT_UNLOCK (mimenc); gst_clock_id_unref (id); } return; stop_task: gst_pad_pause_task (mimenc->srcpad); }
static gboolean gst_base_video_encoder_sink_event (GstPad * pad, GstEvent * event) { GstBaseVideoEncoder *base_video_encoder; GstBaseVideoEncoderClass *base_video_encoder_class; gboolean ret = FALSE; base_video_encoder = GST_BASE_VIDEO_ENCODER (gst_pad_get_parent (pad)); base_video_encoder_class = GST_BASE_VIDEO_ENCODER_GET_CLASS (base_video_encoder); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: { if (base_video_encoder_class->finish) { base_video_encoder_class->finish (base_video_encoder); } ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), event); } break; case GST_EVENT_NEWSEGMENT: { gboolean update; double rate; double applied_rate; GstFormat format; gint64 start; gint64 stop; gint64 position; gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, &format, &start, &stop, &position); if (format != GST_FORMAT_TIME) goto newseg_wrong_format; GST_DEBUG ("new segment %" GST_TIME_FORMAT " %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (position)); gst_segment_set_newsegment_full (&GST_BASE_VIDEO_CODEC (base_video_encoder)->segment, update, rate, applied_rate, format, start, stop, position); ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), event); } break; case GST_EVENT_CUSTOM_DOWNSTREAM: { const GstStructure *s; s = gst_event_get_structure (event); if (gst_structure_has_name (s, "GstForceKeyUnit")) { GST_OBJECT_LOCK (base_video_encoder); base_video_encoder->force_keyframe = TRUE; GST_OBJECT_UNLOCK (base_video_encoder); gst_event_unref (event); ret = GST_FLOW_OK; } else { ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), event); } break; } default: /* FIXME this changes the order of events */ ret = gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), event); break; } done: gst_object_unref (base_video_encoder); return ret; newseg_wrong_format: { GST_DEBUG_OBJECT (base_video_encoder, "received non TIME newsegment"); gst_event_unref (event); goto done; } }
static gboolean gst_musepackdec_src_query (GstPad * pad, GstQuery * query) { GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (gst_pad_get_parent (pad)); GstFormat format; gboolean res = FALSE; gint samplerate; samplerate = g_atomic_int_get (&musepackdec->rate); if (samplerate == 0) goto done; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_POSITION:{ gint64 cur, cur_off; gst_query_parse_position (query, &format, NULL); GST_OBJECT_LOCK (musepackdec); cur_off = musepackdec->segment.last_stop; GST_OBJECT_UNLOCK (musepackdec); if (format == GST_FORMAT_TIME) { cur = gst_util_uint64_scale_int (cur_off, GST_SECOND, samplerate); gst_query_set_position (query, GST_FORMAT_TIME, cur); res = TRUE; } else if (format == GST_FORMAT_DEFAULT) { gst_query_set_position (query, GST_FORMAT_DEFAULT, cur_off); res = TRUE; } break; } case GST_QUERY_DURATION:{ gint64 len, len_off; gst_query_parse_duration (query, &format, NULL); GST_OBJECT_LOCK (musepackdec); len_off = musepackdec->segment.duration; GST_OBJECT_UNLOCK (musepackdec); if (format == GST_FORMAT_TIME) { len = gst_util_uint64_scale_int (len_off, GST_SECOND, samplerate); gst_query_set_duration (query, GST_FORMAT_TIME, len); res = TRUE; } else if (format == GST_FORMAT_DEFAULT) { gst_query_set_duration (query, GST_FORMAT_DEFAULT, len_off); res = TRUE; } break; } case GST_QUERY_SEEKING:{ GstFormat fmt; res = TRUE; gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL); if (fmt == GST_FORMAT_TIME || fmt == GST_FORMAT_DEFAULT) gst_query_set_seeking (query, fmt, TRUE, 0, -1); else gst_query_set_seeking (query, fmt, FALSE, -1, -1); break; } default: res = gst_pad_query_default (pad, query); break; } done: gst_object_unref (musepackdec); return res; }
static GstFlowReturn gst_audio_aggregator_aggregate (GstAggregator * agg, gboolean timeout) { /* Get all pads that have data for us and store them in a * new list. * * Calculate the current output offset/timestamp and * offset_end/timestamp_end. Allocate a silence buffer * for this and store it. * * For all pads: * 1) Once per input buffer (cached) * 1) Check discont (flag and timestamp with tolerance) * 2) If discont or new, resync. That means: * 1) Drop all start data of the buffer that comes before * the current position/offset. * 2) Calculate the offset (output segment!) that the first * frame of the input buffer corresponds to. Base this on * the running time. * * 2) If the current pad's offset/offset_end overlaps with the output * offset/offset_end, mix it at the appropiate position in the output * buffer and advance the pad's position. Remember if this pad needs * a new buffer to advance behind the output offset_end. * * 3) If we had no pad with a buffer, go EOS. * * 4) If we had at least one pad that did not advance behind output * offset_end, let collected be called again for the current * output offset/offset_end. */ GstElement *element; GstAudioAggregator *aagg; GList *iter; GstFlowReturn ret; GstBuffer *outbuf = NULL; gint64 next_offset; gint64 next_timestamp; gint rate, bpf; gboolean dropped = FALSE; gboolean is_eos = TRUE; gboolean is_done = TRUE; guint blocksize; element = GST_ELEMENT (agg); aagg = GST_AUDIO_AGGREGATOR (agg); /* Sync pad properties to the stream time */ gst_aggregator_iterate_sinkpads (agg, (GstAggregatorPadForeachFunc) sync_pad_values, NULL); GST_AUDIO_AGGREGATOR_LOCK (aagg); GST_OBJECT_LOCK (agg); /* Update position from the segment start/stop if needed */ if (agg->segment.position == -1) { if (agg->segment.rate > 0.0) agg->segment.position = agg->segment.start; else agg->segment.position = agg->segment.stop; } if (G_UNLIKELY (aagg->info.finfo->format == GST_AUDIO_FORMAT_UNKNOWN)) { if (timeout) { GST_DEBUG_OBJECT (aagg, "Got timeout before receiving any caps, don't output anything"); /* Advance position */ if (agg->segment.rate > 0.0) agg->segment.position += aagg->priv->output_buffer_duration; else if (agg->segment.position > aagg->priv->output_buffer_duration) agg->segment.position -= aagg->priv->output_buffer_duration; else agg->segment.position = 0; GST_OBJECT_UNLOCK (agg); GST_AUDIO_AGGREGATOR_UNLOCK (aagg); return GST_AGGREGATOR_FLOW_NEED_DATA; } else { GST_OBJECT_UNLOCK (agg); goto not_negotiated; } } rate = GST_AUDIO_INFO_RATE (&aagg->info); bpf = GST_AUDIO_INFO_BPF (&aagg->info); if (aagg->priv->offset == -1) { aagg->priv->offset = gst_util_uint64_scale (agg->segment.position - agg->segment.start, rate, GST_SECOND); GST_DEBUG_OBJECT (aagg, "Starting at offset %" G_GINT64_FORMAT, aagg->priv->offset); } blocksize = gst_util_uint64_scale (aagg->priv->output_buffer_duration, rate, GST_SECOND); blocksize = MAX (1, blocksize); /* for the next timestamp, use the sample counter, which will * never accumulate rounding errors */ /* FIXME: Reverse mixing does not work at all yet */ if (agg->segment.rate > 0.0) { next_offset = aagg->priv->offset + blocksize; } else { next_offset = aagg->priv->offset - blocksize; } next_timestamp = agg->segment.start + gst_util_uint64_scale (next_offset, GST_SECOND, rate); if (aagg->priv->current_buffer == NULL) { GST_OBJECT_UNLOCK (agg); aagg->priv->current_buffer = GST_AUDIO_AGGREGATOR_GET_CLASS (aagg)->create_output_buffer (aagg, blocksize); /* Be careful, some things could have changed ? */ GST_OBJECT_LOCK (agg); GST_BUFFER_FLAG_SET (aagg->priv->current_buffer, GST_BUFFER_FLAG_GAP); } outbuf = aagg->priv->current_buffer; GST_LOG_OBJECT (agg, "Starting to mix %u samples for offset %" G_GINT64_FORMAT " with timestamp %" GST_TIME_FORMAT, blocksize, aagg->priv->offset, GST_TIME_ARGS (agg->segment.position)); for (iter = element->sinkpads; iter; iter = iter->next) { GstBuffer *inbuf; GstAudioAggregatorPad *pad = (GstAudioAggregatorPad *) iter->data; GstAggregatorPad *aggpad = (GstAggregatorPad *) iter->data; gboolean drop_buf = FALSE; gboolean pad_eos = gst_aggregator_pad_is_eos (aggpad); if (!pad_eos) is_eos = FALSE; inbuf = gst_aggregator_pad_get_buffer (aggpad); GST_OBJECT_LOCK (pad); if (!inbuf) { if (timeout) { if (pad->priv->output_offset < next_offset) { gint64 diff = next_offset - pad->priv->output_offset; GST_DEBUG_OBJECT (pad, "Timeout, missing %" G_GINT64_FORMAT " frames (%" GST_TIME_FORMAT ")", diff, GST_TIME_ARGS (gst_util_uint64_scale (diff, GST_SECOND, GST_AUDIO_INFO_RATE (&aagg->info)))); } } else if (!pad_eos) { is_done = FALSE; } GST_OBJECT_UNLOCK (pad); continue; } g_assert (!pad->priv->buffer || pad->priv->buffer == inbuf); /* New buffer? */ if (!pad->priv->buffer) { /* Takes ownership of buffer */ if (!gst_audio_aggregator_fill_buffer (aagg, pad, inbuf)) { dropped = TRUE; GST_OBJECT_UNLOCK (pad); gst_aggregator_pad_drop_buffer (aggpad); continue; } } else { gst_buffer_unref (inbuf); } if (!pad->priv->buffer && !dropped && pad_eos) { GST_DEBUG_OBJECT (aggpad, "Pad is in EOS state"); GST_OBJECT_UNLOCK (pad); continue; } g_assert (pad->priv->buffer); /* This pad is lacking behind, we need to update the offset * and maybe drop the current buffer */ if (pad->priv->output_offset < aagg->priv->offset) { gint64 diff = aagg->priv->offset - pad->priv->output_offset; gint64 odiff = diff; if (pad->priv->position + diff > pad->priv->size) diff = pad->priv->size - pad->priv->position; pad->priv->position += diff; pad->priv->output_offset += diff; if (pad->priv->position == pad->priv->size) { GST_DEBUG_OBJECT (pad, "Buffer was late by %" GST_TIME_FORMAT ", dropping %" GST_PTR_FORMAT, GST_TIME_ARGS (gst_util_uint64_scale (odiff, GST_SECOND, GST_AUDIO_INFO_RATE (&aagg->info))), pad->priv->buffer); /* Buffer done, drop it */ gst_buffer_replace (&pad->priv->buffer, NULL); dropped = TRUE; GST_OBJECT_UNLOCK (pad); gst_aggregator_pad_drop_buffer (aggpad); continue; } } if (pad->priv->output_offset >= aagg->priv->offset && pad->priv->output_offset < aagg->priv->offset + blocksize && pad->priv->buffer) { GST_LOG_OBJECT (aggpad, "Mixing buffer for current offset"); drop_buf = !gst_audio_aggregator_mix_buffer (aagg, pad, pad->priv->buffer, outbuf); if (pad->priv->output_offset >= next_offset) { GST_LOG_OBJECT (pad, "Pad is at or after current offset: %" G_GUINT64_FORMAT " >= %" G_GINT64_FORMAT, pad->priv->output_offset, next_offset); } else { is_done = FALSE; } } GST_OBJECT_UNLOCK (pad); if (drop_buf) gst_aggregator_pad_drop_buffer (aggpad); } GST_OBJECT_UNLOCK (agg); if (dropped) { /* We dropped a buffer, retry */ GST_LOG_OBJECT (aagg, "A pad dropped a buffer, wait for the next one"); GST_AUDIO_AGGREGATOR_UNLOCK (aagg); return GST_AGGREGATOR_FLOW_NEED_DATA; } if (!is_done && !is_eos) { /* Get more buffers */ GST_LOG_OBJECT (aagg, "We're not done yet for the current offset, waiting for more data"); GST_AUDIO_AGGREGATOR_UNLOCK (aagg); return GST_AGGREGATOR_FLOW_NEED_DATA; } if (is_eos) { gint64 max_offset = 0; GST_DEBUG_OBJECT (aagg, "We're EOS"); GST_OBJECT_LOCK (agg); for (iter = GST_ELEMENT (agg)->sinkpads; iter; iter = iter->next) { GstAudioAggregatorPad *pad = GST_AUDIO_AGGREGATOR_PAD (iter->data); max_offset = MAX ((gint64) max_offset, (gint64) pad->priv->output_offset); } GST_OBJECT_UNLOCK (agg); /* This means EOS or nothing mixed in at all */ if (aagg->priv->offset == max_offset) { gst_buffer_replace (&aagg->priv->current_buffer, NULL); GST_AUDIO_AGGREGATOR_UNLOCK (aagg); return GST_FLOW_EOS; } if (max_offset <= next_offset) { GST_DEBUG_OBJECT (aagg, "Last buffer is incomplete: %" G_GUINT64_FORMAT " <= %" G_GINT64_FORMAT, max_offset, next_offset); next_offset = max_offset; next_timestamp = agg->segment.start + gst_util_uint64_scale (next_offset, GST_SECOND, rate); if (next_offset > aagg->priv->offset) gst_buffer_resize (outbuf, 0, (next_offset - aagg->priv->offset) * bpf); } } /* set timestamps on the output buffer */ GST_OBJECT_LOCK (agg); if (agg->segment.rate > 0.0) { GST_BUFFER_PTS (outbuf) = agg->segment.position; GST_BUFFER_OFFSET (outbuf) = aagg->priv->offset; GST_BUFFER_OFFSET_END (outbuf) = next_offset; GST_BUFFER_DURATION (outbuf) = next_timestamp - agg->segment.position; } else { GST_BUFFER_PTS (outbuf) = next_timestamp; GST_BUFFER_OFFSET (outbuf) = next_offset; GST_BUFFER_OFFSET_END (outbuf) = aagg->priv->offset; GST_BUFFER_DURATION (outbuf) = agg->segment.position - next_timestamp; } GST_OBJECT_UNLOCK (agg); /* send it out */ GST_LOG_OBJECT (aagg, "pushing outbuf %p, timestamp %" GST_TIME_FORMAT " offset %" G_GINT64_FORMAT, outbuf, GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)), GST_BUFFER_OFFSET (outbuf)); GST_AUDIO_AGGREGATOR_UNLOCK (aagg); ret = gst_aggregator_finish_buffer (agg, aagg->priv->current_buffer); aagg->priv->current_buffer = NULL; GST_LOG_OBJECT (aagg, "pushed outbuf, result = %s", gst_flow_get_name (ret)); GST_AUDIO_AGGREGATOR_LOCK (aagg); GST_OBJECT_LOCK (agg); aagg->priv->offset = next_offset; agg->segment.position = next_timestamp; /* If there was a timeout and there was a gap in data in out of the streams, * then it's a very good time to for a resync with the timestamps. */ if (timeout) { for (iter = element->sinkpads; iter; iter = iter->next) { GstAudioAggregatorPad *pad = GST_AUDIO_AGGREGATOR_PAD (iter->data); GST_OBJECT_LOCK (pad); if (pad->priv->output_offset < aagg->priv->offset) pad->priv->output_offset = -1; GST_OBJECT_UNLOCK (pad); } } GST_OBJECT_UNLOCK (agg); GST_AUDIO_AGGREGATOR_UNLOCK (aagg); return ret; /* ERRORS */ not_negotiated: { GST_AUDIO_AGGREGATOR_UNLOCK (aagg); GST_ELEMENT_ERROR (aagg, STREAM, FORMAT, (NULL), ("Unknown data received, not negotiated")); return GST_FLOW_NOT_NEGOTIATED; } }
static gboolean gst_switch_sink_commit_new_kid (GstSwitchSink * sink) { GstPad *targetpad; GstState kid_state; GstElement *new_kid, *old_kid; gboolean is_fakesink = FALSE; GstBus *bus; /* need locking around member accesses */ GST_OBJECT_LOCK (sink); /* If we're currently changing state, set the child to the next state * we're transitioning too, rather than our current state which is * about to change */ if (GST_STATE_NEXT (sink) != GST_STATE_VOID_PENDING) kid_state = GST_STATE_NEXT (sink); else kid_state = GST_STATE (sink); new_kid = sink->new_kid ? gst_object_ref (sink->new_kid) : NULL; sink->new_kid = NULL; GST_OBJECT_UNLOCK (sink); /* Fakesink by default if NULL is passed as the new child */ if (new_kid == NULL) { GST_DEBUG_OBJECT (sink, "Replacing kid with fakesink"); new_kid = gst_element_factory_make ("fakesink", "testsink"); if (new_kid == NULL) { GST_ERROR_OBJECT (sink, "Failed to create fakesink"); return FALSE; } /* Add a reference, as it would if the element came from sink->new_kid */ gst_object_ref (new_kid); g_object_set (new_kid, "sync", TRUE, NULL); is_fakesink = TRUE; } else { GST_DEBUG_OBJECT (sink, "Setting new kid"); } /* set temporary bus of our own to catch error messages from the child * (could we just set our own bus on it, or would the state change messages * from the not-yet-added element confuse the state change algorithm? Let's * play it safe for now) */ bus = gst_bus_new (); gst_element_set_bus (new_kid, bus); gst_object_unref (bus); if (gst_element_set_state (new_kid, kid_state) == GST_STATE_CHANGE_FAILURE) { GstMessage *msg; /* check if child posted an error message and if so re-post it on our bus * so that the application gets to see a decent error and not our generic * fallback error message which is completely indecipherable to the user */ msg = gst_bus_pop_filtered (GST_ELEMENT_BUS (new_kid), GST_MESSAGE_ERROR); if (msg) { GST_INFO_OBJECT (sink, "Forwarding kid error: %" GST_PTR_FORMAT, msg); gst_element_post_message (GST_ELEMENT (sink), msg); } GST_ELEMENT_ERROR (sink, CORE, STATE_CHANGE, (NULL), ("Failed to set state on new child.")); gst_element_set_bus (new_kid, NULL); gst_object_unref (new_kid); return FALSE; } gst_element_set_bus (new_kid, NULL); gst_bin_add (GST_BIN (sink), new_kid); /* Now, replace the existing child */ GST_OBJECT_LOCK (sink); old_kid = sink->kid; sink->kid = new_kid; /* Mark whether a custom kid or fakesink has been installed */ sink->have_kid = !is_fakesink; GST_OBJECT_UNLOCK (sink); /* kill old element */ if (old_kid) { GST_DEBUG_OBJECT (sink, "Removing old kid %" GST_PTR_FORMAT, old_kid); gst_element_set_state (old_kid, GST_STATE_NULL); gst_bin_remove (GST_BIN (sink), old_kid); gst_object_unref (old_kid); /* Don't lose the SINK flag */ GST_OBJECT_FLAG_SET (sink, GST_ELEMENT_IS_SINK); } /* re-attach ghostpad */ GST_DEBUG_OBJECT (sink, "Creating new ghostpad"); targetpad = gst_element_get_static_pad (sink->kid, "sink"); gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad); gst_object_unref (targetpad); GST_DEBUG_OBJECT (sink, "done changing child of switchsink"); /* FIXME: Push new-segment info and pre-roll buffer(s) into the kid */ return TRUE; }
static gboolean gst_audio_aggregator_mix_buffer (GstAudioAggregator * aagg, GstAudioAggregatorPad * pad, GstBuffer * inbuf, GstBuffer * outbuf) { guint overlap; guint out_start; gboolean filled; guint blocksize; guint in_offset; gboolean pad_changed = FALSE; blocksize = gst_util_uint64_scale (aagg->priv->output_buffer_duration, GST_AUDIO_INFO_RATE (&aagg->info), GST_SECOND); blocksize = MAX (1, blocksize); /* Overlap => mix */ if (aagg->priv->offset < pad->priv->output_offset) out_start = pad->priv->output_offset - aagg->priv->offset; else out_start = 0; overlap = pad->priv->size - pad->priv->position; if (overlap > blocksize - out_start) overlap = blocksize - out_start; if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) { /* skip gap buffer */ GST_LOG_OBJECT (pad, "skipping GAP buffer"); pad->priv->output_offset += pad->priv->size - pad->priv->position; pad->priv->position = pad->priv->size; gst_buffer_replace (&pad->priv->buffer, NULL); return FALSE; } gst_buffer_ref (inbuf); in_offset = pad->priv->position; GST_OBJECT_UNLOCK (pad); GST_OBJECT_UNLOCK (aagg); filled = GST_AUDIO_AGGREGATOR_GET_CLASS (aagg)->aggregate_one_buffer (aagg, pad, inbuf, in_offset, outbuf, out_start, overlap); GST_OBJECT_LOCK (aagg); GST_OBJECT_LOCK (pad); pad_changed = (inbuf != pad->priv->buffer); gst_buffer_unref (inbuf); if (filled) GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_GAP); if (pad_changed) return FALSE; pad->priv->position += overlap; pad->priv->output_offset += overlap; if (pad->priv->position == pad->priv->size) { /* Buffer done, drop it */ gst_buffer_replace (&pad->priv->buffer, NULL); GST_LOG_OBJECT (pad, "Finished mixing buffer, waiting for next"); return FALSE; } return TRUE; }
static void debug_dump_pad (GstPad * pad, const gchar * color_name, const gchar * element_name, GstDebugGraphDetails details, GString * str, const gint indent) { GstPadTemplate *pad_templ; GstPadPresence presence; gchar *pad_name, *param_name = NULL; const gchar *style_name; static const char *const ignore_propnames[] = { "parent", "direction", "template", "caps", NULL }; const gchar *spc = MAKE_INDENT (indent); pad_name = debug_dump_make_object_name (GST_OBJECT (pad)); /* pad availability */ style_name = "filled,solid"; if ((pad_templ = gst_pad_get_pad_template (pad))) { presence = GST_PAD_TEMPLATE_PRESENCE (pad_templ); gst_object_unref (pad_templ); if (presence == GST_PAD_SOMETIMES) { style_name = "filled,dotted"; } else if (presence == GST_PAD_REQUEST) { style_name = "filled,dashed"; } } param_name = debug_dump_get_object_params (G_OBJECT (pad), details, ignore_propnames); if (details & GST_DEBUG_GRAPH_SHOW_STATES) { gchar pad_flags[4]; const gchar *activation_mode = "-><"; const gchar *task_mode = ""; GstTask *task; GST_OBJECT_LOCK (pad); task = GST_PAD_TASK (pad); if (task) { switch (gst_task_get_state (task)) { case GST_TASK_STARTED: task_mode = "[T]"; break; case GST_TASK_PAUSED: task_mode = "[t]"; break; default: /* Invalid task state, ignoring */ break; } } GST_OBJECT_UNLOCK (pad); /* check if pad flags */ pad_flags[0] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLAG_BLOCKED) ? 'B' : 'b'; pad_flags[1] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLAG_FLUSHING) ? 'F' : 'f'; pad_flags[2] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLAG_BLOCKING) ? 'B' : 'b'; pad_flags[3] = '\0'; g_string_append_printf (str, "%s %s_%s [color=black, fillcolor=\"%s\", label=\"%s%s\\n[%c][%s]%s\", height=\"0.2\", style=\"%s\"];\n", spc, element_name, pad_name, color_name, GST_OBJECT_NAME (pad), (param_name ? param_name : ""), activation_mode[pad->mode], pad_flags, task_mode, style_name); } else { g_string_append_printf (str, "%s %s_%s [color=black, fillcolor=\"%s\", label=\"%s%s\", height=\"0.2\", style=\"%s\"];\n", spc, element_name, pad_name, color_name, GST_OBJECT_NAME (pad), (param_name ? param_name : ""), style_name); } g_free (param_name); g_free (pad_name); }
static gpointer gst_curl_base_sink_transfer_thread_func (gpointer data) { GstCurlBaseSink *sink = (GstCurlBaseSink *) data; GstCurlBaseSinkClass *klass = GST_CURL_BASE_SINK_GET_CLASS (sink); GstFlowReturn ret; gboolean data_available; GST_LOG ("transfer thread started"); GST_OBJECT_LOCK (sink); if (!gst_curl_base_sink_transfer_setup_unlocked (sink)) { /* no need to set sink->error, as it is set by the called function */ sink->flow_ret = GST_FLOW_ERROR; goto done; } while (!sink->transfer_thread_close && sink->flow_ret == GST_FLOW_OK) { /* we are working on a new file, clearing flag and setting a new file * name */ sink->new_file = FALSE; /* wait for data to arrive for this new file, if we get a new file name * again before getting data we will simply skip transferring anything * for this file and go directly to the new file */ data_available = gst_curl_base_sink_wait_for_data_unlocked (sink); if (data_available) { if (G_UNLIKELY (!klass->set_protocol_dynamic_options_unlocked (sink))) { sink->error = g_strdup ("unexpected state"); sink->flow_ret = GST_FLOW_ERROR; goto done; } } /* stay unlocked while handling the actual transfer */ GST_OBJECT_UNLOCK (sink); if (data_available) { GST_LOG ("have data"); if (!gst_curl_base_sink_is_live (sink)) { /* prepare transfer if needed */ if (klass->prepare_transfer) { GST_OBJECT_LOCK (sink); if (!klass->prepare_transfer (sink)) { sink->flow_ret = GST_FLOW_ERROR; goto done; } GST_OBJECT_UNLOCK (sink); } GST_LOG ("adding handle"); curl_multi_add_handle (sink->multi_handle, sink->curl); } /* Start driving the transfer. */ klass->handle_transfer (sink); /* easy handle will be possibly re-used for next transfer, thus it needs * to be removed from the multi stack and re-added again */ if (!gst_curl_base_sink_is_live (sink)) { GST_LOG ("removing handle"); curl_multi_remove_handle (sink->multi_handle, sink->curl); } } else { GST_LOG ("have no data yet"); } /* lock again before looping to check the thread closed flag */ GST_OBJECT_LOCK (sink); } if (sink->is_live) { GST_LOG ("removing handle"); curl_multi_remove_handle (sink->multi_handle, sink->curl); } done: /* extract the error code so the lock does not have to be * taken when calling the functions below that take the lock * on their own */ ret = sink->flow_ret; GST_OBJECT_UNLOCK (sink); /* if there is a flow error, always notify the render function so it * can return the flow error up along the pipeline. as an error has * occurred there is no response to receive, so notify the event function * so it doesn't block indefinitely waiting for a response. */ if (ret != GST_FLOW_OK) { gst_curl_base_sink_data_sent_notify (sink); gst_curl_base_sink_got_response_notify (sink); } GST_DEBUG ("exit thread func - transfer thread close flag: %d", sink->transfer_thread_close); return NULL; }
static GstFlowReturn gst_shm_src_create (GstPushSrc * psrc, GstBuffer ** outbuf) { GstShmSrc *self = GST_SHM_SRC (psrc); gchar *buf = NULL; int rv = 0; struct GstShmBuffer *gsb; do { if (gst_poll_wait (self->poll, GST_CLOCK_TIME_NONE) < 0) { if (errno == EBUSY) return GST_FLOW_WRONG_STATE; GST_ELEMENT_ERROR (self, RESOURCE, READ, ("Failed to read from shmsrc"), ("Poll failed on fd: %s", strerror (errno))); return GST_FLOW_ERROR; } if (self->unlocked) return GST_FLOW_WRONG_STATE; if (gst_poll_fd_has_closed (self->poll, &self->pollfd)) { GST_ELEMENT_ERROR (self, RESOURCE, READ, ("Failed to read from shmsrc"), ("Control socket has closed")); return GST_FLOW_ERROR; } if (gst_poll_fd_has_error (self->poll, &self->pollfd)) { GST_ELEMENT_ERROR (self, RESOURCE, READ, ("Failed to read from shmsrc"), ("Control socket has error")); return GST_FLOW_ERROR; } if (gst_poll_fd_can_read (self->poll, &self->pollfd)) { buf = NULL; GST_LOG_OBJECT (self, "Reading from pipe"); GST_OBJECT_LOCK (self); rv = sp_client_recv (self->pipe->pipe, &buf); GST_OBJECT_UNLOCK (self); if (rv < 0) { GST_ELEMENT_ERROR (self, RESOURCE, READ, ("Failed to read from shmsrc"), ("Error reading control data: %d", rv)); return GST_FLOW_ERROR; } } } while (buf == NULL); GST_LOG_OBJECT (self, "Got buffer %p of size %d", buf, rv); gsb = g_slice_new0 (struct GstShmBuffer); gsb->buf = buf; gsb->pipe = self->pipe; gst_shm_pipe_inc (self->pipe); *outbuf = gst_buffer_new (); GST_BUFFER_FLAG_SET (*outbuf, GST_BUFFER_FLAG_READONLY); GST_BUFFER_DATA (*outbuf) = (guint8 *) buf; GST_BUFFER_SIZE (*outbuf) = rv; GST_BUFFER_MALLOCDATA (*outbuf) = (guint8 *) gsb; GST_BUFFER_FREE_FUNC (*outbuf) = free_buffer; return GST_FLOW_OK; }
static void gst_curl_base_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstCurlBaseSink *sink; GstState cur_state; g_return_if_fail (GST_IS_CURL_BASE_SINK (object)); sink = GST_CURL_BASE_SINK (object); gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0); if (cur_state != GST_STATE_PLAYING && cur_state != GST_STATE_PAUSED) { GST_OBJECT_LOCK (sink); switch (prop_id) { case PROP_LOCATION: g_free (sink->url); sink->url = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "url set to %s", sink->url); break; case PROP_USER_NAME: g_free (sink->user); sink->user = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "user set to %s", sink->user); break; case PROP_USER_PASSWD: g_free (sink->passwd); sink->passwd = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "passwd set to %s", sink->passwd); break; case PROP_FILE_NAME: g_free (sink->file_name); sink->file_name = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "file_name set to %s", sink->file_name); break; case PROP_TIMEOUT: sink->timeout = g_value_get_int (value); GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->timeout); break; case PROP_QOS_DSCP: sink->qos_dscp = g_value_get_int (value); gst_curl_base_sink_setup_dscp_unlocked (sink); GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->qos_dscp); break; default: GST_DEBUG_OBJECT (sink, "invalid property id %d", prop_id); break; } GST_OBJECT_UNLOCK (sink); return; } /* in PLAYING or PAUSED state */ GST_OBJECT_LOCK (sink); switch (prop_id) { case PROP_FILE_NAME: g_free (sink->file_name); sink->file_name = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "file_name set to %s", sink->file_name); gst_curl_base_sink_new_file_notify_unlocked (sink); break; case PROP_TIMEOUT: sink->timeout = g_value_get_int (value); GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->timeout); break; case PROP_QOS_DSCP: sink->qos_dscp = g_value_get_int (value); gst_curl_base_sink_setup_dscp_unlocked (sink); GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->qos_dscp); break; default: GST_WARNING_OBJECT (sink, "cannot set property when PLAYING"); break; } GST_OBJECT_UNLOCK (sink); }
static void gst_net_client_clock_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object); gboolean update = FALSE; switch (prop_id) { case PROP_ADDRESS: GST_OBJECT_LOCK (self); g_free (self->priv->address); self->priv->address = g_value_dup_string (value); if (self->priv->address == NULL) self->priv->address = g_strdup (DEFAULT_ADDRESS); GST_OBJECT_UNLOCK (self); break; case PROP_PORT: GST_OBJECT_LOCK (self); self->priv->port = g_value_get_int (value); GST_OBJECT_UNLOCK (self); break; case PROP_ROUNDTRIP_LIMIT: GST_OBJECT_LOCK (self); self->priv->roundtrip_limit = g_value_get_uint64 (value); GST_OBJECT_UNLOCK (self); update = TRUE; break; case PROP_MINIMUM_UPDATE_INTERVAL: GST_OBJECT_LOCK (self); self->priv->minimum_update_interval = g_value_get_uint64 (value); GST_OBJECT_UNLOCK (self); update = TRUE; break; case PROP_BUS: GST_OBJECT_LOCK (self); if (self->priv->bus) gst_object_unref (self->priv->bus); self->priv->bus = g_value_dup_object (value); GST_OBJECT_UNLOCK (self); update = TRUE; break; case PROP_BASE_TIME: self->priv->base_time = g_value_get_uint64 (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } if (update && self->priv->internal_clock) { GList *l; G_LOCK (clocks_lock); for (l = clocks; l; l = l->next) { ClockCache *cache = l->data; if (cache->clock == self->priv->internal_clock) { update_clock_cache (cache); } } G_UNLOCK (clocks_lock); } }
static GstFlowReturn gst_timestampoverlay_transform_frame_ip (GstVideoFilter * filter, GstVideoFrame * frame) { GstTimeStampOverlay *overlay = GST_TIMESTAMPOVERLAY (filter); GST_DEBUG_OBJECT (overlay, "transform_frame_ip"); GstClockTime buffer_time, stream_time, running_time, clock_time, latency, render_time, render_realtime; GstSegment *segment = &GST_BASE_TRANSFORM (overlay)->segment; unsigned char * imgdata; buffer_time = GST_BUFFER_TIMESTAMP (frame->buffer); if (!GST_CLOCK_TIME_IS_VALID (buffer_time)) { GST_DEBUG_OBJECT (filter, "Can't draw timestamps: buffer timestamp is " "invalid"); return GST_FLOW_OK; } if (frame->info.stride[0] < (8 * frame->info.finfo->pixel_stride[0] * 64)) { GST_WARNING_OBJECT (filter, "Can't draw timestamps: video-frame is to narrow"); return GST_FLOW_OK; } GST_DEBUG ("buffer with timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (buffer_time)); stream_time = gst_segment_to_stream_time (segment, GST_FORMAT_TIME, buffer_time); running_time = gst_segment_to_running_time (segment, GST_FORMAT_TIME, buffer_time); clock_time = running_time + gst_element_get_base_time (GST_ELEMENT (overlay)); latency = overlay->latency; if (GST_CLOCK_TIME_IS_VALID (latency)) render_time = clock_time + latency; else render_time = clock_time; GST_OBJECT_LOCK (overlay->realtime_clock); render_realtime = gst_clock_unadjust_unlocked ( overlay->realtime_clock, render_time); GST_OBJECT_UNLOCK (overlay->realtime_clock); imgdata = frame->data[0]; /* Centre Vertically: */ imgdata += (frame->info.height - 6 * 8) * frame->info.stride[0] / 2; /* Centre Horizontally: */ imgdata += (frame->info.width - 64 * 8) * frame->info.finfo->pixel_stride[0] / 2; draw_timestamp (0, buffer_time, imgdata, frame->info.stride[0], frame->info.finfo->pixel_stride[0]); draw_timestamp (1, stream_time, imgdata, frame->info.stride[0], frame->info.finfo->pixel_stride[0]); draw_timestamp (2, running_time, imgdata, frame->info.stride[0], frame->info.finfo->pixel_stride[0]); draw_timestamp (3, clock_time, imgdata, frame->info.stride[0], frame->info.finfo->pixel_stride[0]); draw_timestamp (4, render_time, imgdata, frame->info.stride[0], frame->info.finfo->pixel_stride[0]); draw_timestamp (5, render_realtime, imgdata, frame->info.stride[0], frame->info.finfo->pixel_stride[0]); return GST_FLOW_OK; }
static void gst_net_client_clock_constructed (GObject * object) { GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object); GstClock *internal_clock; GstClockTime internal; GList *l; ClockCache *cache = NULL; G_OBJECT_CLASS (gst_net_client_clock_parent_class)->constructed (object); G_LOCK (clocks_lock); for (l = clocks; l; l = l->next) { ClockCache *tmp = l->data; GstNetClientInternalClock *internal_clock = GST_NET_CLIENT_INTERNAL_CLOCK (tmp->clock); if (strcmp (internal_clock->address, self->priv->address) == 0 && internal_clock->port == self->priv->port) { cache = tmp; if (cache->remove_id) { gst_clock_id_unschedule (cache->remove_id); cache->remove_id = NULL; } break; } } if (!cache) { cache = g_new0 (ClockCache, 1); cache->clock = g_object_new (GST_TYPE_NET_CLIENT_INTERNAL_CLOCK, "address", self->priv->address, "port", self->priv->port, "is-ntp", self->priv->is_ntp, NULL); clocks = g_list_prepend (clocks, cache); } cache->clocks = g_list_prepend (cache->clocks, self); GST_OBJECT_LOCK (cache->clock); if (gst_clock_is_synced (cache->clock)) gst_clock_set_synced (GST_CLOCK (self), TRUE); self->priv->synced_id = g_signal_connect (cache->clock, "synced", G_CALLBACK (gst_net_client_clock_synced_cb), self); GST_OBJECT_UNLOCK (cache->clock); G_UNLOCK (clocks_lock); self->priv->internal_clock = internal_clock = cache->clock; /* gst_clock_get_time() values are guaranteed to be increasing. because no one * has called get_time on this clock yet we are free to adjust to any value * without worrying about worrying about MAX() issues with the clock's * internal time. */ /* update our internal time so get_time() give something around base_time. assume that the rate is 1 in the beginning. */ internal = gst_clock_get_internal_time (internal_clock); gst_clock_set_calibration (internal_clock, internal, self->priv->base_time, 1, 1); { GstClockTime now = gst_clock_get_time (internal_clock); if (GST_CLOCK_DIFF (now, self->priv->base_time) > 0 || GST_CLOCK_DIFF (now, self->priv->base_time + GST_SECOND) < 0) { g_warning ("unable to set the base time, expect sync problems!"); } } /* all systems go, cap'n */ }
static GstFlowReturn gst_goom_chain (GstPad * pad, GstBuffer * buffer) { GstGoom *goom; GstFlowReturn ret; GstBuffer *outbuf = NULL; goom = GST_GOOM (gst_pad_get_parent (pad)); /* If we don't have an output format yet, preallocate a buffer to try and * set one */ if (GST_PAD_CAPS (goom->srcpad) == NULL) { ret = get_buffer (goom, &outbuf); if (ret != GST_FLOW_OK) { gst_buffer_unref (buffer); goto beach; } } /* don't try to combine samples from discont buffer */ if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { gst_adapter_clear (goom->adapter); goom->next_ts = -1; } /* Match timestamps from the incoming audio */ if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE) goom->next_ts = GST_BUFFER_TIMESTAMP (buffer); GST_DEBUG_OBJECT (goom, "Input buffer has %d samples, time=%" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer) / goom->bps, GST_BUFFER_TIMESTAMP (buffer)); /* Collect samples until we have enough for an output frame */ gst_adapter_push (goom->adapter, buffer); ret = GST_FLOW_OK; while (TRUE) { const guint16 *data; gboolean need_skip; guchar *out_frame; gint i, c; guint avail, to_flush; Message m; avail = gst_adapter_available (goom->adapter); GST_DEBUG_OBJECT (goom, "avail now %u", avail); /* we need GOOM_SAMPLES to get a meaningful result from goom. */ if (avail < (GOOM_SAMPLES * goom->bps)) break; /* we also need enough samples to produce one frame at least */ if (avail < goom->bpf) break; GST_DEBUG_OBJECT (goom, "processing buffer"); if (goom->next_ts != -1) { gint64 qostime; qostime = gst_segment_to_running_time (&goom->segment, GST_FORMAT_TIME, goom->next_ts); GST_OBJECT_LOCK (goom); /* check for QoS, don't compute buffers that are known to be late */ need_skip = goom->earliest_time != -1 && qostime <= goom->earliest_time; GST_OBJECT_UNLOCK (goom); if (need_skip) { GST_WARNING_OBJECT (goom, "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (goom->earliest_time)); goto skip; } } /* get next GOOM_SAMPLES, we have at least this amount of samples */ data = (const guint16 *) gst_adapter_peek (goom->adapter, GOOM_SAMPLES * goom->bps); if (goom->channels == 2) { for (i = 0; i < GOOM_SAMPLES; i++) { goom->datain[0][i] = *data++; goom->datain[1][i] = *data++; } } else { for (i = 0; i < GOOM_SAMPLES; i++) { goom->datain[0][i] = *data; goom->datain[1][i] = *data++; } } /* alloc a buffer if we don't have one yet, this happens * when we pushed a buffer in this while loop before */ if (outbuf == NULL) { ret = get_buffer (goom, &outbuf); if (ret != GST_FLOW_OK) { goto beach; } } GST_BUFFER_TIMESTAMP (outbuf) = goom->next_ts; GST_BUFFER_DURATION (outbuf) = goom->duration; GST_BUFFER_SIZE (outbuf) = goom->outsize; //gst_spectrum_transform_ip(gstSpectrum,buffer); //print_spectrum_message(gstSpectrum); //readMessage(&m); //c = m.magnitude[0] + m.magnitude[1] + m.magnitude[2] + m.magnitude[3] + m.magnitude[4]; //if (c != 0) { /*printf("\n\n ["); for (i = 0; i < 5; i++) printf("%f $ ", m.magnitude[i]); printf("] \n\n");*/ /*g_print ("Goom: %" GST_TIME_FORMAT ", message received: %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (goom->next_ts), GST_TIME_ARGS (m.timestamp));*/ //} out_frame = (guchar *) goom_update (goom->plugin, goom->datain, 0, 0); memcpy (GST_BUFFER_DATA (outbuf), out_frame, goom->outsize); GST_DEBUG ("Pushing frame with time=%" GST_TIME_FORMAT ", duration=%" GST_TIME_FORMAT, GST_TIME_ARGS (goom->next_ts), GST_TIME_ARGS (goom->duration)); ret = gst_pad_push (goom->srcpad, outbuf); outbuf = NULL; skip: /* interpollate next timestamp */ if (goom->next_ts != -1) goom->next_ts += goom->duration; /* Now flush the samples we needed for this frame, which might be more than * the samples we used (GOOM_SAMPLES). */ to_flush = goom->bpf; GST_DEBUG_OBJECT (goom, "finished frame, flushing %u bytes from input", to_flush); gst_adapter_flush (goom->adapter, to_flush); if (ret != GST_FLOW_OK) break; } if (outbuf != NULL) gst_buffer_unref (outbuf); beach: gst_object_unref (goom); return ret; }
static void gst_net_client_internal_clock_observe_times (GstNetClientInternalClock * self, GstClockTime local_1, GstClockTime remote_1, GstClockTime remote_2, GstClockTime local_2) { GstClockTime current_timeout = 0; GstClockTime local_avg, remote_avg; gdouble r_squared; GstClock *clock; GstClockTime rtt, rtt_limit, min_update_interval; /* Use for discont tracking */ GstClockTime time_before = 0; GstClockTime min_guess = 0; GstClockTimeDiff time_discont = 0; gboolean synched, now_synched; GstClockTime internal_time, external_time, rate_num, rate_den; GstClockTime orig_internal_time, orig_external_time, orig_rate_num, orig_rate_den; GstClockTime max_discont; GstClockTime last_rtts[MEDIAN_PRE_FILTERING_WINDOW]; GstClockTime median; gint i; GST_OBJECT_LOCK (self); rtt_limit = self->roundtrip_limit; GST_LOG_OBJECT (self, "local1 %" G_GUINT64_FORMAT " remote1 %" G_GUINT64_FORMAT " remote2 %" G_GUINT64_FORMAT " local2 %" G_GUINT64_FORMAT, local_1, remote_1, remote_2, local_2); /* If the server told us a poll interval and it's bigger than the * one configured via the property, use the server's */ if (self->last_remote_poll_interval != GST_CLOCK_TIME_NONE && self->last_remote_poll_interval > self->minimum_update_interval) min_update_interval = self->last_remote_poll_interval; else min_update_interval = self->minimum_update_interval; GST_OBJECT_UNLOCK (self); if (local_2 < local_1) { GST_LOG_OBJECT (self, "Dropping observation: receive time %" GST_TIME_FORMAT " < send time %" GST_TIME_FORMAT, GST_TIME_ARGS (local_1), GST_TIME_ARGS (local_2)); goto bogus_observation; } if (remote_2 < remote_1) { GST_LOG_OBJECT (self, "Dropping observation: remote receive time %" GST_TIME_FORMAT " < send time %" GST_TIME_FORMAT, GST_TIME_ARGS (remote_1), GST_TIME_ARGS (remote_2)); goto bogus_observation; } /* The round trip time is (assuming symmetric path delays) * delta = (local_2 - local_1) - (remote_2 - remote_1) */ rtt = GST_CLOCK_DIFF (local_1, local_2) - GST_CLOCK_DIFF (remote_1, remote_2); if ((rtt_limit > 0) && (rtt > rtt_limit)) { GST_LOG_OBJECT (self, "Dropping observation: RTT %" GST_TIME_FORMAT " > limit %" GST_TIME_FORMAT, GST_TIME_ARGS (rtt), GST_TIME_ARGS (rtt_limit)); goto bogus_observation; } for (i = 1; i < MEDIAN_PRE_FILTERING_WINDOW; i++) self->last_rtts[i - 1] = self->last_rtts[i]; self->last_rtts[i - 1] = rtt; if (self->last_rtts_missing) { self->last_rtts_missing--; } else { memcpy (&last_rtts, &self->last_rtts, sizeof (last_rtts)); g_qsort_with_data (&last_rtts, MEDIAN_PRE_FILTERING_WINDOW, sizeof (GstClockTime), (GCompareDataFunc) compare_clock_time, NULL); median = last_rtts[MEDIAN_PRE_FILTERING_WINDOW / 2]; /* FIXME: We might want to use something else here, like only allowing * things in the interquartile range, or also filtering away delays that * are too small compared to the median. This here worked well enough * in tests so far. */ if (rtt > 2 * median) { GST_LOG_OBJECT (self, "Dropping observation, long RTT %" GST_TIME_FORMAT " > 2 * median %" GST_TIME_FORMAT, GST_TIME_ARGS (rtt), GST_TIME_ARGS (median)); goto bogus_observation; } } /* Track an average round trip time, for a bit of smoothing */ /* Always update before discarding a sample, so genuine changes in * the network get picked up, eventually */ if (self->rtt_avg == GST_CLOCK_TIME_NONE) self->rtt_avg = rtt; else if (rtt < self->rtt_avg) /* Shorter RTTs carry more weight than longer */ self->rtt_avg = (3 * self->rtt_avg + rtt) / 4; else self->rtt_avg = (15 * self->rtt_avg + rtt) / 16; if (rtt > 2 * self->rtt_avg) { GST_LOG_OBJECT (self, "Dropping observation, long RTT %" GST_TIME_FORMAT " > 2 * avg %" GST_TIME_FORMAT, GST_TIME_ARGS (rtt), GST_TIME_ARGS (self->rtt_avg)); goto bogus_observation; } /* The difference between the local and remote clock (again assuming * symmetric path delays): * * local_1 + delta / 2 - remote_1 = theta * or * local_2 - delta / 2 - remote_2 = theta * * which gives after some simple algebraic transformations: * * (remote_1 - local_1) + (remote_2 - local_2) * theta = ------------------------------------------- * 2 * * * Thus remote time at local_avg is equal to: * * local_avg + theta = * * local_1 + local_2 (remote_1 - local_1) + (remote_2 - local_2) * ----------------- + ------------------------------------------- * 2 2 * * = * * remote_1 + remote_2 * ------------------- = remote_avg * 2 * * We use this for our clock estimation, i.e. local_avg at remote clock * being the same as remote_avg. */ local_avg = (local_2 + local_1) / 2; remote_avg = (remote_2 + remote_1) / 2; GST_LOG_OBJECT (self, "remoteavg %" G_GUINT64_FORMAT " localavg %" G_GUINT64_FORMAT, remote_avg, local_avg); clock = GST_CLOCK_CAST (self); /* Store what the clock produced as 'now' before this update */ gst_clock_get_calibration (GST_CLOCK_CAST (self), &orig_internal_time, &orig_external_time, &orig_rate_num, &orig_rate_den); internal_time = orig_internal_time; external_time = orig_external_time; rate_num = orig_rate_num; rate_den = orig_rate_den; min_guess = gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_1, internal_time, external_time, rate_num, rate_den); time_before = gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_2, internal_time, external_time, rate_num, rate_den); /* Maximum discontinuity, when we're synched with the master. Could make this a property, * but this value seems to work fine */ max_discont = self->rtt_avg / 4; /* If the remote observation was within a max_discont window around our min/max estimates, we're synched */ synched = (GST_CLOCK_DIFF (remote_avg, min_guess) < (GstClockTimeDiff) (max_discont) && GST_CLOCK_DIFF (time_before, remote_avg) < (GstClockTimeDiff) (max_discont)); if (gst_clock_add_observation_unapplied (GST_CLOCK_CAST (self), local_avg, remote_avg, &r_squared, &internal_time, &external_time, &rate_num, &rate_den)) { /* Now compare the difference (discont) in the clock * after this observation */ time_discont = GST_CLOCK_DIFF (time_before, gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_2, internal_time, external_time, rate_num, rate_den)); /* If we were in sync with the remote clock, clamp the allowed * discontinuity to within quarter of one RTT. In sync means our send/receive estimates * of remote time correctly windowed the actual remote time observation */ if (synched && ABS (time_discont) > max_discont) { GstClockTimeDiff offset; GST_DEBUG_OBJECT (clock, "Too large a discont, clamping to 1/4 average RTT = %" GST_TIME_FORMAT, GST_TIME_ARGS (max_discont)); if (time_discont > 0) { /* Too large a forward step - add a -ve offset */ offset = max_discont - time_discont; if (-offset > external_time) external_time = 0; else external_time += offset; } else { /* Too large a backward step - add a +ve offset */ offset = -(max_discont + time_discont); external_time += offset; } time_discont += offset; } /* Check if the new clock params would have made our observation within range */ now_synched = (GST_CLOCK_DIFF (remote_avg, gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_1, internal_time, external_time, rate_num, rate_den)) < (GstClockTimeDiff) (max_discont)) && (GST_CLOCK_DIFF (gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_2, internal_time, external_time, rate_num, rate_den), remote_avg) < (GstClockTimeDiff) (max_discont)); /* Only update the clock if we had synch or just gained it */ if (synched || now_synched || self->skipped_updates > MAX_SKIPPED_UPDATES) { gst_clock_set_calibration (GST_CLOCK_CAST (self), internal_time, external_time, rate_num, rate_den); /* ghetto formula - shorter timeout for bad correlations */ current_timeout = (1e-3 / (1 - MIN (r_squared, 0.99999))) * GST_SECOND; current_timeout = MIN (current_timeout, gst_clock_get_timeout (GST_CLOCK_CAST (self))); self->skipped_updates = 0; /* FIXME: When do we consider the clock absolutely not synced anymore? */ gst_clock_set_synced (GST_CLOCK (self), TRUE); } else { /* Restore original calibration vars for the report, we're not changing the clock */ internal_time = orig_internal_time; external_time = orig_external_time; rate_num = orig_rate_num; rate_den = orig_rate_den; time_discont = 0; self->skipped_updates++; } } /* Limit the polling to at most one per minimum_update_interval */ if (rtt < min_update_interval) current_timeout = MAX (min_update_interval - rtt, current_timeout); GST_OBJECT_LOCK (self); if (self->busses) { GstStructure *s; GstMessage *msg; GList *l; /* Output a stats message, whether we updated the clock or not */ s = gst_structure_new ("gst-netclock-statistics", "synchronised", G_TYPE_BOOLEAN, synched, "rtt", G_TYPE_UINT64, rtt, "rtt-average", G_TYPE_UINT64, self->rtt_avg, "local", G_TYPE_UINT64, local_avg, "remote", G_TYPE_UINT64, remote_avg, "discontinuity", G_TYPE_INT64, time_discont, "remote-min-estimate", G_TYPE_UINT64, min_guess, "remote-max-estimate", G_TYPE_UINT64, time_before, "remote-min-error", G_TYPE_INT64, GST_CLOCK_DIFF (remote_avg, min_guess), "remote-max-error", G_TYPE_INT64, GST_CLOCK_DIFF (remote_avg, time_before), "request-send", G_TYPE_UINT64, local_1, "request-receive", G_TYPE_UINT64, local_2, "r-squared", G_TYPE_DOUBLE, r_squared, "timeout", G_TYPE_UINT64, current_timeout, "internal-time", G_TYPE_UINT64, internal_time, "external-time", G_TYPE_UINT64, external_time, "rate-num", G_TYPE_UINT64, rate_num, "rate-den", G_TYPE_UINT64, rate_den, "rate", G_TYPE_DOUBLE, (gdouble) (rate_num) / rate_den, "local-clock-offset", G_TYPE_INT64, GST_CLOCK_DIFF (internal_time, external_time), NULL); msg = gst_message_new_element (GST_OBJECT (self), s); for (l = self->busses; l; l = l->next) gst_bus_post (l->data, gst_message_ref (msg)); gst_message_unref (msg); } GST_OBJECT_UNLOCK (self); GST_INFO ("next timeout: %" GST_TIME_FORMAT, GST_TIME_ARGS (current_timeout)); self->timeout_expiration = gst_util_get_timestamp () + current_timeout; return; bogus_observation: /* Schedule a new packet again soon */ self->timeout_expiration = gst_util_get_timestamp () + (GST_SECOND / 4); return; }
gboolean gst_egl_adaptation_init_display (GstEglAdaptationContext * ctx) { GstMessage *msg; EGLDisplay display; GST_DEBUG_OBJECT (ctx->element, "Enter EGL initial configuration"); if (!platform_wrapper_init ()) { GST_ERROR_OBJECT (ctx->element, "Couldn't init EGL platform wrapper"); goto HANDLE_ERROR; } msg = gst_message_new_need_context (GST_OBJECT_CAST (ctx->element), GST_EGL_DISPLAY_CONTEXT_TYPE); gst_element_post_message (GST_ELEMENT_CAST (ctx->element), msg); GST_OBJECT_LOCK (ctx->element); if (!ctx->set_display) { GstContext *context; GST_OBJECT_UNLOCK (ctx->element); display = eglGetDisplay (EGL_DEFAULT_DISPLAY); if (display == EGL_NO_DISPLAY) { GST_ERROR_OBJECT (ctx->element, "Could not get EGL display connection"); goto HANDLE_ERROR; /* No EGL error is set by eglGetDisplay() */ } ctx->display = gst_egl_display_new (display, (GDestroyNotify) eglTerminate); context = gst_context_new_egl_display (ctx->display, FALSE); msg = gst_message_new_have_context (GST_OBJECT (ctx->element), context); gst_element_post_message (GST_ELEMENT_CAST (ctx->element), msg); } if (!eglInitialize (gst_egl_display_get (ctx->display), &ctx->eglglesctx->egl_major, &ctx->eglglesctx->egl_minor)) { got_egl_error ("eglInitialize"); GST_ERROR_OBJECT (ctx->element, "Could not init EGL display connection"); goto HANDLE_EGL_ERROR; } /* Check against required EGL version * XXX: Need to review the version requirement in terms of the needed API */ if (ctx->eglglesctx->egl_major < GST_EGLGLESSINK_EGL_MIN_VERSION) { GST_ERROR_OBJECT (ctx->element, "EGL v%d needed, but you only have v%d.%d", GST_EGLGLESSINK_EGL_MIN_VERSION, ctx->eglglesctx->egl_major, ctx->eglglesctx->egl_minor); goto HANDLE_ERROR; } GST_INFO_OBJECT (ctx->element, "System reports supported EGL version v%d.%d", ctx->eglglesctx->egl_major, ctx->eglglesctx->egl_minor); eglBindAPI (EGL_OPENGL_ES_API); return TRUE; /* Errors */ HANDLE_EGL_ERROR: GST_ERROR_OBJECT (ctx->element, "EGL call returned error %x", eglGetError ()); HANDLE_ERROR: GST_ERROR_OBJECT (ctx->element, "Couldn't setup window/surface from handle"); return FALSE; }
static GstFlowReturn gst_mimenc_chain (GstPad * pad, GstBuffer * in) { GstMimEnc *mimenc; GstBuffer *out_buf = NULL, *buf = NULL; guchar *data; gint buffer_size; GstBuffer *header = NULL; GstFlowReturn res = GST_FLOW_OK; GstEvent *event = NULL; gboolean keyframe; g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR); mimenc = GST_MIMENC (gst_pad_get_parent (pad)); g_return_val_if_fail (GST_IS_MIMENC (mimenc), GST_FLOW_ERROR); GST_OBJECT_LOCK (mimenc); if (mimenc->segment.format == GST_FORMAT_UNDEFINED) { GST_WARNING_OBJECT (mimenc, "No new-segment received," " initializing segment with time 0..-1"); gst_segment_init (&mimenc->segment, GST_FORMAT_TIME); gst_segment_set_newsegment (&mimenc->segment, FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0); } if (mimenc->enc == NULL) { mimenc->enc = mimic_open (); if (mimenc->enc == NULL) { GST_WARNING_OBJECT (mimenc, "mimic_open error\n"); res = GST_FLOW_ERROR; goto out_unlock; } if (!mimic_encoder_init (mimenc->enc, mimenc->res)) { GST_WARNING_OBJECT (mimenc, "mimic_encoder_init error\n"); mimic_close (mimenc->enc); mimenc->enc = NULL; res = GST_FLOW_ERROR; goto out_unlock; } if (!mimic_get_property (mimenc->enc, "buffer_size", &mimenc->buffer_size)) { GST_WARNING_OBJECT (mimenc, "mimic_get_property('buffer_size') error\n"); mimic_close (mimenc->enc); mimenc->enc = NULL; res = GST_FLOW_ERROR; goto out_unlock; } } buf = in; data = GST_BUFFER_DATA (buf); out_buf = gst_buffer_new_and_alloc (mimenc->buffer_size); GST_BUFFER_TIMESTAMP (out_buf) = gst_segment_to_running_time (&mimenc->segment, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf)); mimenc->last_buffer = GST_BUFFER_TIMESTAMP (out_buf); buffer_size = mimenc->buffer_size; keyframe = (mimenc->frames % MAX_INTERFRAMES) == 0 ? TRUE : FALSE; if (!mimic_encode_frame (mimenc->enc, data, GST_BUFFER_DATA (out_buf), &buffer_size, keyframe)) { GST_WARNING_OBJECT (mimenc, "mimic_encode_frame error\n"); gst_buffer_unref (out_buf); gst_buffer_unref (buf); res = GST_FLOW_ERROR; goto out_unlock; } GST_BUFFER_SIZE (out_buf) = buffer_size; GST_DEBUG_OBJECT (mimenc, "incoming buf size %d, encoded size %d", GST_BUFFER_SIZE (buf), GST_BUFFER_SIZE (out_buf)); ++mimenc->frames; // now let's create that tcp header header = gst_mimenc_create_tcp_header (mimenc, buffer_size, GST_BUFFER_TIMESTAMP (out_buf), keyframe, FALSE); if (!header) { gst_buffer_unref (out_buf); GST_DEBUG_OBJECT (mimenc, "header not created succesfully"); res = GST_FLOW_ERROR; goto out_unlock; } if (mimenc->need_newsegment) { event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0); mimenc->need_newsegment = FALSE; } GST_OBJECT_UNLOCK (mimenc); if (event) { if (!gst_pad_push_event (mimenc->srcpad, event)) GST_WARNING_OBJECT (mimenc, "Failed to push NEWSEGMENT event"); } res = gst_pad_push (mimenc->srcpad, header); if (res != GST_FLOW_OK) { gst_buffer_unref (out_buf); goto out; } res = gst_pad_push (mimenc->srcpad, out_buf); out: if (buf) gst_buffer_unref (buf); gst_object_unref (mimenc); return res; out_unlock: GST_OBJECT_UNLOCK (mimenc); goto out; }