static gboolean
gst_v4l2_transform_decide_allocation (GstBaseTransform * trans,
    GstQuery * query)
{
  GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
  gboolean ret = FALSE;

  GST_DEBUG_OBJECT (self, "called");

  if (gst_v4l2_object_decide_allocation (self->v4l2capture, query)) {
    GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2capture->pool);

    ret = GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
        query);

    if (!gst_buffer_pool_set_active (pool, TRUE))
      goto activate_failed;
  }

  return ret;

activate_failed:
  GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
      ("failed to activate bufferpool"), ("failed to activate bufferpool"));
  return TRUE;
}
예제 #2
0
static GstBuffer *
gst_v4lmjpegsink_buffer_new (GstBufferPool * pool,
    guint64 offset, guint size, gpointer user_data)
{
  GstV4lMjpegSink *v4lmjpegsink = GST_V4LMJPEGSINK (user_data);
  GstBuffer *buffer = NULL;
  guint8 *data;
  gint num;

  if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsink)))
    return NULL;
  if (v4lmjpegsink->breq.size < size) {
    GST_DEBUG ("Requested buffer size is too large (%d > %ld)",
        size, v4lmjpegsink->breq.size);
    return NULL;
  }
  if (!gst_v4lmjpegsink_wait_frame (v4lmjpegsink, &num))
    return NULL;
  data = gst_v4lmjpegsink_get_buffer (v4lmjpegsink, num);
  if (!data)
    return NULL;
  buffer = gst_buffer_new ();
  GST_BUFFER_DATA (buffer) = data;
  GST_BUFFER_MAXSIZE (buffer) = v4lmjpegsink->breq.size;
  GST_BUFFER_SIZE (buffer) = size;
  GST_BUFFER_POOL (buffer) = pool;
  GST_BUFFER_POOL_PRIVATE (buffer) = GINT_TO_POINTER (num);

  /* with this flag set, we don't need our own buffer_free() function */
  GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_DONTFREE);

  return buffer;
}
예제 #3
0
/**
 * gst_v4l2_buffer_pool_new:
 * @obj:  the v4l2 object owning the pool
 *
 * Construct a new buffer pool.
 *
 * Returns: the new pool, use gst_object_unref() to free resources
 */
GstBufferPool *
gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
{
  GstV4l2BufferPool *pool;
  GstStructure *s;
  gint fd;

  fd = v4l2_dup (obj->video_fd);
  if (fd < 0)
    goto dup_failed;

  pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, NULL);
  pool->video_fd = fd;
  pool->obj = obj;

  s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
  gst_buffer_pool_config_set_params (s, caps, obj->sizeimage, 2, 0);
  gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), s);

  return GST_BUFFER_POOL (pool);

  /* ERRORS */
dup_failed:
  {
    GST_DEBUG ("failed to dup fd %d (%s)", errno, g_strerror (errno));
    return NULL;
  }
}
static gboolean
mark_meta_pooled (GstBuffer * buffer, GstMeta ** meta, gpointer user_data)
{
  GST_DEBUG_OBJECT (GST_BUFFER_POOL (user_data),
      "marking meta %p as POOLED in buffer %p", *meta, buffer);
  GST_META_FLAG_SET (*meta, GST_META_FLAG_POOLED);
  GST_META_FLAG_SET (*meta, GST_META_FLAG_LOCKED);

  return TRUE;
}
예제 #5
0
void
gst_v4l2_buffer_pool_set_other_pool (GstV4l2BufferPool * pool,
    GstBufferPool * other_pool)
{
  g_return_if_fail (!gst_buffer_pool_is_active (GST_BUFFER_POOL (pool)));

  if (pool->other_pool)
    gst_object_unref (pool->other_pool);
  pool->other_pool = gst_object_ref (other_pool);
}
예제 #6
0
static gboolean
gst_v4l2_video_dec_negotiate (GstVideoDecoder * decoder)
{
  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);

  /* We don't allow renegotiation without carefull disabling the pool */
  if (self->v4l2capture->pool &&
      gst_buffer_pool_is_active (GST_BUFFER_POOL (self->v4l2capture->pool)))
    return TRUE;

  return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
}
예제 #7
0
GstBufferPool *
gst_omx_buffer_pool_new (GstElement * element, GstOMXComponent * component,
    GstOMXPort * port)
{
  GstOMXBufferPool *pool;

  pool = g_object_new (gst_omx_buffer_pool_get_type (), NULL);
  pool->element = gst_object_ref (element);
  pool->component = component;
  pool->port = port;

  return GST_BUFFER_POOL (pool);
}
예제 #8
0
static void
gst_wayland_buffer_pool_finalize (GObject * object)
{
  GstWaylandBufferPool *pool = GST_WAYLAND_BUFFER_POOL_CAST (object);

  if (pool->wl_pool)
    gst_wayland_buffer_pool_stop (GST_BUFFER_POOL (pool));

  g_mutex_clear (&pool->buffers_map_mutex);
  g_hash_table_unref (pool->buffers_map);

  g_object_unref (pool->display);

  G_OBJECT_CLASS (gst_wayland_buffer_pool_parent_class)->finalize (object);
}
예제 #9
0
static void
gst_v4lmjpegsink_chain (GstPad * pad, GstData * _data)
{
  GstBuffer *buf = GST_BUFFER (_data);
  GstV4lMjpegSink *v4lmjpegsink;
  gint num;

  g_return_if_fail (pad != NULL);
  g_return_if_fail (GST_IS_PAD (pad));
  g_return_if_fail (buf != NULL);

  v4lmjpegsink = GST_V4LMJPEGSINK (gst_pad_get_parent (pad));

  if (v4lmjpegsink->clock) {
    GST_DEBUG ("videosink: clock wait: %" G_GUINT64_FORMAT,
        GST_BUFFER_TIMESTAMP (buf));

    gst_element_wait (GST_ELEMENT (v4lmjpegsink), GST_BUFFER_TIMESTAMP (buf));
  }
#if 0
  if (GST_BUFFER_POOL (buf) == v4lmjpegsink->bufferpool) {
    num = GPOINTER_TO_INT (GST_BUFFER_POOL_PRIVATE (buf));
    gst_v4lmjpegsink_play_frame (v4lmjpegsink, num);
  } else {
#endif
    /* check size */
    if (GST_BUFFER_SIZE (buf) > v4lmjpegsink->breq.size) {
      GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, WRITE, (NULL),
          ("Buffer too big (%d KB), max. buffersize is %ld KB",
              GST_BUFFER_SIZE (buf) / 1024, v4lmjpegsink->breq.size / 1024));
      return;
    }

    /* put JPEG data to the device */
    gst_v4lmjpegsink_wait_frame (v4lmjpegsink, &num);
    memcpy (gst_v4lmjpegsink_get_buffer (v4lmjpegsink, num),
        GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
    gst_v4lmjpegsink_play_frame (v4lmjpegsink, num);
#if 0
  }
#endif

  g_signal_emit (G_OBJECT (v4lmjpegsink),
      gst_v4lmjpegsink_signals[SIGNAL_FRAME_DISPLAYED], 0);

  gst_buffer_unref (buf);
}
예제 #10
0
static void
gst_v4l2_buffer_pool_group_released (GstV4l2BufferPool * pool)
{
  GstBufferPoolAcquireParams params = { 0 };
  GstBuffer *buffer = NULL;
  GstFlowReturn ret;

  GST_DEBUG_OBJECT (pool, "A buffer was lost, reallocating it");

  params.flags =
      (GstBufferPoolAcquireFlags) GST_V4L2_BUFFER_POOL_ACQUIRE_FLAG_RESURRECT;
  ret =
      gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (pool), &buffer, &params);

  if (ret == GST_FLOW_OK)
    gst_buffer_unref (buffer);
}
예제 #11
0
void
gst_droid_cam_src_stream_window_clear (GstDroidCamSrcStreamWindow * win)
{
  GST_DEBUG ("stream window clear");

  g_mutex_lock (&win->lock);

  if (win->pool) {
    if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (win->pool), FALSE)) {
      GST_ERROR ("failed to deactivate buffer pool");
    }

    gst_object_unref (win->pool);

    win->pool = NULL;
  }

  g_mutex_unlock (&win->lock);
}
예제 #12
0
void
gst_droid_cam_src_stream_window_destroy (GstDroidCamSrcStreamWindow * win)
{
  GST_DEBUG ("stream window destroy");

  gst_object_unref (win->allocator);
  win->allocator = NULL;

  g_mutex_clear (&win->lock);

  if (win->pool) {
    if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (win->pool), FALSE)) {
      GST_ERROR ("failed to deactivate buffer pool");
    }

    gst_object_unref (win->pool);
  }

  g_slice_free (GstDroidCamSrcStreamWindow, win);
}
예제 #13
0
static GstFlowReturn
gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame)
{
  GstV4l2Error error = GST_V4L2_ERROR_INIT;
  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
  GstFlowReturn ret = GST_FLOW_OK;
  gboolean processed = FALSE;
  GstBuffer *tmp;

  GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number);

  if (G_UNLIKELY (!g_atomic_int_get (&self->active)))
    goto flushing;

  if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2output))) {
    if (!self->input_state)
      goto not_negotiated;
    if (!gst_v4l2_object_set_format (self->v4l2output, self->input_state->caps,
          &error))
      goto not_negotiated;
  }

  if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) {
    GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool);
    GstVideoInfo info;
    GstVideoCodecState *output_state;
    GstBuffer *codec_data;
    GstCaps *acquired_caps, *available_caps, *caps, *filter;
    GstStructure *st;

    GST_DEBUG_OBJECT (self, "Sending header");

    codec_data = self->input_state->codec_data;

    /* We are running in byte-stream mode, so we don't know the headers, but
     * we need to send something, otherwise the decoder will refuse to
     * intialize.
     */
    if (codec_data) {
      gst_buffer_ref (codec_data);
    } else {
      codec_data = gst_buffer_ref (frame->input_buffer);
      processed = TRUE;
    }

    /* Ensure input internal pool is active */
    if (!gst_buffer_pool_is_active (pool)) {
      GstStructure *config = gst_buffer_pool_get_config (pool);
      gst_buffer_pool_config_set_params (config, self->input_state->caps,
          self->v4l2output->info.size, 2, 2);

      /* There is no reason to refuse this config */
      if (!gst_buffer_pool_set_config (pool, config))
        goto activate_failed;

      if (!gst_buffer_pool_set_active (pool, TRUE))
        goto activate_failed;
    }

    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
    ret =
        gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
            v4l2output->pool), &codec_data);
    GST_VIDEO_DECODER_STREAM_LOCK (decoder);

    gst_buffer_unref (codec_data);

    /* For decoders G_FMT returns coded size, G_SELECTION returns visible size
     * in the compose rectangle. gst_v4l2_object_acquire_format() checks both
     * and returns the visible size as with/height and the coded size as
     * padding. */
    if (!gst_v4l2_object_acquire_format (self->v4l2capture, &info))
      goto not_negotiated;

    /* Create caps from the acquired format, remove the format field */
    acquired_caps = gst_video_info_to_caps (&info);
    st = gst_caps_get_structure (acquired_caps, 0);
    gst_structure_remove_field (st, "format");

    /* Probe currently available pixel formats */
    available_caps = gst_v4l2_object_probe_caps (self->v4l2capture, NULL);
    available_caps = gst_caps_make_writable (available_caps);

    /* Replace coded size with visible size, we want to negotiate visible size
     * with downstream, not coded size. */
    gst_caps_map_in_place (available_caps, gst_v4l2_video_remove_padding, self);

    filter = gst_caps_intersect_full (available_caps, acquired_caps,
        GST_CAPS_INTERSECT_FIRST);
    gst_caps_unref (acquired_caps);
    gst_caps_unref (available_caps);
    caps = gst_pad_peer_query_caps (decoder->srcpad, filter);
    gst_caps_unref (filter);

    GST_DEBUG_OBJECT (self, "Possible decoded caps: %" GST_PTR_FORMAT, caps);
    if (gst_caps_is_empty (caps)) {
      gst_caps_unref (caps);
      goto not_negotiated;
    }

    /* Fixate pixel format */
    caps = gst_caps_fixate (caps);

    GST_DEBUG_OBJECT (self, "Chosen decoded caps: %" GST_PTR_FORMAT, caps);

    /* Try to set negotiated format, on success replace acquired format */
    if (gst_v4l2_object_set_format (self->v4l2capture, caps, &error))
      gst_video_info_from_caps (&info, caps);
    else
      gst_v4l2_clear_error (&error);
    gst_caps_unref (caps);

    output_state = gst_video_decoder_set_output_state (decoder,
        info.finfo->format, info.width, info.height, self->input_state);

    /* Copy the rest of the information, there might be more in the future */
    output_state->info.interlace_mode = info.interlace_mode;
    gst_video_codec_state_unref (output_state);

    if (!gst_video_decoder_negotiate (decoder)) {
      if (GST_PAD_IS_FLUSHING (decoder->srcpad))
        goto flushing;
      else
        goto not_negotiated;
    }

    /* Ensure our internal pool is activated */
    if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (self->v4l2capture->pool),
            TRUE))
      goto activate_failed;
  }

  if (g_atomic_int_get (&self->processing) == FALSE) {
    /* It's possible that the processing thread stopped due to an error */
    if (self->output_flow != GST_FLOW_OK &&
        self->output_flow != GST_FLOW_FLUSHING) {
      GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving");
      ret = self->output_flow;
      goto drop;
    }

    GST_DEBUG_OBJECT (self, "Starting decoding thread");

    /* Start the processing task, when it quits, the task will disable input
     * processing to unlock input if draining, or prevent potential block */
    g_atomic_int_set (&self->processing, TRUE);
    if (!gst_pad_start_task (decoder->srcpad,
            (GstTaskFunction) gst_v4l2_video_dec_loop, self,
            (GDestroyNotify) gst_v4l2_video_dec_loop_stopped))
      goto start_task_failed;
  }

  if (!processed) {
    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
    ret =
        gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->v4l2output->
            pool), &frame->input_buffer);
    GST_VIDEO_DECODER_STREAM_LOCK (decoder);

    if (ret == GST_FLOW_FLUSHING) {
      if (g_atomic_int_get (&self->processing) == FALSE)
        ret = self->output_flow;
      goto drop;
    } else if (ret != GST_FLOW_OK) {
      goto process_failed;
    }
  }

  /* No need to keep input arround */
  tmp = frame->input_buffer;
  frame->input_buffer = gst_buffer_new ();
  gst_buffer_copy_into (frame->input_buffer, tmp,
      GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
      GST_BUFFER_COPY_META, 0, 0);
  gst_buffer_unref (tmp);

  gst_video_codec_frame_unref (frame);
  return ret;

  /* ERRORS */
not_negotiated:
  {
    GST_ERROR_OBJECT (self, "not negotiated");
    ret = GST_FLOW_NOT_NEGOTIATED;
    gst_v4l2_error (self, &error);
    goto drop;
  }
activate_failed:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
        (_("Failed to allocate required memory.")),
        ("Buffer pool activation failed"));
    ret = GST_FLOW_ERROR;
    goto drop;
  }
flushing:
  {
    ret = GST_FLOW_FLUSHING;
    goto drop;
  }

start_task_failed:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
        (_("Failed to start decoding thread.")), (NULL));
    g_atomic_int_set (&self->processing, FALSE);
    ret = GST_FLOW_ERROR;
    goto drop;
  }
process_failed:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
        (_("Failed to process frame.")),
        ("Maybe be due to not enough memory or failing driver"));
    ret = GST_FLOW_ERROR;
    goto drop;
  }
drop:
  {
    gst_video_decoder_drop_frame (decoder, frame);
    return ret;
  }
}
static GstFlowReturn
gst_v4l2_transform_prepare_output_buffer (GstBaseTransform * trans,
    GstBuffer * inbuf, GstBuffer ** outbuf)
{
  GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
  GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool);
  GstFlowReturn ret = GST_FLOW_OK;
  GstBaseTransformClass *bclass = GST_BASE_TRANSFORM_CLASS (parent_class);

  if (gst_base_transform_is_passthrough (trans)) {
    GST_DEBUG_OBJECT (self, "Passthrough, no need to do anything");
    *outbuf = inbuf;
    goto beach;
  }

  /* Ensure input internal pool is active */
  if (!gst_buffer_pool_is_active (pool)) {
    GstStructure *config = gst_buffer_pool_get_config (pool);
    gst_buffer_pool_config_set_params (config, self->incaps,
        self->v4l2output->info.size, 2, 2);

    /* There is no reason to refuse this config */
    if (!gst_buffer_pool_set_config (pool, config))
      goto activate_failed;

    if (!gst_buffer_pool_set_active (pool, TRUE))
      goto activate_failed;
  }

  GST_DEBUG_OBJECT (self, "Queue input buffer");
  ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (pool), &inbuf);
  if (G_UNLIKELY (ret != GST_FLOW_OK))
    goto beach;

  do {
    pool = gst_base_transform_get_buffer_pool (trans);

    if (!gst_buffer_pool_set_active (pool, TRUE))
      goto activate_failed;

    GST_DEBUG_OBJECT (self, "Dequeue output buffer");
    ret = gst_buffer_pool_acquire_buffer (pool, outbuf, NULL);
    g_object_unref (pool);

    if (ret != GST_FLOW_OK)
      goto alloc_failed;

    pool = self->v4l2capture->pool;
    ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (pool), outbuf);

  } while (ret == GST_V4L2_FLOW_CORRUPTED_BUFFER);

  if (ret != GST_FLOW_OK) {
    gst_buffer_unref (*outbuf);
    *outbuf = NULL;
  }

  if (bclass->copy_metadata)
    if (!bclass->copy_metadata (trans, inbuf, *outbuf)) {
      /* something failed, post a warning */
      GST_ELEMENT_WARNING (self, STREAM, NOT_IMPLEMENTED,
          ("could not copy metadata"), (NULL));
    }

beach:
  return ret;

activate_failed:
  GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
      ("failed to activate bufferpool"), ("failed to activate bufferpool"));
  g_object_unref (pool);
  return GST_FLOW_ERROR;

alloc_failed:
  GST_DEBUG_OBJECT (self, "could not allocate buffer from pool");
  return ret;
}
예제 #15
0
static void
gst_droidcamsrc_stream_window_reset_buffer_pool_locked
    (GstDroidCamSrcStreamWindow * win)
{
  GstStructure *config;
  GstCaps *caps;
  GstCapsFeatures *feature;

  GST_DEBUG ("stream window configure buffer pool");

  if (win->pool) {
    /* we will ignore the error here */
    if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (win->pool), FALSE)) {
      GST_WARNING ("Failed to deactivate buffer pool");
    }

    gst_object_unref (win->pool);
  }

  win->pool = gst_droid_cam_src_buffer_pool_new (win->info);

  if (!win->count || !win->width || !win->height || !win->usage || !win->format) {
    GST_ERROR ("incomplete configuration");
    goto clean_and_out;
  }

  config = gst_buffer_pool_get_config (GST_BUFFER_POOL (win->pool));
  if (!config) {
    GST_ERROR ("failed to get buffer pool config");
    goto clean_and_out;
  }

  /* TODO: 30 is hardcoded */
  caps = gst_caps_new_simple ("video/x-raw",
      "format", G_TYPE_STRING, "ENCODED",
      "width", G_TYPE_INT, win->width,
      "height", G_TYPE_INT, win->height,
      "framerate", GST_TYPE_FRACTION, 30, 1, NULL);
  feature = gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DROID_HANDLE, NULL);
  gst_caps_set_features (caps, 0, feature);

  gst_buffer_pool_config_set_params (config, caps, 0, win->count, win->count);
  gst_buffer_pool_config_set_allocator (config, win->allocator, NULL);

  gst_structure_set (config,
      GST_DROIDCAMSRC_BUFFER_POOL_USAGE_KEY, G_TYPE_INT, win->usage,
      GST_DROIDCAMSRC_BUFFER_POOL_WIDTH_KEY, G_TYPE_INT, win->width,
      GST_DROIDCAMSRC_BUFFER_POOL_HEIGHT_KEY, G_TYPE_INT, win->height,
      GST_DROIDCAMSRC_BUFFER_POOL_FORMAT_KEY, G_TYPE_INT, win->format, NULL);

  gst_caps_unref (caps);

  if (!gst_buffer_pool_set_config (GST_BUFFER_POOL (win->pool), config)) {
    GST_ERROR ("failed to set buffer pool config");
    goto clean_and_out;
  }

  if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (win->pool), TRUE)) {
    GST_ERROR ("failed to activate buffer pool");
    goto clean_and_out;
  }

  win->needs_reconfigure = FALSE;

  return;

clean_and_out:
  if (win->pool) {
    gst_object_unref (win->pool);
    win->pool = NULL;
  }
}
예제 #16
0
static int
gst_droidcamsrc_stream_window_dequeue_buffer (struct preview_stream_ops *w,
    buffer_handle_t ** buffer, int *stride)
{
  GstDroidCamSrcStreamWindow *win;
  GstBuffer *buff;
  GstFlowReturn ret;
  int trials;
  GstBufferPoolAcquireParams params;
  GstMemory *mem;
  struct ANativeWindowBuffer *native;
  int res;

  GST_DEBUG ("dequeue buffer %p", buffer);

  win = container_of (w, GstDroidCamSrcStreamWindow, window);

  g_mutex_lock (&win->lock);

retry:
  GST_DEBUG ("needs reconfigure? %d", win->needs_reconfigure);

  if (!win->pool || (win->pool && win->needs_reconfigure)) {
    /* create and re/configure the pool */
    gst_droidcamsrc_stream_window_reset_buffer_pool_locked (win);
  }

  if (!win->pool) {
    GST_ERROR ("failed to create buffer pool");
    res = -1;
    goto unlock_and_exit;
  }

  mem = NULL;
  trials = ACQUIRE_BUFFER_TRIALS;
  params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;

  while (trials > 0) {
    ret =
        gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (win->pool), &buff,
        &params);
    if (ret == GST_FLOW_OK) {
      /* we have our buffer */
      break;
    } else if (ret == GST_FLOW_ERROR || ret == GST_FLOW_FLUSHING) {
      /* no point in waiting */
      break;
    }

    /* we need to unlock here to allow buffers to be returned back */
    g_mutex_unlock (&win->lock);
    usleep (ACQUIRE_BUFFER_TIMEOUT);
    g_mutex_lock (&win->lock);
    if (win->needs_reconfigure) {
      /* out of here */
      goto retry;
    }

    --trials;
  }

  if (buff) {
    /* handover */
    mem = gst_buffer_peek_memory (buff, 0);
  } else if (ret == GST_FLOW_FLUSHING) {
    GST_INFO ("pool is flushing");
  } else {
    GST_WARNING ("failed to get a buffer");
  }

  if (!mem) {
    GST_ERROR ("no buffer memory found");

    res = -1;
    goto unlock_and_exit;
  }

  native = gst_memory_get_native_buffer (mem);
  if (!native) {
    GST_ERROR ("invalid buffer");
    gst_buffer_unref (buff);

    res = -1;
    goto unlock_and_exit;
  }

  *buffer = &native->handle;
  *stride = native->stride;

  GST_LOG ("dequeue buffer done %p", *buffer);

  res = 0;

unlock_and_exit:
  g_mutex_unlock (&win->lock);
  return res;
}
static GstFlowReturn
gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame)
{
  GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
  GstFlowReturn ret = GST_FLOW_OK;

  GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number);

  if (G_UNLIKELY (!g_atomic_int_get (&self->active)))
    goto flushing;

  if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2output))) {
    if (!self->input_state)
      goto not_negotiated;
    if (!gst_v4l2_object_set_format (self->v4l2output, self->input_state->caps))
      goto not_negotiated;
  }

  if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) {
    GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool);
    GstVideoInfo info;
    GstVideoCodecState *output_state;
    GstBuffer *codec_data;

    GST_DEBUG_OBJECT (self, "Sending header");

    codec_data = self->input_state->codec_data;

    /* We are running in byte-stream mode, so we don't know the headers, but
     * we need to send something, otherwise the decoder will refuse to
     * intialize.
     */
    if (codec_data) {
      gst_buffer_ref (codec_data);
    } else {
      codec_data = frame->input_buffer;
      frame->input_buffer = NULL;
    }

    /* Ensure input internal pool is active */
    if (!gst_buffer_pool_is_active (pool)) {
      GstStructure *config = gst_buffer_pool_get_config (pool);
      gst_buffer_pool_config_set_params (config, self->input_state->caps,
          self->v4l2output->info.size, 2, 2);

      /* There is no reason to refuse this config */
      if (!gst_buffer_pool_set_config (pool, config))
        goto activate_failed;

      if (!gst_buffer_pool_set_active (pool, TRUE))
        goto activate_failed;
    }

    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
    ret =
        gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
            v4l2output->pool), &codec_data);
    GST_VIDEO_DECODER_STREAM_LOCK (decoder);

    gst_buffer_unref (codec_data);

    if (!gst_v4l2_object_acquire_format (self->v4l2capture, &info))
      goto not_negotiated;

    output_state = gst_video_decoder_set_output_state (decoder,
        info.finfo->format, info.width, info.height, self->input_state);

    /* Copy the rest of the information, there might be more in the future */
    output_state->info.interlace_mode = info.interlace_mode;
    gst_video_codec_state_unref (output_state);

    if (!gst_video_decoder_negotiate (decoder)) {
      if (GST_PAD_IS_FLUSHING (decoder->srcpad))
        goto flushing;
      else
        goto not_negotiated;
    }

    /* Ensure our internal pool is activated */
    if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (self->v4l2capture->pool),
            TRUE))
      goto activate_failed;
  }

  if (g_atomic_int_get (&self->processing) == FALSE) {
    /* It's possible that the processing thread stopped due to an error */
    if (self->output_flow != GST_FLOW_OK &&
        self->output_flow != GST_FLOW_FLUSHING) {
      GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving");
      ret = self->output_flow;
      goto drop;
    }

    GST_DEBUG_OBJECT (self, "Starting decoding thread");

    /* Start the processing task, when it quits, the task will disable input
     * processing to unlock input if draining, or prevent potential block */
    g_atomic_int_set (&self->processing, TRUE);
    if (!gst_pad_start_task (decoder->srcpad,
            (GstTaskFunction) gst_v4l2_video_dec_loop, self,
            (GDestroyNotify) gst_v4l2_video_dec_loop_stopped))
      goto start_task_failed;
  }

  if (frame->input_buffer) {
    GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
    ret =
        gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->v4l2output->
            pool), &frame->input_buffer);
    GST_VIDEO_DECODER_STREAM_LOCK (decoder);

    if (ret == GST_FLOW_FLUSHING) {
      if (g_atomic_int_get (&self->processing) == FALSE)
        ret = self->output_flow;
      goto drop;
    } else if (ret != GST_FLOW_OK) {
      goto process_failed;
    }

    /* No need to keep input arround */
    gst_buffer_replace (&frame->input_buffer, NULL);
  }

  gst_video_codec_frame_unref (frame);
  return ret;

  /* ERRORS */
not_negotiated:
  {
    GST_ERROR_OBJECT (self, "not negotiated");
    ret = GST_FLOW_NOT_NEGOTIATED;
    goto drop;
  }
activate_failed:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
        (_("Failed to allocate required memory.")),
        ("Buffer pool activation failed"));
    ret = GST_FLOW_ERROR;
    goto drop;
  }
flushing:
  {
    ret = GST_FLOW_FLUSHING;
    goto drop;
  }

start_task_failed:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
        (_("Failed to start decoding thread.")), (NULL));
    g_atomic_int_set (&self->processing, FALSE);
    ret = GST_FLOW_ERROR;
    goto drop;
  }
process_failed:
  {
    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
        (_("Failed to process frame.")),
        ("Maybe be due to not enough memory or failing driver"));
    ret = GST_FLOW_ERROR;
    goto drop;
  }
drop:
  {
    gst_video_decoder_drop_frame (decoder, frame);
    return ret;
  }
}
예제 #18
0
/**
 * gst_v4l2_buffer_pool_new:
 * @obj:  the v4l2 object owning the pool
 *
 * Construct a new buffer pool.
 *
 * Returns: the new pool, use gst_object_unref() to free resources
 */
GstBufferPool *
gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
{
  GstV4l2BufferPool *pool;
  GstStructure *config;
  gchar *name, *parent_name;
  gint fd;

  fd = v4l2_dup (obj->video_fd);
  if (fd < 0)
    goto dup_failed;

  /* setting a significant unique name */
  parent_name = gst_object_get_name (GST_OBJECT (obj->element));
  name = g_strconcat (parent_name, ":", "pool:",
      V4L2_TYPE_IS_OUTPUT (obj->type) ? "sink" : "src", NULL);
  g_free (parent_name);

  pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL,
      "name", name, NULL);
  g_free (name);

  gst_poll_fd_init (&pool->pollfd);
  pool->pollfd.fd = fd;
  gst_poll_add_fd (pool->poll, &pool->pollfd);
  if (V4L2_TYPE_IS_OUTPUT (obj->type))
    gst_poll_fd_ctl_write (pool->poll, &pool->pollfd, TRUE);
  else
    gst_poll_fd_ctl_read (pool->poll, &pool->pollfd, TRUE);

  pool->video_fd = fd;
  pool->obj = obj;
  pool->can_poll_device = TRUE;

  pool->vallocator =
      gst_v4l2_allocator_new (GST_OBJECT (pool), obj->video_fd, &obj->format);
  if (pool->vallocator == NULL)
    goto allocator_failed;

  gst_object_ref (obj->element);

  config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
  gst_buffer_pool_config_set_params (config, caps, obj->info.size, 0, 0);
  /* This will simply set a default config, but will not configure the pool
   * because min and max are not valid */
  gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), config);

  return GST_BUFFER_POOL (pool);

  /* ERRORS */
dup_failed:
  {
    GST_ERROR ("failed to dup fd %d (%s)", errno, g_strerror (errno));
    return NULL;
  }
allocator_failed:
  {
    GST_ERROR_OBJECT (pool, "Failed to create V4L2 allocator");
    return NULL;
  }
}
예제 #19
0
static int
gst_droidcamsrc_stream_window_enqueue_buffer (struct preview_stream_ops *w,
    buffer_handle_t * buffer)
{
  GstDroidCamSrcStreamWindow *win;
  GstDroidCamSrc *src;
  GstBuffer *buff;
  int ret;
  GstVideoCropMeta *meta;

  GST_DEBUG ("enqueue buffer %p", buffer);

  win = container_of (w, GstDroidCamSrcStreamWindow, window);

  g_mutex_lock (&win->lock);

  src = GST_DROIDCAMSRC (GST_PAD_PARENT (win->pad->pad));

  buff = gst_droidcamsrc_stream_window_get_buffer (buffer);

  if (!buff) {
    GST_ERROR ("no buffer corresponding to handle %p", buffer);
    ret = -1;
    goto unlock_and_out;
  }

  /* if the buffer pool is not our current pool then just release it */
  if (buff->pool != GST_BUFFER_POOL (win->pool)) {
    GST_DEBUG ("releasing old buffer %p", buffer);
    gst_buffer_unref (buff);
    ret = 0;
    goto unlock_and_out;
  }

  /* now update crop meta */
  meta = gst_buffer_get_video_crop_meta (buff);
  meta->x = win->left;
  meta->y = win->top;
  meta->width = win->right - win->left;
  meta->height = win->bottom - win->top;

  GST_LOG
      ("window width = %d, height = %d, crop info: left = %d, top = %d, right = %d, bottom = %d",
      win->width, win->height, win->left, win->top, win->right, win->bottom);

  g_mutex_unlock (&win->lock);

  /* it should be safe to access that variable without locking.
   * pad gets activated during READY_TO_PAUSED and deactivated during
   * PAUSED_TO_READY while we start the preview during PAUSED_TO_PLAYING
   * and stop it during PLAYING_TO_PAUSED.
   */
  if (!win->pad->running) {
    gst_buffer_unref (buff);
    GST_DEBUG ("unreffing buffer because pad task is not running");
    ret = 0;
    goto unlock_pad_and_out;
  }
  // TODO: duration, offset, offset_end ...
  gst_droidcamsrc_timestamp (src, buff);

  g_mutex_lock (&win->pad->queue_lock);

  g_queue_push_tail (win->pad->queue, buff);

  g_cond_signal (&win->pad->cond);

  ret = 0;
  goto unlock_pad_and_out;

unlock_and_out:
  g_mutex_unlock (&win->lock);

  return ret;

unlock_pad_and_out:
  g_mutex_unlock (&win->pad->queue_lock);

  return ret;
}