Example #1
0
static void
gst_droidcamsrc_dev_preview_metadata_callback (void *user,
    const DroidMediaCameraFace * faces, size_t num_faces)
{
  GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));
  GstStructure *s;
  gint width, height;
  GValue regions = G_VALUE_INIT;
  gint i;

  GST_DEBUG_OBJECT (src, "dev preview metadata callback");

  GST_INFO_OBJECT (src, "camera detected %d faces", num_faces);

  GST_OBJECT_LOCK (src);
  width = src->width;
  height = src->height;
  GST_OBJECT_UNLOCK (src);

  s = gst_structure_new ("regions-of-interest", "frame-width", G_TYPE_UINT,
      width, "frame-height", G_TYPE_UINT, height, "type", G_TYPE_UINT,
      GST_DROIDCAMSRC_ROI_FACE_AREA, NULL);

  g_value_init (&regions, GST_TYPE_LIST);

  for (i = 0; i < num_faces; i++) {
    GValue region = G_VALUE_INIT;
    int x, y, w, h, r, b;
    GstStructure *rs;

    g_value_init (&region, GST_TYPE_STRUCTURE);

    GST_DEBUG_OBJECT (src,
        "face %d: score=%d, left=%d, top=%d, right=%d, bottom=%d", i,
        faces[i].score, faces[i].left, faces[i].top, faces[i].right,
        faces[i].bottom);
    x = gst_util_uint64_scale (faces[i].left + 1000, width, 2000);
    y = gst_util_uint64_scale (faces[i].top + 1000, height, 2000);
    r = gst_util_uint64_scale (faces[i].right + 1000, width, 2000);
    b = gst_util_uint64_scale (faces[i].bottom + 1000, height, 2000);
    w = r - x;
    h = b - y;
    rs = gst_structure_new ("region-of-interest",
        "region-x", G_TYPE_UINT, x,
        "region-y", G_TYPE_UINT, y,
        "region-w", G_TYPE_UINT, w,
        "region-h", G_TYPE_UINT, h,
        "region-id", G_TYPE_INT, faces[i].id,
        "region-score", G_TYPE_INT, faces[i].score, NULL);

    gst_value_set_structure (&region, rs);
    gst_structure_free (rs);
    gst_value_list_append_value (&regions, &region);
    g_value_unset (&region);
  }

  gst_structure_take_value (s, "regions", &regions);
  gst_droidcamsrc_post_message (src, s);
}
Example #2
0
static void
gst_droidcamsrc_dev_prepare_buffer (GstDroidCamSrcDev * dev, GstBuffer * buffer,
    DroidMediaRect rect, int width, int height, GstVideoFormat format)
{
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));
  GstVideoCropMeta *crop;

  GST_LOG_OBJECT (src, "prepare buffer %" GST_PTR_FORMAT, buffer);

  gst_droidcamsrc_timestamp (src, buffer);

  crop = gst_buffer_add_video_crop_meta (buffer);
  crop->x = rect.left;
  crop->y = rect.top;
  crop->width = rect.right - rect.left;
  crop->height = rect.bottom - rect.top;

  gst_buffer_add_gst_buffer_orientation_meta (buffer,
      dev->info->orientation, dev->info->direction);

  gst_buffer_add_video_meta (buffer, GST_VIDEO_FRAME_FLAG_NONE,
      format, width, height);

  GST_LOG_OBJECT (src, "preview info: w=%d, h=%d, crop: x=%d, y=%d, w=%d, h=%d",
      width, height, crop->x, crop->y, crop->width, crop->height);
}
Example #3
0
gboolean
gst_droidcamsrc_dev_start (GstDroidCamSrcDev * dev, gboolean apply_settings)
{
  gboolean ret = FALSE;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));

  g_rec_mutex_lock (dev->lock);

  if (dev->running) {
    GST_WARNING_OBJECT (src, "preview is already running");
    ret = TRUE;
    goto out;
  }

  GST_DEBUG_OBJECT (src, "dev start");

  if (!gst_buffer_pool_set_active (dev->pool, TRUE)) {
    GST_ERROR_OBJECT (src, "Failed to activate buffer pool");
    goto out;
  }

  if (apply_settings) {
    gst_droidcamsrc_apply_mode_settings (src, SET_ONLY);
  }

  /* now set params */
  if (!gst_droidcamsrc_dev_set_params (dev)) {
    goto out;
  }

  if (dev->use_raw_data) {
    GST_INFO_OBJECT (src, "Using raw data mode");
    droid_media_camera_set_preview_callback_flags (dev->cam,
        dev->c.CAMERA_FRAME_CALLBACK_FLAG_CAMERA);
  } else {
    GST_INFO_OBJECT (src, "Using native buffers mode");
    droid_media_camera_set_preview_callback_flags (dev->cam,
        dev->c.CAMERA_FRAME_CALLBACK_FLAG_NOOP);
  }

  if (!droid_media_camera_start_preview (dev->cam)) {
    GST_ERROR_OBJECT (src, "error starting preview");
    goto out;
  }

  dev->running = TRUE;

  ret = TRUE;

out:
  if (ret != TRUE) {
    gst_buffer_pool_set_active (dev->pool, FALSE);
  }

  g_rec_mutex_unlock (dev->lock);
  return ret;
}
Example #4
0
static void
gst_droidcamsrc_dev_raw_image_notify_callback (void *user)
{
  GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));

  GST_DEBUG_OBJECT (src, "dev raw image notify callback");

  GST_FIXME_OBJECT (src, "implement me");
}
Example #5
0
static void
gst_droidcamsrc_dev_postview_frame_callback (void *user,
    G_GNUC_UNUSED DroidMediaData * mem)
{
  GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));

  GST_DEBUG_OBJECT (src, "dev postview frame callback");

  GST_FIXME_OBJECT (src, "implement me");
}
Example #6
0
static void
gst_droidcamsrc_dev_zoom_callback (void *user, G_GNUC_UNUSED int value,
    G_GNUC_UNUSED int arg)
{
  GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));

  GST_DEBUG_OBJECT (src, "dev zoom callback");

  GST_FIXME_OBJECT (src, "implement me");
}
Example #7
0
static void
gst_droidcamsrc_dev_error_callback (void *user, int arg)
{
  GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));

  GST_DEBUG_OBJECT (src, "dev error callback");

  GST_ELEMENT_ERROR (src, LIBRARY, FAILED, (NULL),
      ("error 0x%x from camera HAL", arg));
}
Example #8
0
static void
gst_droidcamsrc_dev_focus_move_callback (void *user, int arg)
{
  GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));
  GstStructure *s;

  GST_DEBUG_OBJECT (src, "dev focus move callback");

  /* TODO: an idea could be to query focus state when moving stops or starts
   * and use that to emulate realtime reporting of CAF status */

  GST_LOG_OBJECT (src, "focus move %d", arg);

  s = gst_structure_new ("focus-move", "status", G_TYPE_INT, arg, NULL);
  gst_droidcamsrc_post_message (src, s);
}
Example #9
0
static void
gst_droidcamsrc_dev_shutter_callback (void *user)
{
  GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));

  GST_DEBUG_OBJECT (src, "dev shutter callback");

  g_rec_mutex_lock (dev->lock);

  if (!dev->img->image_start_sent) {
    gst_droidcamsrc_post_message (src,
        gst_structure_new_empty (GST_DROIDCAMSRC_CAPTURE_START));
    dev->img->image_start_sent = TRUE;
  }

  g_rec_mutex_unlock (dev->lock);
}
Example #10
0
static void
gst_droidcamsrc_dev_focus_callback (void *user, int arg)
{
  GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));
  GstStructure *s;
  gint status;

  GST_DEBUG_OBJECT (src, "dev focus callback");

  if (arg) {
    status = GST_PHOTOGRAPHY_FOCUS_STATUS_SUCCESS;
  } else {
    status = GST_PHOTOGRAPHY_FOCUS_STATUS_FAIL;
  }

  s = gst_structure_new (GST_PHOTOGRAPHY_AUTOFOCUS_DONE, "status",
      G_TYPE_INT, status, NULL);
  gst_droidcamsrc_post_message (src, s);
}
Example #11
0
gboolean
gst_droidcamsrc_dev_start_video_recording (GstDroidCamSrcDev * dev)
{
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));
  gboolean ret = FALSE;

  GST_DEBUG ("dev start video recording");

  gst_buffer_pool_set_flushing (dev->pool, TRUE);

  g_mutex_lock (&dev->vidsrc->lock);
  dev->vidsrc->pushed_buffers = 0;
  g_mutex_unlock (&dev->vidsrc->lock);

  g_rec_mutex_lock (dev->lock);
  if (dev->use_raw_data) {
    GST_ELEMENT_ERROR (src, STREAM, FORMAT, ("Cannot record video in raw mode"),
        (NULL));
    goto out;
  }

  dev->vid->running = TRUE;
  dev->vid->eos_sent = FALSE;
  dev->vid->video_frames = 0;
  dev->vid->queued_frames = 0;

  if (!droid_media_camera_start_recording (dev->cam)) {
    GST_ELEMENT_ERROR (src, LIBRARY, FAILED, ("error starting video recording"),
        (NULL));
    goto out;
  }

  ret = TRUE;

out:
  g_rec_mutex_unlock (dev->lock);

  gst_buffer_pool_set_flushing (dev->pool, FALSE);

  return ret;
}
Example #12
0
gboolean
gst_droidcamsrc_dev_open (GstDroidCamSrcDev * dev, GstDroidCamSrcCamInfo * info)
{
  GstDroidCamSrc *src;

  g_rec_mutex_lock (dev->lock);

  src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));

  GST_DEBUG_OBJECT (src, "dev open");

  dev->info = info;
  dev->cam = droid_media_camera_connect (dev->info->num);

  if (!dev->cam) {
    g_rec_mutex_unlock (dev->lock);

    GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), ("error opening camera"));
    return FALSE;
  }

  dev->queue = droid_media_camera_get_buffer_queue (dev->cam);

  if (!droid_media_camera_lock (dev->cam)) {
    droid_media_camera_disconnect (dev->cam);
    dev->cam = NULL;
    dev->queue = NULL;

    GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), ("error locking camera"));
    return FALSE;
  }

  /* disable shutter sound */
  gst_droidcamsrc_dev_send_command (dev,
      dev->c.CAMERA_CMD_ENABLE_SHUTTER_SOUND, 0, 0);

  g_rec_mutex_unlock (dev->lock);

  return TRUE;
}
Example #13
0
static void
gst_droidcamsrc_dev_preview_frame_callback (void *user,
    G_GNUC_UNUSED DroidMediaData * mem)
{
  GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));
  GstDroidCamSrcPad *pad = dev->vfsrc;
  GstBuffer *buffer;
  gsize width, height;
  DroidMediaRect rect;

  GST_DEBUG_OBJECT (src, "dev preview frame callback");

  /* We are accessing this without a lock because:
   * 1) We should not be called while preview is stopped and this is when we manipulate this flag
   * 2) We can get called when we start the preview and we will deadlock because the lock is already held
   */
  if (!dev->use_raw_data) {
    GST_WARNING_OBJECT (src,
        "preview frame callback called while not when we do not expect it");
    return;
  }

  buffer = gst_buffer_new_allocate (NULL, mem->size, NULL);
  gst_buffer_fill (buffer, 0, mem->data, mem->size);

  GST_OBJECT_LOCK (src);
  width = src->width;
  height = src->height;
  rect = src->crop_rect;
  GST_OBJECT_UNLOCK (src);

  gst_droidcamsrc_dev_prepare_buffer (dev, buffer, rect, width, height,
      GST_VIDEO_FORMAT_NV21);

  g_mutex_lock (&pad->lock);
  g_queue_push_tail (pad->queue, buffer);
  g_cond_signal (&pad->cond);
  g_mutex_unlock (&pad->lock);
}
Example #14
0
static void
gst_droidcamsrc_dev_frame_available (void *user)
{
  GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));
  GstDroidCamSrcPad *pad = dev->vfsrc;
  DroidMediaBuffer *buffer;
  GstMemory *mem;
  DroidMediaRect rect;
  guint width, height;
  GstBuffer *buff;
  DroidMediaBufferCallbacks cb;
  GstFlowReturn flow_ret;
  DroidMediaBufferInfo info;

  GST_DEBUG_OBJECT (src, "frame available");

  if (!pad->running) {
    GST_DEBUG_OBJECT (src, "vfsrc pad task is not running");

    goto acquire_and_release;
  }

  /* We are accessing this without a lock because:
   * 1) We should not be called while preview is stopped and this is when we manipulate this flag
   * 2) We can get called when we start the preview and we will deadlock because the lock is already held
   */
  if (dev->use_raw_data) {
    goto acquire_and_release;
  }

  flow_ret = gst_buffer_pool_acquire_buffer (dev->pool, &buff, NULL);
  if (flow_ret != GST_FLOW_OK) {
    GST_WARNING_OBJECT (src, "failed to acquire buffer from pool: %s",
        gst_flow_get_name (flow_ret));

    goto acquire_and_release;
  }

  cb.ref = (DroidMediaCallback) gst_buffer_ref;
  cb.unref = (DroidMediaCallback) gst_buffer_unref;
  cb.data = buff;

  mem =
      gst_droid_media_buffer_allocator_alloc (dev->media_allocator, dev->queue,
      &cb);
  if (!mem) {
    GST_ERROR_OBJECT (src, "failed to acquire buffer from droidmedia");
    gst_buffer_unref (buff);
    return;
  }

  buffer = gst_droid_media_buffer_memory_get_buffer (mem);

  gst_buffer_insert_memory (buff, 0, mem);
  gst_droidcamsrc_timestamp (src, buff);

  rect = droid_media_buffer_get_crop_rect (buffer);
  width = droid_media_buffer_get_width (buffer);
  height = droid_media_buffer_get_height (buffer);

  gst_droidcamsrc_dev_prepare_buffer (dev, buff, rect, width, height,
      GST_VIDEO_FORMAT_YV12);

  g_mutex_lock (&pad->lock);
  g_queue_push_tail (pad->queue, buff);
  g_cond_signal (&pad->cond);
  g_mutex_unlock (&pad->lock);

  GST_OBJECT_LOCK (src);
  src->crop_rect = rect;
  GST_OBJECT_UNLOCK (src);
  return;

acquire_and_release:
  if (droid_media_buffer_queue_acquire_and_release (dev->queue, &info)) {
    GST_OBJECT_LOCK (src);
    src->crop_rect = info.crop_rect;
    GST_OBJECT_UNLOCK (src);
  }
}
Example #15
0
static void
gst_droidcamsrc_dev_compressed_image_callback (void *user, DroidMediaData * mem)
{
  GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));
  size_t size = mem->size;
  void *data = mem->data;
  GstBuffer *buffer;
  GstTagList *tags;
  GstEvent *event = NULL;
  void *d;

  GST_DEBUG_OBJECT (src, "dev compressed image callback");

  if (!data) {
    GST_ERROR_OBJECT (src, "invalid memory from camera hal");
    return;
  }

  /* TODO: research a way to get rid of the memcpy */
  d = g_malloc (size);
  memcpy (d, data, size);
  buffer = gst_buffer_new_wrapped (d, size);
  if (!dev->img->image_preview_sent) {
    gst_droidcamsrc_post_message (src,
        gst_structure_new_empty (GST_DROIDCAMSRC_CAPTURE_END));
    /* TODO: generate and send preview if we don't get it from HAL */
    dev->img->image_preview_sent = TRUE;
  }

  gst_droidcamsrc_timestamp (src, buffer);

  tags = gst_droidcamsrc_exif_tags_from_jpeg_data (d, size);
  if (tags) {
    GST_INFO_OBJECT (src, "pushing tags %" GST_PTR_FORMAT, tags);
    event = gst_event_new_tag (tags);
  }

  g_mutex_lock (&dev->imgsrc->lock);

  // TODO: get the correct lock
  if (event) {
    src->imgsrc->pending_events =
        g_list_append (src->imgsrc->pending_events, event);
  }

  g_queue_push_tail (dev->imgsrc->queue, buffer);
  g_cond_signal (&dev->imgsrc->cond);
  g_mutex_unlock (&dev->imgsrc->lock);

  /* we need to start restart the preview
   * android demands this but GStreamer does not know about it.
   */
  g_rec_mutex_lock (dev->lock);
  dev->running = FALSE;
  g_rec_mutex_unlock (dev->lock);

  gst_droidcamsrc_dev_start (dev, TRUE);

  g_mutex_lock (&src->capture_lock);
  --src->captures;
  g_mutex_unlock (&src->capture_lock);

  g_object_notify (G_OBJECT (src), "ready-for-capture");
}
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;
}
Example #17
0
static void
gst_droidcamsrc_dev_video_frame_callback (void *user,
    DroidMediaCameraRecordingData * video_data)
{
  GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user;
  GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));
  void *data = droid_media_camera_recording_frame_get_data (video_data);
  GstBuffer *buffer;
  GstMemory *mem;
  GstDroidCamSrcDevVideoData *mem_data;
  gboolean drop_buffer;

  GST_DEBUG_OBJECT (src, "dev video frame callback");

  g_mutex_lock (&dev->vid->lock);

  /* TODO: not sure what to do with timestamp */

  /* unlikely but just in case */
  if (G_UNLIKELY (!data)) {
    GST_ERROR ("invalid memory from camera HAL");
    droid_media_camera_release_recording_frame (dev->cam, video_data);
    goto unlock_and_out;
  }

  /* TODO: this is bad */
  mem_data = g_slice_new0 (GstDroidCamSrcDevVideoData);
  mem_data->dev = dev;
  mem_data->data = video_data;

  buffer = gst_buffer_new ();
  mem = gst_wrapped_memory_allocator_wrap (dev->wrap_allocator,
      data, droid_media_camera_recording_frame_get_size (video_data),
      (GFunc) gst_droidcamsrc_dev_release_recording_frame, mem_data);
  gst_buffer_insert_memory (buffer, 0, mem);

  GST_BUFFER_OFFSET (buffer) = dev->vid->video_frames;
  GST_BUFFER_OFFSET_END (buffer) = ++dev->vid->video_frames;
  gst_droidcamsrc_timestamp (src, buffer);

  g_rec_mutex_lock (dev->lock);
  ++dev->vid->queued_frames;
  g_rec_mutex_unlock (dev->lock);

  drop_buffer = !dev->vid->running;

  if (drop_buffer) {
    GST_INFO_OBJECT (src,
        "dropping buffer because video recording is not running");
    gst_buffer_unref (buffer);
  } else {
    g_mutex_lock (&dev->vidsrc->lock);
    g_queue_push_tail (dev->vidsrc->queue, buffer);
    g_cond_signal (&dev->vidsrc->cond);
    g_mutex_unlock (&dev->vidsrc->lock);
  }

unlock_and_out:
  /* in case stop_video_recording() is waiting for us */
  g_cond_signal (&dev->vid->cond);
  g_mutex_unlock (&dev->vid->lock);
}