static GstCaps *
gst_decklink_audio_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
{
  GstDecklinkAudioSink *self = GST_DECKLINK_AUDIO_SINK_CAST (bsink);
  GstCaps *caps;

  if ((caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (bsink))))
    return caps;

  caps = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));

  GST_OBJECT_LOCK (self);
  if (self->output && self->output->attributes) {
    int64_t max_channels = 0;
    HRESULT ret;
    GstStructure *s;
    GValue arr = G_VALUE_INIT;
    GValue v = G_VALUE_INIT;

    ret =
        self->output->attributes->GetInt (BMDDeckLinkMaximumAudioChannels,
        &max_channels);
    /* 2 should always be supported */
    if (ret != S_OK) {
      max_channels = 2;
    }

    caps = gst_caps_make_writable (caps);
    s = gst_caps_get_structure (caps, 0);

    g_value_init (&arr, GST_TYPE_LIST);
    g_value_init (&v, G_TYPE_INT);
    if (max_channels >= 16) {
      g_value_set_int (&v, 16);
      gst_value_list_append_value (&arr, &v);
    }
    if (max_channels >= 8) {
      g_value_set_int (&v, 8);
      gst_value_list_append_value (&arr, &v);
    }
    g_value_set_int (&v, 2);
    gst_value_list_append_value (&arr, &v);

    gst_structure_set_value (s, "channels", &arr);
    g_value_unset (&v);
    g_value_unset (&arr);
  }
  GST_OBJECT_UNLOCK (self);

  if (filter) {
    GstCaps *intersection =
        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
    gst_caps_unref (caps);
    caps = intersection;
  }

  return caps;
}
GstCaps *
gst_edt_pdv_sink_get_caps (GstBaseSink * basesink, GstCaps * filter_caps)
{
  GstEdtPdvSink *pdvsink = GST_EDT_PDV_SINK (basesink);
  gint width, height, depth;
  GstVideoFormat format;
  GstVideoInfo vinfo;

  if (!pdvsink->dev) {
    return gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
            (pdvsink)));
  }

  gst_video_info_init (&vinfo);
  width = pdv_get_width (pdvsink->dev);
  height = pdv_get_height (pdvsink->dev);
  depth = pdv_get_depth (pdvsink->dev);

  switch (depth) {
    case 8:
      format = GST_VIDEO_FORMAT_GRAY8;
      break;
    case 16:
      /* TODO: will this be host order or always one of BE/LE? */
      format = GST_VIDEO_FORMAT_GRAY16_BE;
      break;
    default:
      format = GST_VIDEO_FORMAT_UNKNOWN;
  }
  gst_video_info_set_format (&vinfo, format, width, height);

  /* TODO: handle filter_caps */
  return gst_video_info_to_caps (&vinfo);
}
static gboolean
gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
{
  GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
  const GstStructure *structure;
  GstCaps *allowed_caps;
  gboolean ret = TRUE;

  GST_LOG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);

  allowed_caps = gst_pad_get_caps (GST_BASE_SINK_PAD (bsink));

  if (!gst_caps_can_intersect (allowed_caps, caps))
    return FALSE;

  structure = gst_caps_get_structure (caps, 0);

  ret &= gst_structure_get_int (structure, "width", &sink->video_width);
  ret &= gst_structure_get_int (structure, "height", &sink->video_height);

  if (!ret)
    return FALSE;

  gst_caps_replace (&sink->caps, caps);

  return TRUE;
}
Beispiel #4
0
static void
gst_shout2send_init (GstShout2send * shout2send)
{
  gst_base_sink_set_sync (GST_BASE_SINK (shout2send), FALSE);

  gst_pad_set_setcaps_function (GST_BASE_SINK_PAD (shout2send),
      GST_DEBUG_FUNCPTR (gst_shout2send_setcaps));

  shout2send->timer = gst_poll_new_timer ();

  shout2send->ip = g_strdup (DEFAULT_IP);
  shout2send->port = DEFAULT_PORT;
  shout2send->password = g_strdup (DEFAULT_PASSWORD);
  shout2send->username = g_strdup (DEFAULT_USERNAME);
  shout2send->streamname = g_strdup (DEFAULT_STREAMNAME);
  shout2send->description = g_strdup (DEFAULT_DESCRIPTION);
  shout2send->genre = g_strdup (DEFAULT_GENRE);
  shout2send->mount = g_strdup (DEFAULT_MOUNT);
  shout2send->url = g_strdup (DEFAULT_URL);
  shout2send->protocol = DEFAULT_PROTOCOL;
  shout2send->ispublic = DEFAULT_PUBLIC;

  shout2send->tags = gst_tag_list_new ();
  shout2send->conn = NULL;
  shout2send->audio_format = SHOUT_FORMAT_VORBIS;
  shout2send->connected = FALSE;
  shout2send->songmetadata = NULL;
  shout2send->songartist = NULL;
  shout2send->songtitle = NULL;
}
static GstCaps *
gst_oss_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
{
  GstOssSink *osssink;
  GstCaps *caps;

  osssink = GST_OSSSINK (bsink);

  if (osssink->fd == -1) {
    caps = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
  } else if (osssink->probed_caps) {
    caps = gst_caps_ref (osssink->probed_caps);
  } else {
    caps = gst_oss_helper_probe_caps (osssink->fd);
    if (caps && !gst_caps_is_empty (caps)) {
      osssink->probed_caps = gst_caps_ref (caps);
    }
  }

  if (filter && caps) {
    GstCaps *intersection;

    intersection =
        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
    gst_caps_unref (caps);
    return intersection;
  } else {
    return caps;
  }
}
static GstCaps *
gst_openal_sink_getcaps (GstBaseSink * bsink)
{
    GstOpenALSink *sink = GST_OPENAL_SINK (bsink);
    GstCaps *caps;

    if (sink->device == NULL) {
        GstPad *pad = GST_BASE_SINK_PAD (bsink);
        caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
    } else if (sink->probed_caps)
        caps = gst_caps_copy (sink->probed_caps);
    else {
        if (sink->context)
            caps = gst_openal_helper_probe_caps (sink->context);
        else if (sink->custom_ctx)
            caps = gst_openal_helper_probe_caps (sink->custom_ctx);
        else {
            ALCcontext *ctx = alcCreateContext (sink->device, NULL);
            if (ctx) {
                caps = gst_openal_helper_probe_caps (ctx);
                alcDestroyContext (ctx);
            } else {
                GST_ELEMENT_WARNING (sink, RESOURCE, FAILED,
                                     ("Could not create temporary context."),
                                     GST_ALC_ERROR (sink->device));
                caps = NULL;
            }
        }

        if (caps && !gst_caps_is_empty (caps))
            sink->probed_caps = gst_caps_copy (caps);
    }

    return caps;
}
static GstCaps *
gst_v4l2sink_get_caps (GstBaseSink * bsink)
{
  GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink);
  GstCaps *ret;
  GSList *walk;
  GSList *formats;

  if (!GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) {
    /* FIXME: copy? */
    GST_DEBUG_OBJECT (v4l2sink, "device is not open");
    return
        gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
            (v4l2sink)));
  }

  if (v4l2sink->probed_caps) {
    LOG_CAPS (v4l2sink, v4l2sink->probed_caps);
    return gst_caps_ref (v4l2sink->probed_caps);
  }

  formats = gst_v4l2_object_get_format_list (v4l2sink->v4l2object);

  ret = gst_caps_new_empty ();

  for (walk = v4l2sink->v4l2object->formats; walk; walk = walk->next) {
    struct v4l2_fmtdesc *format;

    GstStructure *template;
Beispiel #8
0
/* GstBaseSink vmethod implementations */
static GstCaps *
gst_osx_audio_sink_getcaps (GstBaseSink * sink)
{
  GstCaps *caps;
  GstOsxAudioSink *osxsink;
  OSStatus status;
  AudioValueRange rates[10];
  UInt32 propertySize;
  int i;

  propertySize = sizeof (AudioValueRange) * 9;
  osxsink = GST_OSX_AUDIO_SINK (sink);

  caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
          (sink)));


  status = AudioDeviceGetProperty (osxsink->ringbuffer->device_id, 0, FALSE,
      kAudioDevicePropertyAvailableNominalSampleRates, &propertySize, &rates);

  GST_DEBUG
      ("Getting available sample rates: Status: %ld number of ranges: %lu",
      status, propertySize / sizeof (AudioValueRange));

  for (i = 0; i < propertySize / sizeof (AudioValueRange); i++) {
    GST_LOG_OBJECT (osxsink, "Range from %f to %f", rates[i].mMinimum,
        rates[i].mMaximum);
  }

  return caps;
}
Beispiel #9
0
static GstFlowReturn
gst_test_reverse_negotiation_sink_render (GstBaseSink * bsink,
    GstBuffer * buffer)
{
  GstTestReverseNegotiationSink *sink =
      GST_TEST_REVERSE_NEGOTIATION_SINK (bsink);
  GstCaps *caps;
  GstVideoInfo info;

  caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (bsink));

  fail_unless (caps != NULL);
  fail_unless (gst_video_info_from_caps (&info, caps));

  sink->nbuffers++;

  /* The third buffer is still in the old size
   * because the videoconverts can't convert
   * the frame sizes
   */
  if (sink->nbuffers > 3) {
    fail_unless_equals_int (GST_VIDEO_INFO_WIDTH (&info), 512);
    fail_unless_equals_int (GST_VIDEO_INFO_HEIGHT (&info), 128);
  }

  gst_caps_unref (caps);

  return GST_FLOW_OK;
}
Beispiel #10
0
static void
gst_gio_base_sink_init (GstGioBaseSink * sink, GstGioBaseSinkClass * gclass)
{
    gst_pad_set_query_function (GST_BASE_SINK_PAD (sink),
                                GST_DEBUG_FUNCPTR (gst_gio_base_sink_query));

    gst_base_sink_set_sync (GST_BASE_SINK (sink), FALSE);

    sink->cancel = g_cancellable_new ();
}
Beispiel #11
0
static GstCaps *
gst_v4l2sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
{
  GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink);

  if (!GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) {
    /* FIXME: copy? */
    GST_DEBUG_OBJECT (v4l2sink, "device is not open");
    return gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (v4l2sink));
  }


  return gst_v4l2_object_get_caps (v4l2sink->v4l2object, filter);
}
static void
gst_gnome_vfs_sink_init (GstGnomeVFSSink * sink, GstGnomeVFSSinkClass * klass)
{
    gst_pad_set_query_function (GST_BASE_SINK_PAD (sink),
                                GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_query));

    sink->uri = NULL;
    sink->uri_name = NULL;
    sink->handle = NULL;
    sink->own_handle = FALSE;
    sink->current_pos = 0;

    GST_BASE_SINK (sink)->sync = FALSE;
}
Beispiel #13
0
static void
gst_fd_sink_init (GstFdSink * fdsink, GstFdSinkClass * klass)
{
  GstPad *pad;

  pad = GST_BASE_SINK_PAD (fdsink);
  gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_fd_sink_query));

  fdsink->fd = 1;
  fdsink->uri = g_strdup_printf ("fd://%d", fdsink->fd);
  fdsink->bytes_written = 0;
  fdsink->current_pos = 0;

  gst_base_sink_set_sync (GST_BASE_SINK (fdsink), FALSE);
}
const gchar *
get_mime_type (GstAnalyzerSink * sink)
{
  GstCaps *caps = NULL;
  GstStructure *structure;
  const gchar *name;

  caps = gst_pad_get_allowed_caps (GST_BASE_SINK_PAD (sink));
  if (caps) {
    caps = gst_caps_truncate (caps);
    structure = gst_caps_get_structure (caps, 0);
    name = g_strdup (gst_structure_get_name (structure));
    gst_caps_unref (caps);
    return name;
  }
  return NULL;
}
Beispiel #15
0
static GstCaps *
gst_openal_sink_getcaps (GstBaseSink * basesink, GstCaps * filter)
{
  GstOpenALSink *sink = GST_OPENAL_SINK (basesink);
  GstCaps *caps;

  if (sink->default_device == NULL) {
    GstPad *pad = GST_BASE_SINK_PAD (basesink);
    GstCaps *tcaps = gst_pad_get_pad_template_caps (pad);
    caps = gst_caps_copy (tcaps);
    gst_caps_unref (tcaps);
  } else if (sink->probed_caps)
    caps = gst_caps_copy (sink->probed_caps);
  else {
    if (sink->default_context)
      caps = gst_openal_helper_probe_caps (sink->default_context);
    else if (sink->user_context)
      caps = gst_openal_helper_probe_caps (sink->user_context);
    else {
      ALCcontext *context = alcCreateContext (sink->default_device, NULL);
      if (context) {
        caps = gst_openal_helper_probe_caps (context);
        alcDestroyContext (context);
      } else {
        GST_ELEMENT_WARNING (sink, RESOURCE, FAILED,
            ("Could not create temporary context."),
            GST_ALC_ERROR (sink->default_device));
        caps = NULL;
      }
    }

    if (caps && !gst_caps_is_empty (caps))
      sink->probed_caps = gst_caps_copy (caps);
  }

  if (filter) {
    GstCaps *intersection;

    intersection =
        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
    return intersection;
  } else {
    return caps;
  }
}
Beispiel #16
0
static void
gst_file_sink_init (GstFileSink * filesink, GstFileSinkClass * g_class)
{
  GstPad *pad;

  pad = GST_BASE_SINK_PAD (filesink);

  gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_file_sink_query));

  filesink->filename = NULL;
  filesink->file = NULL;
  filesink->buffer_mode = DEFAULT_BUFFER_MODE;
  filesink->buffer_size = DEFAULT_BUFFER_SIZE;
  filesink->buffer = NULL;
  filesink->append = FALSE;

  gst_base_sink_set_sync (GST_BASE_SINK (filesink), FALSE);
}
Beispiel #17
0
static GstCaps *
gst_eglglessink_getcaps (GstBaseSink * bsink)
{
  GstEglGlesSink *eglglessink;
  GstCaps *ret = NULL;

  eglglessink = GST_EGLGLESSINK (bsink);

  GST_OBJECT_LOCK (eglglessink);
  if (eglglessink->sinkcaps) {
    ret = gst_caps_ref (eglglessink->sinkcaps);
  } else {
    ret =
        gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
            (bsink)));
  }
  GST_OBJECT_UNLOCK (eglglessink);

  return ret;
}
static void
type_instance_init (GTypeInstance * instance, gpointer g_class)
{
  GstOmxBaseSink *self;

  self = GST_OMX_BASE_SINK (instance);

  GST_LOG_OBJECT (self, "begin");

  self->gomx = gstomx_core_new (self, G_TYPE_FROM_CLASS (g_class));
  self->in_port = g_omx_core_new_port (self->gomx, 0);

  {
    GstPad *sinkpad;
    self->sinkpad = sinkpad = GST_BASE_SINK_PAD (self);
    self->base_activatepush = GST_PAD_ACTIVATEPUSHFUNC (sinkpad);
    gst_pad_set_activatepush_function (sinkpad, activate_push);
    gst_pad_set_link_function (sinkpad, pad_sink_link);
  }

  GST_LOG_OBJECT (self, "end");
}
Beispiel #19
0
static void
gst_aasink_init (GstAASink * aasink)
{
  GstPad *pad;

  pad = GST_BASE_SINK_PAD (aasink);
  gst_pad_set_fixatecaps_function (pad, gst_aasink_fixate);

  memcpy (&aasink->ascii_surf, &aa_defparams,
      sizeof (struct aa_hardware_params));
  aasink->ascii_parms.bright = 0;
  aasink->ascii_parms.contrast = 16;
  aasink->ascii_parms.gamma = 1.0;
  aasink->ascii_parms.dither = 0;
  aasink->ascii_parms.inversion = 0;
  aasink->ascii_parms.randomval = 0;
  aasink->aa_driver = 0;

  aasink->width = -1;
  aasink->height = -1;

}
Beispiel #20
0
static GstCaps *
gst_oss_sink_getcaps (GstBaseSink * bsink)
{
  GstOssSink *osssink;
  GstCaps *caps;

  osssink = GST_OSSSINK (bsink);

  if (osssink->fd == -1) {
    caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
            (bsink)));
  } else if (osssink->probed_caps) {
    caps = gst_caps_copy (osssink->probed_caps);
  } else {
    caps = gst_oss_helper_probe_caps (osssink->fd);
    if (caps && !gst_caps_is_empty (caps)) {
      osssink->probed_caps = gst_caps_copy (caps);
    }
  }

  return caps;
}
static GstCaps *
gst_audioflinger_sink_getcaps (GstBaseSink * bsink)
{
  GstAudioFlingerSink *audioflinger_sink;
  GstCaps *caps;

  audioflinger_sink = GST_AUDIOFLINGERSINK (bsink);
  GST_DEBUG_OBJECT (audioflinger_sink, "enter,%p", audioflinger_sink->audioflinger_device);
  if (audioflinger_sink->audioflinger_device == NULL 
    || audioflinger_sink->m_init == FALSE) {
    caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
            (bsink)));
  } else if (audioflinger_sink->probed_caps) {
    caps = gst_caps_copy (audioflinger_sink->probed_caps);
  } else {
    caps = gst_caps_new_any ();
    if (caps && !gst_caps_is_empty (caps)) {
      audioflinger_sink->probed_caps = gst_caps_copy (caps);
    }
  }

  return caps;
}
static void
type_instance_init (GTypeInstance *instance,
                    gpointer g_class)
{
    GstOmxBaseSink *self;

    self = GST_OMX_BASE_SINK (instance);

    GST_LOG_OBJECT (self, "begin");

    /* GOmx */
    {
        GOmxCore *gomx;
        self->gomx = gomx = g_omx_core_new ();
        gomx->object = self;
    }

    {
        const char *tmp;
        tmp = g_type_get_qdata (G_OBJECT_CLASS_TYPE (g_class),
                                g_quark_from_static_string ("library-name"));
        self->omx_library = g_strdup (tmp);
        tmp = g_type_get_qdata (G_OBJECT_CLASS_TYPE (g_class),
                                g_quark_from_static_string ("component-name"));
        self->omx_component = g_strdup (tmp);
    }

    {
        GstPad *sinkpad;
        self->sinkpad = sinkpad = GST_BASE_SINK_PAD (self);
        self->base_activatepush = GST_PAD_ACTIVATEPUSHFUNC (sinkpad);
        gst_pad_set_activatepush_function (sinkpad, activate_push);
        gst_pad_set_link_function (sinkpad, pad_sink_link);
    }

    GST_LOG_OBJECT (self, "end");
}
static GstCaps *
gst_gtk_gl_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
{
    GstCaps *tmp = NULL;
    GstCaps *result = NULL;

    tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));

    if (filter) {
        GST_DEBUG_OBJECT (bsink, "intersecting with filter caps %" GST_PTR_FORMAT,
                          filter);

        result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
        gst_caps_unref (tmp);
    } else {
        result = tmp;
    }

    result = gst_gl_overlay_compositor_add_caps (result);

    GST_DEBUG_OBJECT (bsink, "returning caps: %" GST_PTR_FORMAT, result);

    return result;
}
Beispiel #24
0
static CoglBool
cogl_gst_source_dispatch (GSource *source,
                          GSourceFunc callback,
                          void *user_data)
{
  CoglGstSource *gst_source= (CoglGstSource*) source;
  CoglGstVideoSinkPrivate *priv = gst_source->sink->priv;
  GstBuffer *buffer;

  g_mutex_lock (&gst_source->buffer_lock);

  if (G_UNLIKELY (gst_source->has_new_caps))
    {
      GstCaps *caps =
        gst_pad_get_current_caps (GST_BASE_SINK_PAD ((GST_BASE_SINK
                (gst_source->sink))));

      if (!cogl_gst_video_sink_parse_caps (caps, gst_source->sink, TRUE))
        goto negotiation_fail;

      gst_source->has_new_caps = FALSE;
      priv->free_layer = priv->custom_start + priv->renderer->n_layers;

      dirty_default_pipeline (gst_source->sink);

      /* We are now in a state where we could generate the pipeline if
       * the application requests it so we can emit the signal.
       * However we'll actually generate the pipeline lazily only if
       * the application actually asks for it. */
      g_signal_emit (gst_source->sink,
                     video_sink_signals[PIPELINE_READY_SIGNAL],
                     0 /* detail */);
    }

  buffer = gst_source->buffer;
  gst_source->buffer = NULL;

  g_mutex_unlock (&gst_source->buffer_lock);

  if (buffer)
    {
      if (!priv->renderer->upload (gst_source->sink, buffer))
        goto fail_upload;

      g_signal_emit (gst_source->sink,
                     video_sink_signals[NEW_FRAME_SIGNAL], 0,
                     NULL);
      gst_buffer_unref (buffer);
    }
  else
    GST_WARNING_OBJECT (gst_source->sink, "No buffers available for display");

  return TRUE;


negotiation_fail:
  {
    GST_WARNING_OBJECT (gst_source->sink,
        "Failed to handle caps. Stopping GSource");
    priv->flow_return = GST_FLOW_NOT_NEGOTIATED;
    g_mutex_unlock (&gst_source->buffer_lock);

    return FALSE;
  }

fail_upload:
  {
    GST_WARNING_OBJECT (gst_source->sink, "Failed to upload buffer");
    priv->flow_return = GST_FLOW_ERROR;
    gst_buffer_unref (buffer);
    return FALSE;
  }
}
Beispiel #25
0
static GstFlowReturn
gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer)
{
  GstFlowReturn ret;
  GstAppSink *appsink = GST_APP_SINK_CAST (psink);
  GstAppSinkPrivate *priv = appsink->priv;
  gboolean emit;

restart:
  g_mutex_lock (&priv->mutex);
  if (priv->flushing)
    goto flushing;

  /* queue holding caps event might have been FLUSHed,
   * but caps state still present in pad caps */
  if (G_UNLIKELY (!priv->last_caps &&
          gst_pad_has_current_caps (GST_BASE_SINK_PAD (psink)))) {
    priv->last_caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (psink));
    GST_DEBUG_OBJECT (appsink, "activating pad caps %" GST_PTR_FORMAT,
        priv->last_caps);
  }

  GST_DEBUG_OBJECT (appsink, "pushing render buffer %p on queue (%d)",
      buffer, priv->num_buffers);

  while (priv->max_buffers > 0 && priv->num_buffers >= priv->max_buffers) {
    if (priv->drop) {
      GstBuffer *old;

      /* we need to drop the oldest buffer and try again */
      if ((old = dequeue_buffer (appsink))) {
        GST_DEBUG_OBJECT (appsink, "dropping old buffer %p", old);
        gst_buffer_unref (old);
      }
    } else {
      GST_DEBUG_OBJECT (appsink, "waiting for free space, length %d >= %d",
          priv->num_buffers, priv->max_buffers);

      if (priv->unlock) {
        /* we are asked to unlock, call the wait_preroll method */
        g_mutex_unlock (&priv->mutex);
        if ((ret = gst_base_sink_wait_preroll (psink)) != GST_FLOW_OK)
          goto stopping;

        /* we are allowed to continue now */
        goto restart;
      }

      /* wait for a buffer to be removed or flush */
      g_cond_wait (&priv->cond, &priv->mutex);
      if (priv->flushing)
        goto flushing;
    }
  }
  /* we need to ref the buffer when pushing it in the queue */
  g_queue_push_tail (priv->queue, gst_buffer_ref (buffer));
  priv->num_buffers++;
  g_cond_signal (&priv->cond);
  emit = priv->emit_signals;
  g_mutex_unlock (&priv->mutex);

  if (priv->callbacks.new_sample) {
    ret = priv->callbacks.new_sample (appsink, priv->user_data);
  } else {
    ret = GST_FLOW_OK;
    if (emit)
      g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_SAMPLE], 0, &ret);
  }
  return ret;

flushing:
  {
    GST_DEBUG_OBJECT (appsink, "we are flushing");
    g_mutex_unlock (&priv->mutex);
    return GST_FLOW_FLUSHING;
  }
stopping:
  {
    GST_DEBUG_OBJECT (appsink, "we are stopping");
    return ret;
  }
}
Beispiel #26
0
/* Buffer management
 *
 * The buffer_alloc function must either return a buffer with given size and
 * caps or create a buffer with different caps attached to the buffer. This
 * last option is called reverse negotiation, ie, where the sink suggests a
 * different format from the upstream peer. 
 *
 * We try to do reverse negotiation when our geometry changes and we like a
 * resized buffer.
 */
static GstFlowReturn
gst_vdp_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
    GstCaps * caps, GstBuffer ** buf)
{
  VdpSink *vdp_sink;
  GstStructure *structure = NULL;
  GstFlowReturn ret = GST_FLOW_OK;
  gint width, height;
  GstCaps *alloc_caps;
  gint w_width, w_height;
  GError *err;

  vdp_sink = GST_VDP_SINK (bsink);

  GST_LOG_OBJECT (vdp_sink,
      "a buffer of %d bytes was requested with caps %" GST_PTR_FORMAT
      " and offset %" G_GUINT64_FORMAT, size, caps, offset);

  /* get struct to see what is requested */
  structure = gst_caps_get_structure (caps, 0);
  if (!gst_structure_get_int (structure, "width", &width) ||
      !gst_structure_get_int (structure, "height", &height)) {
    GST_WARNING_OBJECT (vdp_sink, "invalid caps for buffer allocation %"
        GST_PTR_FORMAT, caps);
    ret = GST_FLOW_NOT_NEGOTIATED;
    goto beach;
  }

  alloc_caps = gst_caps_ref (caps);

  /* We take the flow_lock because the window might go away */
  g_mutex_lock (vdp_sink->flow_lock);
  if (!vdp_sink->window) {
    g_mutex_unlock (vdp_sink->flow_lock);
    goto alloc;
  }

  /* What is our geometry */
  gst_vdp_sink_window_update_geometry (vdp_sink, vdp_sink->window);
  w_width = vdp_sink->window->width;
  w_height = vdp_sink->window->height;

  g_mutex_unlock (vdp_sink->flow_lock);

  /* We would like another geometry */
  if (width != w_width || height != w_height) {
    GstCaps *new_caps, *allowed_caps, *desired_caps;
    GstStructure *desired_struct;

    /* make a copy of the incomming caps to create the new
     * suggestion. We can't use make_writable because we might
     * then destroy the original caps which we still need when the
     * peer does not accept the suggestion. */
    new_caps = gst_caps_copy (caps);
    desired_struct = gst_caps_get_structure (new_caps, 0);

    GST_DEBUG ("we would love to receive a %dx%d video", w_width, w_height);
    gst_structure_set (desired_struct, "width", G_TYPE_INT, w_width, NULL);
    gst_structure_set (desired_struct, "height", G_TYPE_INT, w_height, NULL);

    allowed_caps = gst_pad_get_caps (GST_BASE_SINK_PAD (vdp_sink));
    desired_caps = gst_caps_intersect (new_caps, allowed_caps);

    gst_caps_unref (new_caps);
    gst_caps_unref (allowed_caps);

    /* see if peer accepts our new suggestion, if there is no peer, this 
     * function returns true. */
    if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (vdp_sink), desired_caps)) {
      /* we will not alloc a buffer of the new suggested caps. Make sure
       * we also unref this new caps after we set it on the buffer. */
      GST_DEBUG ("peer pad accepts our desired caps %" GST_PTR_FORMAT,
          desired_caps);
      gst_caps_unref (alloc_caps);
      alloc_caps = desired_caps;
    } else {
      GST_DEBUG ("peer pad does not accept our desired caps %" GST_PTR_FORMAT,
          desired_caps);
      /* we alloc a buffer with the original incomming caps already in the
       * width and height variables */
      gst_caps_unref (desired_caps);
    }
  }

alloc:
  gst_vdp_buffer_pool_set_caps (vdp_sink->bpool, alloc_caps);
  gst_caps_unref (alloc_caps);

  err = NULL;
  *buf =
      GST_BUFFER_CAST (gst_vdp_buffer_pool_get_buffer (vdp_sink->bpool, &err));
  if (!*buf) {
    gst_vdp_sink_post_error (vdp_sink, err);
    return GST_FLOW_ERROR;
  }

beach:
  return ret;
}
Beispiel #27
0
static gboolean
gst_vdp_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
{
  VdpSink *vdp_sink;
  GstCaps *allowed_caps;
  gboolean ret = TRUE;
  GstStructure *structure;
  GstCaps *intersection;
  gint new_width, new_height;
  const GValue *fps;

  vdp_sink = GST_VDP_SINK (bsink);

  GST_OBJECT_LOCK (vdp_sink);
  if (!vdp_sink->device)
    return FALSE;
  GST_OBJECT_UNLOCK (vdp_sink);

  allowed_caps = gst_pad_get_caps (GST_BASE_SINK_PAD (bsink));
  GST_DEBUG_OBJECT (vdp_sink,
      "sinkconnect possible caps %" GST_PTR_FORMAT " with given caps %"
      GST_PTR_FORMAT, allowed_caps, caps);

  /* We intersect those caps with our template to make sure they are correct */
  intersection = gst_caps_intersect (allowed_caps, caps);
  gst_caps_unref (allowed_caps);

  GST_DEBUG_OBJECT (vdp_sink, "intersection returned %" GST_PTR_FORMAT,
      intersection);
  if (gst_caps_is_empty (intersection)) {
    gst_caps_unref (intersection);
    return FALSE;
  }

  gst_caps_unref (intersection);

  structure = gst_caps_get_structure (caps, 0);

  ret &= gst_structure_get_int (structure, "width", &new_width);
  ret &= gst_structure_get_int (structure, "height", &new_height);
  fps = gst_structure_get_value (structure, "framerate");
  ret &= (fps != NULL);
  if (!ret)
    return FALSE;

  GST_VIDEO_SINK_WIDTH (vdp_sink) = new_width;
  GST_VIDEO_SINK_HEIGHT (vdp_sink) = new_height;
  vdp_sink->fps_n = gst_value_get_fraction_numerator (fps);
  vdp_sink->fps_d = gst_value_get_fraction_denominator (fps);

  gst_vdp_buffer_pool_set_caps (vdp_sink->bpool, caps);

  /* Notify application to set xwindow id now */
  g_mutex_lock (vdp_sink->flow_lock);
  if (!vdp_sink->window) {
    g_mutex_unlock (vdp_sink->flow_lock);
    gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (vdp_sink));
  } else {
    g_mutex_unlock (vdp_sink->flow_lock);
  }

  /* Creating our window and our image */
  if (GST_VIDEO_SINK_WIDTH (vdp_sink) <= 0
      || GST_VIDEO_SINK_HEIGHT (vdp_sink) <= 0) {
    GST_ELEMENT_ERROR (vdp_sink, CORE, NEGOTIATION, (NULL),
        ("Invalid image size."));
    return FALSE;
  }

  g_mutex_lock (vdp_sink->flow_lock);
  if (!vdp_sink->window) {
    vdp_sink->window = gst_vdp_sink_window_new (vdp_sink,
        GST_VIDEO_SINK_WIDTH (vdp_sink), GST_VIDEO_SINK_HEIGHT (vdp_sink));
  }
  g_mutex_unlock (vdp_sink->flow_lock);

  return TRUE;
}
static GstFlowReturn
webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
{
    WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink);
    WebKitVideoSinkPrivate* priv = sink->priv;

    g_mutex_lock(priv->buffer_mutex);

    if (priv->unlocked) {
        g_mutex_unlock(priv->buffer_mutex);
        return GST_FLOW_OK;
    }

    // Ignore buffers if the video is already in fullscreen using
    // another sink.
    if (priv->gstGWorld->isFullscreen()) {
        g_mutex_unlock(priv->buffer_mutex);
        return GST_FLOW_OK;
    }

    priv->buffer = gst_buffer_ref(buffer);

    // For the unlikely case where the buffer has no caps, the caps
    // are implicitely the caps of the pad. This shouldn't happen.
    if (G_UNLIKELY(!GST_BUFFER_CAPS(buffer))) {
        buffer = priv->buffer = gst_buffer_make_metadata_writable(priv->buffer);
        gst_buffer_set_caps(priv->buffer, GST_PAD_CAPS(GST_BASE_SINK_PAD(bsink)));
    }

    GstCaps *caps = GST_BUFFER_CAPS(buffer);
    GstVideoFormat format;
    int width, height;
    if (G_UNLIKELY(!gst_video_format_parse_caps(caps, &format, &width, &height))) {
        gst_buffer_unref(buffer);
        g_mutex_unlock(priv->buffer_mutex);
        return GST_FLOW_ERROR;
    }

    // Cairo's ARGB has pre-multiplied alpha while GStreamer's doesn't.
    // Here we convert to Cairo's ARGB.
    if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) {
        // Because GstBaseSink::render() only owns the buffer reference in the
        // method scope we can't use gst_buffer_make_writable() here. Also
        // The buffer content should not be changed here because the same buffer
        // could be passed multiple times to this method (in theory)
        GstBuffer *newBuffer = gst_buffer_try_new_and_alloc(GST_BUFFER_SIZE(buffer));

        // Check if allocation failed
        if (G_UNLIKELY(!newBuffer)) {
            gst_buffer_unref(buffer);
            g_mutex_unlock(priv->buffer_mutex);
            return GST_FLOW_ERROR;
        }

        gst_buffer_copy_metadata(newBuffer, buffer, (GstBufferCopyFlags) GST_BUFFER_COPY_ALL);

        // We don't use Color::premultipliedARGBFromColor() here because
        // one function call per video pixel is just too expensive:
        // For 720p/PAL for example this means 1280*720*25=23040000
        // function calls per second!
        unsigned short alpha;
        const guint8 *source = GST_BUFFER_DATA(buffer);
        guint8 *destination = GST_BUFFER_DATA(newBuffer);

        for (int x = 0; x < height; x++) {
            for (int y = 0; y < width; y++) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
                alpha = source[3];
                destination[0] = (source[0] * alpha + 128) / 255;
                destination[1] = (source[1] * alpha + 128) / 255;
                destination[2] = (source[2] * alpha + 128) / 255;
                destination[3] = alpha;
#else
                alpha = source[0];
                destination[0] = alpha;
                destination[1] = (source[1] * alpha + 128) / 255;
                destination[2] = (source[2] * alpha + 128) / 255;
                destination[3] = (source[3] * alpha + 128) / 255;
#endif
                source += 4;
                destination += 4;
            }
        }
        gst_buffer_unref(buffer);
        buffer = priv->buffer = newBuffer;
    }

    // This should likely use a lower priority, but glib currently starves
    // lower priority sources.
    // See: https://bugzilla.gnome.org/show_bug.cgi?id=610830.
    priv->timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT, 0,
                                          webkit_video_sink_timeout_func,
                                          gst_object_ref(sink),
                                          (GDestroyNotify)gst_object_unref);

    g_cond_wait(priv->data_cond, priv->buffer_mutex);
    g_mutex_unlock(priv->buffer_mutex);
    return GST_FLOW_OK;
}
Beispiel #29
0
static GstFlowReturn webkitVideoSinkRender(GstBaseSink* baseSink, GstBuffer* buffer)
{
    WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(baseSink);
    WebKitVideoSinkPrivate* priv = sink->priv;

    g_mutex_lock(priv->bufferMutex);

    if (priv->unlocked) {
        g_mutex_unlock(priv->bufferMutex);
        return GST_FLOW_OK;
    }

#if USE(NATIVE_FULLSCREEN_VIDEO)
    // Ignore buffers if the video is already in fullscreen using
    // another sink.
    if (priv->gstGWorld->isFullscreen()) {
        g_mutex_unlock(priv->bufferMutex);
        return GST_FLOW_OK;
    }
#endif

    priv->buffer = gst_buffer_ref(buffer);

#ifndef GST_API_VERSION_1
    // For the unlikely case where the buffer has no caps, the caps
    // are implicitely the caps of the pad. This shouldn't happen.
    if (UNLIKELY(!GST_BUFFER_CAPS(buffer))) {
        buffer = priv->buffer = gst_buffer_make_metadata_writable(priv->buffer);
        gst_buffer_set_caps(priv->buffer, GST_PAD_CAPS(GST_BASE_SINK_PAD(baseSink)));
    }

    GRefPtr<GstCaps> caps = GST_BUFFER_CAPS(buffer);
#else
    GRefPtr<GstCaps> caps;
    // The video info structure is valid only if the sink handled an allocation query.
    if (GST_VIDEO_INFO_FORMAT(&priv->info) != GST_VIDEO_FORMAT_UNKNOWN)
        caps = adoptGRef(gst_video_info_to_caps(&priv->info));
    else
        caps = priv->currentCaps;
#endif

    GstVideoFormat format;
    WebCore::IntSize size;
    int pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride;
    if (!getVideoSizeAndFormatFromCaps(caps.get(), size, format, pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride)) {
        gst_buffer_unref(buffer);
        g_mutex_unlock(priv->bufferMutex);
        return GST_FLOW_ERROR;
    }

    // Cairo's ARGB has pre-multiplied alpha while GStreamer's doesn't.
    // Here we convert to Cairo's ARGB.
    if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) {
        // Because GstBaseSink::render() only owns the buffer reference in the
        // method scope we can't use gst_buffer_make_writable() here. Also
        // The buffer content should not be changed here because the same buffer
        // could be passed multiple times to this method (in theory).

        GstBuffer* newBuffer = createGstBuffer(buffer);

        // Check if allocation failed.
        if (UNLIKELY(!newBuffer)) {
            g_mutex_unlock(priv->bufferMutex);
            return GST_FLOW_ERROR;
        }

        // We don't use Color::premultipliedARGBFromColor() here because
        // one function call per video pixel is just too expensive:
        // For 720p/PAL for example this means 1280*720*25=23040000
        // function calls per second!
#ifndef GST_API_VERSION_1
        const guint8* source = GST_BUFFER_DATA(buffer);
        guint8* destination = GST_BUFFER_DATA(newBuffer);
#else
        GstMapInfo sourceInfo;
        GstMapInfo destinationInfo;
        gst_buffer_map(buffer, &sourceInfo, GST_MAP_READ);
        const guint8* source = const_cast<guint8*>(sourceInfo.data);
        gst_buffer_map(newBuffer, &destinationInfo, GST_MAP_WRITE);
        guint8* destination = static_cast<guint8*>(destinationInfo.data);
#endif

        for (int x = 0; x < size.height(); x++) {
            for (int y = 0; y < size.width(); y++) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
                unsigned short alpha = source[3];
                destination[0] = (source[0] * alpha + 128) / 255;
                destination[1] = (source[1] * alpha + 128) / 255;
                destination[2] = (source[2] * alpha + 128) / 255;
                destination[3] = alpha;
#else
                unsigned short alpha = source[0];
                destination[0] = alpha;
                destination[1] = (source[1] * alpha + 128) / 255;
                destination[2] = (source[2] * alpha + 128) / 255;
                destination[3] = (source[3] * alpha + 128) / 255;
#endif
                source += 4;
                destination += 4;
            }
        }

#ifdef GST_API_VERSION_1
        gst_buffer_unmap(buffer, &sourceInfo);
        gst_buffer_unmap(newBuffer, &destinationInfo);
#endif
        gst_buffer_unref(buffer);
        buffer = priv->buffer = newBuffer;
    }

    // This should likely use a lower priority, but glib currently starves
    // lower priority sources.
    // See: https://bugzilla.gnome.org/show_bug.cgi?id=610830.
    priv->timeoutId = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, webkitVideoSinkTimeoutCallback,
                                          gst_object_ref(sink), reinterpret_cast<GDestroyNotify>(gst_object_unref));

    g_cond_wait(priv->dataCondition, priv->bufferMutex);
    g_mutex_unlock(priv->bufferMutex);
    return GST_FLOW_OK;
}
Beispiel #30
0
static GstCaps *
gst_tinyalsa_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
{
  GstTinyalsaSink *sink = GST_TINYALSA_SINK (bsink);
  GstCaps *caps = NULL;
  GValue formats = { 0, };
  GValue format = { 0, };
  struct pcm_params *params = NULL;
  struct pcm_mask *mask;
  int rate_min, rate_max, channels_min, channels_max;
  guint16 m;

  GST_DEBUG_OBJECT (sink, "Querying caps");

  GST_OBJECT_LOCK (sink);

  if (sink->cached_caps) {
    GST_DEBUG_OBJECT (sink, "Returning cached caps");
    caps = gst_caps_ref (sink->cached_caps);
    goto done;
  }

  if (sink->pcm) {
    /* We can't query the device while it's open, so return current caps */
    caps = gst_pad_get_current_caps (GST_BASE_SINK_PAD (bsink));
    goto done;
  }

  params = pcm_params_get (sink->card, sink->device, PCM_OUT);
  if (!params) {
    GST_ERROR_OBJECT (sink, "Could not get PCM params");
    goto done;
  }

  mask = pcm_params_get_mask (params, PCM_PARAM_FORMAT);
  m = (mask->bits[1] << 8) | mask->bits[0];

  if (!(m & SNDRV_PCM_FORMAT_ANY)) {
    GST_ERROR_OBJECT (sink, "Could not find any supported format");
    goto done;
  }

  caps = gst_caps_new_empty_simple ("audio/x-raw");

  g_value_init (&formats, GST_TYPE_LIST);
  g_value_init (&format, G_TYPE_STRING);

  if (m & (1 << SNDRV_PCM_FORMAT_S8)) {
    g_value_set_static_string (&format, "S8");
    gst_value_list_prepend_value (&formats, &format);
  }
  if (m & (1 << SNDRV_PCM_FORMAT_S16_LE)) {
    g_value_set_static_string (&format, "S16LE");
    gst_value_list_prepend_value (&formats, &format);
  }
  if (m & (1 << SNDRV_PCM_FORMAT_S24_LE)) {
    g_value_set_static_string (&format, "S24_32LE");
    gst_value_list_prepend_value (&formats, &format);
  }
  if (m & (1 << SNDRV_PCM_FORMAT_S32_LE)) {
    g_value_set_static_string (&format, "S32LE");
    gst_value_list_prepend_value (&formats, &format);
  }

  gst_caps_set_value (caps, "format", &formats);

  g_value_unset (&format);
  g_value_unset (&formats);

  /* This is a bit of a lie, since the device likely only supports some
   * standard rates in this range. We should probably filter the range to
   * those, standard audio rates but even that isn't guaranteed to be accurate.
   */
  rate_min = pcm_params_get_min (params, PCM_PARAM_RATE);
  rate_max = pcm_params_get_max (params, PCM_PARAM_RATE);

  if (rate_min == rate_max)
    gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate_min, NULL);
  else
    gst_caps_set_simple (caps, "rate", GST_TYPE_INT_RANGE, rate_min, rate_max,
        NULL);

  channels_min = pcm_params_get_min (params, PCM_PARAM_CHANNELS);
  channels_max = pcm_params_get_max (params, PCM_PARAM_CHANNELS);

  if (channels_min == channels_max)
    gst_caps_set_simple (caps, "channels", G_TYPE_INT, channels_min, NULL);
  else
    gst_caps_set_simple (caps, "channels", GST_TYPE_INT_RANGE, channels_min,
        channels_max, NULL);

  gst_caps_replace (&sink->cached_caps, caps);

done:
  GST_OBJECT_UNLOCK (sink);

  GST_DEBUG_OBJECT (sink, "Got caps %" GST_PTR_FORMAT, caps);

  if (caps && filter) {
    GstCaps *intersection =
        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);

    gst_caps_unref (caps);
    caps = intersection;
  }

  if (params)
    pcm_params_free (params);

  return caps;
}