示例#1
0
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;
  }
}
示例#3
0
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;
}
示例#7
0
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;
  }
}
示例#8
0
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;
}
示例#9
0
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;
}
示例#10
0
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;
  }
}
示例#11
0
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;
  }
}
示例#12
0
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;
  }
}
示例#13
0
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;
}
示例#14
0
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);
}
示例#15
0
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;
  }
}
示例#16
0
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;
}
示例#17
0
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;
  }
}
示例#18
0
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;
}
示例#19
0
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;
}
示例#20
0
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;
}
示例#22
0
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);
}
示例#24
0
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;
}
示例#26
0
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 */
}
示例#27
0
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;
}
示例#28
0
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;
}
示例#29
0
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;
}
示例#30
0
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;

}