Exemplo n.º 1
0
static void
_map_data_gl (GstGLContext * context, struct map_data *transfer)
{
  GstGLBaseMemoryAllocatorClass *alloc_class;
  GstGLBaseMemory *mem = transfer->mem;
  GstMapInfo *info = transfer->info;

  alloc_class =
      GST_GL_BASE_MEMORY_ALLOCATOR_GET_CLASS (transfer->mem->mem.allocator);

  g_return_if_fail (alloc_class->map != NULL);

  g_mutex_lock (&mem->lock);

  GST_CAT_LOG (GST_CAT_GL_BASE_MEMORY, "mapping mem %p flags %04x", mem,
      info->flags);

  /* FIXME: validate map flags based on the memory domain */
  if (mem->map_count++ == 0)
    mem->map_flags = info->flags;
  else {
    /* assert that the flags are a subset of the first map flags */
    g_assert ((((GST_MAP_GL - 1) & info->flags) & mem->map_flags) != 0);
    GST_CAT_LOG (GST_CAT_GL_BASE_MEMORY, "multiple map no %d flags %04x "
        "all flags %04x", mem->map_count, info->flags, mem->map_flags);
  }

  if ((info->flags & GST_MAP_GL) != (mem->map_flags & GST_MAP_GL))
    mem->map_flags |= GST_MAP_GL;

  if (info->flags & GST_MAP_GL)
    mem->gl_map_count++;

  transfer->data = alloc_class->map (transfer->mem, transfer->info,
      transfer->size);

  if (transfer->data) {
    if (info->flags & GST_MAP_GL) {
      if (info->flags & GST_MAP_WRITE)
        GST_MINI_OBJECT_FLAG_SET (mem,
            GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
      GST_MEMORY_FLAG_UNSET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
    } else {
      if (info->flags & GST_MAP_WRITE)
        GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
      GST_MEMORY_FLAG_UNSET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
    }
  }

  g_mutex_unlock (&mem->lock);
}
Exemplo n.º 2
0
void test_is_writable()
{
  GstBuffer *buffer;
  GstMiniObject *mobj;
  
  xmlfile = "gstminiobject_test_is_writable";
    std_log(LOG_FILENAME_LINE, "Test Started test_is_writable");

  buffer = gst_buffer_new_and_alloc (4);
  mobj = GST_MINI_OBJECT (buffer);

  fail_unless (gst_mini_object_is_writable (mobj),
      "A buffer with one ref should be writable");

  GST_MINI_OBJECT_FLAG_SET (mobj, GST_MINI_OBJECT_FLAG_READONLY);
  fail_if (gst_mini_object_is_writable (mobj),
      "A buffer with READONLY set should not be writable");
  GST_MINI_OBJECT_FLAG_UNSET (mobj, GST_MINI_OBJECT_FLAG_READONLY);
  fail_unless (gst_mini_object_is_writable (mobj),
      "A buffer with one ref and READONLY not set should be writable");

  fail_if (gst_mini_object_ref (mobj) == NULL, "Could not ref the mobj");

  fail_if (gst_mini_object_is_writable (mobj),
      "A buffer with two refs should not be writable");
  
  std_log(LOG_FILENAME_LINE, "Test Successful");
    create_xml(0);
}
Exemplo n.º 3
0
static GstIOSGLMemory *
_ios_gl_memory_new (GstGLContext * context,
    GstAppleCoreVideoMemory * cv_mem,
    GstGLTextureTarget target,
    GstGLFormat tex_format,
    guint tex_id,
    GstVideoInfo * info,
    guint plane,
    GstVideoAlignment * valign, gpointer gl_data, GDestroyNotify gl_notify)
{
  GstIOSGLMemory *mem;

  mem = g_new0 (GstIOSGLMemory, 1);
  mem->gl_mem.tex_id = tex_id;
  mem->gl_mem.texture_wrapped = TRUE;
  gst_gl_memory_init (&mem->gl_mem, _ios_gl_memory_allocator, NULL, context,
      target, tex_format, NULL, info, plane, valign, NULL, NULL);
  mem->cv_mem = cv_mem;
  mem->gl_data = gl_data;
  mem->gl_notify = gl_notify;

  GST_MINI_OBJECT_FLAG_SET (mem, GST_MEMORY_FLAG_READONLY);

  return mem;
}
Exemplo n.º 4
0
static GstGLMemoryPBO *
_gl_mem_pbo_alloc (GstGLBaseMemoryAllocator * allocator,
    GstGLVideoAllocationParams * params)
{
  GstGLMemoryPBO *mem;
  guint alloc_flags;

  alloc_flags = params->parent.alloc_flags;

  g_return_val_if_fail (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_VIDEO,
      NULL);

  mem = g_new0 (GstGLMemoryPBO, 1);

  if (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE) {
    mem->mem.tex_id = params->parent.gl_handle;
    mem->mem.texture_wrapped = TRUE;
  }

  _gl_mem_init (mem, GST_ALLOCATOR_CAST (allocator), NULL,
      params->parent.context, params->target, params->parent.alloc_params,
      params->v_info, params->plane, params->valign, params->parent.user_data,
      params->parent.notify);

  if (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_GPU_HANDLE) {
    GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
  }
  if (alloc_flags & GST_GL_ALLOCATION_PARAMS_ALLOC_FLAG_WRAP_SYSMEM) {
    GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
    if (mem->pbo) {
      GST_MINI_OBJECT_FLAG_SET (mem->pbo,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD);
      mem->pbo->mem.data = params->parent.wrapped_data;
    }
    mem->mem.mem.data = params->parent.wrapped_data;
  }

  return mem;
}
Exemplo n.º 5
0
static void
_unmap_data_gl (GstGLContext * context, struct unmap_data *transfer)
{
  GstGLBaseBufferAllocatorClass *alloc_class;
  GstGLBaseBuffer *mem = transfer->mem;
  GstMapInfo *info = transfer->info;

  alloc_class =
      GST_GL_BASE_BUFFER_ALLOCATOR_GET_CLASS (transfer->mem->mem.allocator);

  g_return_if_fail (alloc_class->unmap_buffer != NULL);

  g_mutex_lock (&mem->lock);

  GST_CAT_LOG (GST_CAT_GL_BASE_BUFFER, "unmapping mem %p id %d flags %04x", mem,
      mem->id, info->flags);

  alloc_class->unmap_buffer (transfer->mem, transfer->info);

  if (info->flags & GST_MAP_GL && --mem->gl_map_count)
    /* unset the gl flag */
    mem->map_flags &= ~GST_MAP_GL;

  if (--mem->map_count <= 0) {
    mem->map_flags = 0;
  }

  if (info->flags & GST_MAP_GL) {
    if (info->flags & GST_MAP_WRITE)
      GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD);
  } else {
    if (info->flags & GST_MAP_WRITE)
      GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_BUFFER_FLAG_NEED_UPLOAD);
  }

  g_mutex_unlock (&mem->lock);
}
static void
test_transfer_allocator (const gchar * allocator_name)
{
  GstAllocator *gl_allocator;
  GstGLBaseMemoryAllocator *base_mem_alloc;
  GstVideoInfo v_info;
  GstMemory *mem, *mem2, *mem3;
  GstMapInfo map_info;
  GstGLVideoAllocationParams *params;

  gl_allocator = gst_allocator_find (allocator_name);
  fail_if (gl_allocator == NULL);
  base_mem_alloc = GST_GL_BASE_MEMORY_ALLOCATOR (gl_allocator);

  gst_video_info_set_format (&v_info, GST_VIDEO_FORMAT_RGBA, 1, 1);

  params = gst_gl_video_allocation_params_new (context, NULL, &v_info, 0,
      NULL, GST_GL_TEXTURE_TARGET_2D, GST_VIDEO_GL_TEXTURE_TYPE_RGBA);

  /* texture creation */
  mem = (GstMemory *) gst_gl_base_memory_alloc (base_mem_alloc,
      (GstGLAllocationParams *) params);
  gst_gl_allocation_params_free ((GstGLAllocationParams *) params);
  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD));
  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD));

  /* test wrapping raw data */
  params = gst_gl_video_allocation_params_new_wrapped_data (context, NULL,
      &v_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D,
      GST_VIDEO_GL_TEXTURE_TYPE_RGBA, rgba_pixel, NULL, NULL);
  mem2 =
      (GstMemory *) gst_gl_base_memory_alloc (base_mem_alloc,
      (GstGLAllocationParams *) params);
  gst_gl_allocation_params_free ((GstGLAllocationParams *) params);
  fail_if (mem == NULL);

  fail_unless (GST_MEMORY_FLAG_IS_SET (mem2,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD));
  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD));

  /* wrapped texture creation */
  params = gst_gl_video_allocation_params_new_wrapped_texture (context, NULL,
      &v_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D,
      GST_VIDEO_GL_TEXTURE_TYPE_RGBA, ((GstGLMemory *) mem)->tex_id, NULL,
      NULL);
  mem3 =
      (GstMemory *) gst_gl_base_memory_alloc (base_mem_alloc,
      (GstGLAllocationParams *) params);
  gst_gl_allocation_params_free ((GstGLAllocationParams *) params);
  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem3,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD));
  fail_unless (GST_MEMORY_FLAG_IS_SET (mem3,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD));

  /* check data/flags are correct */
  fail_unless (gst_memory_map (mem2, &map_info, GST_MAP_READ));

  fail_unless (GST_MEMORY_FLAG_IS_SET (mem2,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD));
  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD));

  fail_unless (memcmp (map_info.data, rgba_pixel,
          G_N_ELEMENTS (rgba_pixel)) == 0,
      "0x%02x%02x%02x%02x != 0x%02x%02x%02x%02x", map_info.data[0],
      map_info.data[1], map_info.data[2], map_info.data[3],
      (guint8) rgba_pixel[0], (guint8) rgba_pixel[1], (guint8) rgba_pixel[2],
      (guint8) rgba_pixel[3]);

  gst_memory_unmap (mem2, &map_info);

  fail_unless (GST_MEMORY_FLAG_IS_SET (mem2,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD));
  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD));

  fail_unless (gst_memory_map (mem2, &map_info, GST_MAP_READ | GST_MAP_GL));

  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD));
  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD));

  /* test texture copy */
  fail_unless (gst_gl_memory_copy_into ((GstGLMemory *) mem2,
          ((GstGLMemory *) mem)->tex_id, GST_GL_TEXTURE_TARGET_2D,
          GST_VIDEO_GL_TEXTURE_TYPE_RGBA, 1, 1));
  GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);

  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD));
  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem2,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD));
  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD));
  fail_unless (GST_MEMORY_FLAG_IS_SET (mem,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD));

  gst_memory_unmap (mem2, &map_info);

  /* test download of copied texture */
  fail_unless (gst_memory_map (mem, &map_info, GST_MAP_READ));

  fail_unless (memcmp (map_info.data, rgba_pixel,
          G_N_ELEMENTS (rgba_pixel)) == 0,
      "0x%02x%02x%02x%02x != 0x%02x%02x%02x%02x", (guint8) map_info.data[0],
      (guint8) map_info.data[1], (guint8) map_info.data[2],
      (guint8) map_info.data[3], (guint8) rgba_pixel[0], (guint8) rgba_pixel[1],
      (guint8) rgba_pixel[2], (guint8) rgba_pixel[3]);

  gst_memory_unmap (mem, &map_info);

  /* test download of wrapped copied texture */
  fail_unless (gst_memory_map (mem3, &map_info, GST_MAP_READ));

  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD));
  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD));

  fail_unless (memcmp (map_info.data, rgba_pixel,
          G_N_ELEMENTS (rgba_pixel)) == 0,
      "0x%02x%02x%02x%02x != 0x%02x%02x%02x%02x", (guint8) map_info.data[0],
      (guint8) map_info.data[1], (guint8) map_info.data[2],
      (guint8) map_info.data[3], (guint8) rgba_pixel[0], (guint8) rgba_pixel[1],
      (guint8) rgba_pixel[2], (guint8) rgba_pixel[3]);

  gst_memory_unmap (mem3, &map_info);

  /* test upload flag */
  fail_unless (gst_memory_map (mem3, &map_info, GST_MAP_WRITE));
  gst_memory_unmap (mem3, &map_info);

  fail_unless (GST_MEMORY_FLAG_IS_SET (mem3,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD));
  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem3,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD));

  /* test download flag */
  fail_unless (gst_memory_map (mem3, &map_info, GST_MAP_WRITE | GST_MAP_GL));
  gst_memory_unmap (mem3, &map_info);

  fail_unless (!GST_MEMORY_FLAG_IS_SET (mem3,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_UPLOAD));
  fail_unless (GST_MEMORY_FLAG_IS_SET (mem3,
          GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD));

  gst_memory_unref (mem);
  gst_memory_unref (mem2);
  gst_memory_unref (mem3);
  gst_object_unref (gl_allocator);
}
Exemplo n.º 7
0
static GstBuffer *
gst_egl_allocate_eglimage (APP_STATE_T * ctx,
    GstAllocator * allocator, GstVideoFormat format, gint width, gint height)
{
  GstEGLGLESImageData *data = NULL;
  GstBuffer *buffer;
  GstVideoInfo info;
  gint i;
  gint stride[3];
  gsize offset[3];
  GstMemory *mem[3] = { NULL, NULL, NULL };
  guint n_mem;
  GstMemoryFlags flags = 0;

  memset (stride, 0, sizeof (stride));
  memset (offset, 0, sizeof (offset));

  if (!gst_egl_image_memory_is_mappable ())
    flags |= GST_MEMORY_FLAG_NOT_MAPPABLE;
  /* See https://bugzilla.gnome.org/show_bug.cgi?id=695203 */
  flags |= GST_MEMORY_FLAG_NO_SHARE;

  gst_video_info_set_format (&info, format, width, height);

  GST_DEBUG ("Allocating EGL Image format %s width %d height %d",
      gst_video_format_to_string (format), width, height);
  switch (format) {
    case GST_VIDEO_FORMAT_RGBA:{
      gsize size;
      EGLImageKHR image;

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, ctx->gst_display,
          GST_VIDEO_GL_TEXTURE_TYPE_RGBA, GST_VIDEO_INFO_WIDTH (&info),
          GST_VIDEO_INFO_HEIGHT (&info), &size);

      if (mem[0]) {
        stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 1;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        data = g_slice_new0 (GstEGLGLESImageData);

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 4);
        size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);

        glGenTextures (1, &data->texture);
        if (got_gl_error ("glGenTextures"))
          goto mem_error;

        glBindTexture (GL_TEXTURE_2D, data->texture);
        if (got_gl_error ("glBindTexture"))
          goto mem_error;

        /* Set 2D resizing params */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        /* If these are not set the texture image unit will return
         * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
         * * frames. For a deeper explanation take a look at the OpenGL ES
         * * documentation for glTexParameter */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        if (got_gl_error ("glTexParameteri"))
          goto mem_error;

        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
            GST_VIDEO_INFO_WIDTH (&info),
            GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        if (got_gl_error ("glTexImage2D"))
          goto mem_error;

        image =
            eglCreateImageKHR (gst_egl_display_get (ctx->gst_display),
            ctx->context, EGL_GL_TEXTURE_2D_KHR,
            (EGLClientBuffer) (guintptr) data->texture, NULL);
        if (got_egl_error ("eglCreateImageKHR"))
          goto mem_error;

        mem[0] =
            gst_egl_image_allocator_wrap (allocator, ctx->gst_display,
            image, GST_VIDEO_GL_TEXTURE_TYPE_RGBA, flags, size, data, NULL);

        n_mem = 1;
      }
    }
      break;
    default:
      goto mem_error;
      break;
  }

  buffer = gst_buffer_new ();
  gst_buffer_add_video_meta_full (buffer, 0, format, width, height,
      GST_VIDEO_INFO_N_PLANES (&info), offset, stride);

  /* n_mem could be reused for planar colorspaces, for now its == 1 for RGBA */
  for (i = 0; i < n_mem; i++)
    gst_buffer_append_memory (buffer, mem[i]);

  return buffer;
mem_error:
  {
    GST_ERROR ("Failed to create EGLImage");

    if (data)
      gst_egl_gles_image_data_free (data);

    if (mem[0])
      gst_memory_unref (mem[0]);

    return NULL;
  }

}
Exemplo n.º 8
0
/**
 * gst_bus_post:
 * @bus: a #GstBus to post on
 * @message: (transfer full): the #GstMessage to post
 *
 * Post a message on the given bus. Ownership of the message
 * is taken by the bus.
 *
 * Returns: %TRUE if the message could be posted, %FALSE if the bus is flushing.
 *
 * MT safe.
 */
gboolean
gst_bus_post (GstBus * bus, GstMessage * message)
{
  GstBusSyncReply reply = GST_BUS_PASS;
  GstBusSyncHandler handler;
  gboolean emit_sync_message;
  gpointer handler_data;

  g_return_val_if_fail (GST_IS_BUS (bus), FALSE);
  g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE);

  GST_DEBUG_OBJECT (bus, "[msg %p] posting on bus %" GST_PTR_FORMAT, message,
      message);

  /* check we didn't accidentally add a public flag that maps to same value */
  g_assert (!GST_MINI_OBJECT_FLAG_IS_SET (message,
          GST_MESSAGE_FLAG_ASYNC_DELIVERY));

  GST_OBJECT_LOCK (bus);
  /* check if the bus is flushing */
  if (GST_OBJECT_FLAG_IS_SET (bus, GST_BUS_FLUSHING))
    goto is_flushing;

  handler = bus->priv->sync_handler;
  handler_data = bus->priv->sync_handler_data;
  emit_sync_message = bus->priv->num_sync_message_emitters > 0;
  GST_OBJECT_UNLOCK (bus);

  /* first call the sync handler if it is installed */
  if (handler)
    reply = handler (bus, message, handler_data);

  /* emit sync-message if requested to do so via
     gst_bus_enable_sync_message_emission. terrible but effective */
  if (emit_sync_message && reply != GST_BUS_DROP
      && handler != gst_bus_sync_signal_handler)
    gst_bus_sync_signal_handler (bus, message, NULL);

  /* If this is a bus without async message delivery
   * always drop the message */
  if (!bus->priv->poll)
    reply = GST_BUS_DROP;

  /* now see what we should do with the message */
  switch (reply) {
    case GST_BUS_DROP:
      /* drop the message */
      GST_DEBUG_OBJECT (bus, "[msg %p] dropped", message);
      break;
    case GST_BUS_PASS:
      /* pass the message to the async queue, refcount passed in the queue */
      GST_DEBUG_OBJECT (bus, "[msg %p] pushing on async queue", message);
      gst_atomic_queue_push (bus->priv->queue, message);
      gst_poll_write_control (bus->priv->poll);
      GST_DEBUG_OBJECT (bus, "[msg %p] pushed on async queue", message);

      break;
    case GST_BUS_ASYNC:
    {
      /* async delivery, we need a mutex and a cond to block
       * on */
      GCond *cond = GST_MESSAGE_GET_COND (message);
      GMutex *lock = GST_MESSAGE_GET_LOCK (message);

      g_cond_init (cond);
      g_mutex_init (lock);

      GST_MINI_OBJECT_FLAG_SET (message, GST_MESSAGE_FLAG_ASYNC_DELIVERY);

      GST_DEBUG_OBJECT (bus, "[msg %p] waiting for async delivery", message);

      /* now we lock the message mutex, send the message to the async
       * queue. When the message is handled by the app and destroyed,
       * the cond will be signalled and we can continue */
      g_mutex_lock (lock);

      gst_atomic_queue_push (bus->priv->queue, message);
      gst_poll_write_control (bus->priv->poll);

      /* now block till the message is freed */
      g_cond_wait (cond, lock);

      /* we acquired a new ref from gst_message_dispose() so we can clean up */
      g_mutex_unlock (lock);

      GST_DEBUG_OBJECT (bus, "[msg %p] delivered asynchronously", message);

      GST_MINI_OBJECT_FLAG_UNSET (message, GST_MESSAGE_FLAG_ASYNC_DELIVERY);

      g_mutex_clear (lock);
      g_cond_clear (cond);

      gst_message_unref (message);
      break;
    }
    default:
      g_warning ("invalid return from bus sync handler");
      break;
  }
  return TRUE;

  /* ERRORS */
is_flushing:
  {
    GST_DEBUG_OBJECT (bus, "bus is flushing");
    GST_OBJECT_UNLOCK (bus);
    gst_message_unref (message);

    return FALSE;
  }
}
gboolean
gst_egl_image_memory_setup_buffer (GstGLContext * ctx, GstVideoInfo * info,
    GstBuffer * buffer)
{
  gint i = 0;
  gint stride[3];
  gsize offset[3];
  GstMemory *mem[3] = { NULL, NULL, NULL };
  guint n_mem = 0;
  GstMemoryFlags flags = 0;
  EGLImageKHR image = EGL_NO_IMAGE_KHR;
  EGLClientBuffer client_buffer_tex[3] = { 0, 0, 0 };
  GstVideoGLTextureType texture_types[] = { 0, 0, 0, 0 };
  GstEGLImageAllocator *allocator = gst_egl_image_allocator_obtain ();
  GstGLContextEGL *context = GST_GL_CONTEXT_EGL (ctx);

  g_return_val_if_fail (ctx, FALSE);
  g_return_val_if_fail (info, FALSE);
  g_return_val_if_fail (buffer, FALSE);
  g_return_val_if_fail (gst_gl_context_check_feature (ctx,
          "EGL_KHR_image_base"), FALSE);

  memset (stride, 0, sizeof (stride));
  memset (offset, 0, sizeof (offset));

  flags |= GST_MEMORY_FLAG_NOT_MAPPABLE;
  flags |= GST_MEMORY_FLAG_NO_SHARE;

  switch (GST_VIDEO_INFO_FORMAT (info)) {
    case GST_VIDEO_FORMAT_RGB:
    case GST_VIDEO_FORMAT_BGR:
    case GST_VIDEO_FORMAT_RGB16:
    case GST_VIDEO_FORMAT_RGBA:
    case GST_VIDEO_FORMAT_BGRA:
    case GST_VIDEO_FORMAT_ARGB:
    case GST_VIDEO_FORMAT_ABGR:
    case GST_VIDEO_FORMAT_RGBx:
    case GST_VIDEO_FORMAT_BGRx:
    case GST_VIDEO_FORMAT_xRGB:
    case GST_VIDEO_FORMAT_xBGR:
    case GST_VIDEO_FORMAT_AYUV:
    {
      gsize size = 0;

      switch (GST_VIDEO_INFO_FORMAT (info)) {
        case GST_VIDEO_FORMAT_RGB:
        case GST_VIDEO_FORMAT_BGR:
        case GST_VIDEO_FORMAT_RGB16:
        {
          texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_RGB;
          break;
        }
        case GST_VIDEO_FORMAT_RGBA:
        case GST_VIDEO_FORMAT_BGRA:
        case GST_VIDEO_FORMAT_ARGB:
        case GST_VIDEO_FORMAT_ABGR:
        case GST_VIDEO_FORMAT_RGBx:
        case GST_VIDEO_FORMAT_BGRx:
        case GST_VIDEO_FORMAT_xRGB:
        case GST_VIDEO_FORMAT_xBGR:
        case GST_VIDEO_FORMAT_AYUV:
        {
          texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
          break;
        }
        default:
          g_assert_not_reached ();
          break;
      }
#if 0
      mem[0] =
          gst_egl_image_allocator_alloc (allocator, context,
          texture_types[0], GST_VIDEO_INFO_WIDTH (info),
          GST_VIDEO_INFO_HEIGHT (info), size);
      if (mem[0]) {
        stride[0] = size / GST_VIDEO_INFO_HEIGHT (info);
        n_mem = 1;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
      } else
#endif
      {
        gst_gl_generate_texture_full (GST_GL_CONTEXT (context), info, 0, stride,
            offset, &size, (GLuint *) & client_buffer_tex[0]);

        image = context->eglCreateImage (context->egl_display,
            context->egl_context, EGL_GL_TEXTURE_2D_KHR, client_buffer_tex[0],
            NULL);
        if (eglGetError () != EGL_SUCCESS)
          goto mem_error;

        mem[0] =
            gst_egl_image_allocator_wrap (allocator, context,
            image, texture_types[0], flags, size, client_buffer_tex[0],
            (GstEGLImageDestroyNotify) gst_egl_image_memory_del_gl_texture);
        n_mem = 1;
      }
      break;
    }

    case GST_VIDEO_FORMAT_NV12:
    case GST_VIDEO_FORMAT_NV21:
    {
      gsize size[2];

      texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
      texture_types[1] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA;
#if 0
      mem[0] =
          gst_egl_image_allocator_alloc (allocator, context,
          texture_types[0], GST_VIDEO_INFO_COMP_WIDTH (info,
              0), GST_VIDEO_INFO_COMP_HEIGHT (info, 0), size[0]);
      mem[1] =
          gst_egl_image_allocator_alloc (allocator, context,
          texture_types[1],
          GST_VIDEO_INFO_COMP_WIDTH (info, 1),
          GST_VIDEO_INFO_COMP_HEIGHT (info, 1), size[1]);

      if (mem[0] && mem[1]) {
        stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (info);
        offset[1] = size[0];
        stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (info);
        n_mem = 2;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
        GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        if (mem[0])
          gst_memory_unref (mem[0]);
        if (mem[1])
          gst_memory_unref (mem[1]);
        mem[0] = mem[1] = NULL;
      }
#endif
      {
        for (i = 0; i < 2; i++) {
          gst_gl_generate_texture_full (GST_GL_CONTEXT (context), info, 0,
              stride, offset, size, (GLuint *) & client_buffer_tex[i]);

          image = context->eglCreateImage (context->egl_display,
              context->egl_context, EGL_GL_TEXTURE_2D_KHR, client_buffer_tex[i],
              NULL);
          if (eglGetError () != EGL_SUCCESS)
            goto mem_error;

          mem[i] =
              gst_egl_image_allocator_wrap (allocator, context,
              image, texture_types[i], flags, size[i], client_buffer_tex[i],
              (GstEGLImageDestroyNotify) gst_egl_image_memory_del_gl_texture);
        }

        n_mem = 2;
      }
      break;
    }
    case GST_VIDEO_FORMAT_I420:
    case GST_VIDEO_FORMAT_YV12:
    case GST_VIDEO_FORMAT_Y444:
    case GST_VIDEO_FORMAT_Y42B:
    case GST_VIDEO_FORMAT_Y41B:
    {
      gsize size[3];

      texture_types[0] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
      texture_types[1] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
      texture_types[2] = GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE;
#if 0
      mem[0] =
          gst_egl_image_allocator_alloc (allocator, context,
          texture_types[0], GST_VIDEO_INFO_COMP_WIDTH (info,
              0), GST_VIDEO_INFO_COMP_HEIGHT (info, 0), size[0]);
      mem[1] =
          gst_egl_image_allocator_alloc (allocator, context,
          texture_types[1], GST_VIDEO_INFO_COMP_WIDTH (info,
              1), GST_VIDEO_INFO_COMP_HEIGHT (info, 1), size[1]);
      mem[2] =
          gst_egl_image_allocator_alloc (allocator, context,
          texture_types[2], GST_VIDEO_INFO_COMP_WIDTH (info,
              2), GST_VIDEO_INFO_COMP_HEIGHT (info, 2), size[2]);

      if (mem[0] && mem[1] && mem[2]) {
        stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (info);
        offset[1] = size[0];
        stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (info);
        offset[2] = size[1];
        stride[2] = size[2] / GST_VIDEO_INFO_HEIGHT (info);
        n_mem = 3;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
        GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
        GST_MINI_OBJECT_FLAG_SET (mem[2], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        if (mem[0])
          gst_memory_unref (mem[0]);
        if (mem[1])
          gst_memory_unref (mem[1]);
        if (mem[2])
          gst_memory_unref (mem[2]);
        mem[0] = mem[1] = mem[2] = NULL;
      }
#endif
      {
        for (i = 0; i < 3; i++) {
          gst_gl_generate_texture_full (GST_GL_CONTEXT (context), info, i,
              stride, offset, size, (GLuint *) & client_buffer_tex[i]);

          image = context->eglCreateImage (context->egl_display,
              context->egl_context, EGL_GL_TEXTURE_2D_KHR, client_buffer_tex[i],
              NULL);
          if (eglGetError () != EGL_SUCCESS)
            goto mem_error;

          mem[i] =
              gst_egl_image_allocator_wrap (allocator, context,
              image, texture_types[i], flags, size[i], client_buffer_tex[i],
              (GstEGLImageDestroyNotify) gst_egl_image_memory_del_gl_texture);
        }

        n_mem = 3;
      }
      break;
    }
    default:
      g_assert_not_reached ();
      break;
  }

  gst_buffer_add_video_meta_full (buffer, 0, GST_VIDEO_INFO_FORMAT (info),
      GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info),
      GST_VIDEO_INFO_N_PLANES (info), offset, stride);

  gst_buffer_add_video_gl_texture_upload_meta (buffer,
      gst_egl_image_memory_get_orientation (mem[0]), n_mem, texture_types,
      gst_eglimage_to_gl_texture_upload_meta, NULL, NULL, NULL);

  for (i = 0; i < n_mem; i++)
    gst_buffer_append_memory (buffer, mem[i]);

  return TRUE;

mem_error:
  {
    GST_CAT_ERROR (GST_CAT_DEFAULT, "Failed to create EGLImage");

    for (i = 0; i < 3; i++) {
      if (client_buffer_tex[i])
        gst_gl_context_del_texture (ctx, (GLuint *) & client_buffer_tex[i]);
      if (mem[i])
        gst_memory_unref (mem[i]);
    }

    return FALSE;
  }
}
Exemplo n.º 10
0
static GstFlowReturn
gst_omx_buffer_pool_alloc_buffer (GstBufferPool * bpool,
    GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
{
  GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool);
  GstBuffer *buf;
  GstOMXBuffer *omx_buf;

  g_return_val_if_fail (pool->allocating, GST_FLOW_ERROR);

  omx_buf = g_ptr_array_index (pool->port->buffers, pool->current_buffer_index);
  g_return_val_if_fail (omx_buf != NULL, GST_FLOW_ERROR);

  if (pool->other_pool) {
    guint i, n;

    buf = g_ptr_array_index (pool->buffers, pool->current_buffer_index);
    g_assert (pool->other_pool == buf->pool);
    gst_object_replace ((GstObject **) & buf->pool, NULL);

    n = gst_buffer_n_memory (buf);
    for (i = 0; i < n; i++) {
      GstMemory *mem = gst_buffer_peek_memory (buf, i);

      /* FIXME: We don't allow sharing because we need to know
       * when the memory becomes unused and can only then put
       * it back to the pool. Which is done in the pool's release
       * function
       */
      GST_MINI_OBJECT_FLAG_SET (mem, GST_MEMORY_FLAG_NO_SHARE);
    }

    if (pool->add_videometa) {
      GstVideoMeta *meta;

      meta = gst_buffer_get_video_meta (buf);
      if (!meta) {
        gst_buffer_add_video_meta (buf, GST_VIDEO_FRAME_FLAG_NONE,
            GST_VIDEO_INFO_FORMAT (&pool->video_info),
            GST_VIDEO_INFO_WIDTH (&pool->video_info),
            GST_VIDEO_INFO_HEIGHT (&pool->video_info));
      }
    }

    pool->need_copy = FALSE;
  } else {
    GstMemory *mem;
    const guint nstride = pool->port->port_def.format.video.nStride;
    const guint nslice = pool->port->port_def.format.video.nSliceHeight;
    gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
    gint stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, };

    mem = gst_omx_memory_allocator_alloc (pool->allocator, 0, omx_buf);
    buf = gst_buffer_new ();
    gst_buffer_append_memory (buf, mem);
    g_ptr_array_add (pool->buffers, buf);

    switch (GST_VIDEO_INFO_FORMAT (&pool->video_info)) {
      case GST_VIDEO_FORMAT_ABGR:
      case GST_VIDEO_FORMAT_ARGB:
      case GST_VIDEO_FORMAT_RGB16:
      case GST_VIDEO_FORMAT_BGR16:
      case GST_VIDEO_FORMAT_YUY2:
      case GST_VIDEO_FORMAT_UYVY:
      case GST_VIDEO_FORMAT_YVYU:
      case GST_VIDEO_FORMAT_GRAY8:
        break;
      case GST_VIDEO_FORMAT_I420:
        stride[1] = nstride / 2;
        offset[1] = offset[0] + stride[0] * nslice;
        stride[2] = nstride / 2;
        offset[2] = offset[1] + (stride[1] * nslice / 2);
        break;
      case GST_VIDEO_FORMAT_NV12:
      case GST_VIDEO_FORMAT_NV16:
        stride[1] = nstride;
        offset[1] = offset[0] + stride[0] * nslice;
        break;
      default:
        g_assert_not_reached ();
        break;
    }

    if (pool->add_videometa) {
      pool->need_copy = FALSE;
    } else {
      GstVideoInfo info;
      gboolean need_copy = FALSE;
      gint i;

      gst_video_info_init (&info);
      gst_video_info_set_format (&info,
          GST_VIDEO_INFO_FORMAT (&pool->video_info),
          GST_VIDEO_INFO_WIDTH (&pool->video_info),
          GST_VIDEO_INFO_HEIGHT (&pool->video_info));

      for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&pool->video_info); i++) {
        if (info.stride[i] != stride[i] || info.offset[i] != offset[i]) {
          need_copy = TRUE;
          break;
        }
      }

      pool->need_copy = need_copy;
    }

    if (pool->need_copy || pool->add_videometa) {
      /* We always add the videometa. It's the job of the user
       * to copy the buffer if pool->need_copy is TRUE
       */
      gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
          GST_VIDEO_INFO_FORMAT (&pool->video_info),
          GST_VIDEO_INFO_WIDTH (&pool->video_info),
          GST_VIDEO_INFO_HEIGHT (&pool->video_info),
          GST_VIDEO_INFO_N_PLANES (&pool->video_info), offset, stride);
    }
  }

  gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf),
      gst_omx_buffer_data_quark, omx_buf, NULL);

  *buffer = buf;

  pool->current_buffer_index++;

  return GST_FLOW_OK;
}
GstBuffer *
gst_egl_image_allocator_alloc_eglimage (GstAllocator * allocator,
    GstEGLDisplay * display, EGLContext eglcontext, GstVideoFormat format,
    gint width, gint height)
{
  GstEGLGLESImageData *data = NULL;
  GstBuffer *buffer;
  GstVideoInfo info;
  gint i;
  gint stride[3];
  gsize offset[3];
  GstMemory *mem[3] = { NULL, NULL, NULL };
  guint n_mem;
  GstMemoryFlags flags = 0;

  memset (stride, 0, sizeof (stride));
  memset (offset, 0, sizeof (offset));

  if (!gst_egl_image_memory_is_mappable ())
    flags |= GST_MEMORY_FLAG_NOT_MAPPABLE;
  /* See https://bugzilla.gnome.org/show_bug.cgi?id=695203 */
  flags |= GST_MEMORY_FLAG_NO_SHARE;

  gst_video_info_set_format (&info, format, width, height);

  switch (format) {
    case GST_VIDEO_FORMAT_RGB:
    case GST_VIDEO_FORMAT_BGR:{
      gsize size;
      EGLImageKHR image;

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_RGB, GST_VIDEO_INFO_WIDTH (&info),
          GST_VIDEO_INFO_HEIGHT (&info), &size);
      if (mem[0]) {
        stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 1;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        data = g_slice_new0 (GstEGLGLESImageData);

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 3);
        size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);

        glGenTextures (1, &data->texture);
        if (got_gl_error ("glGenTextures"))
          goto mem_error;

        glBindTexture (GL_TEXTURE_2D, data->texture);
        if (got_gl_error ("glBindTexture"))
          goto mem_error;

        /* Set 2D resizing params */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        /* If these are not set the texture image unit will return
         * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
         * * frames. For a deeper explanation take a look at the OpenGL ES
         * * documentation for glTexParameter */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        if (got_gl_error ("glTexParameteri"))
          goto mem_error;

        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
            GST_VIDEO_INFO_WIDTH (&info),
            GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
        if (got_gl_error ("glTexImage2D"))
          goto mem_error;

        image =
            eglCreateImageKHR (gst_egl_display_get (display),
            eglcontext, EGL_GL_TEXTURE_2D_KHR,
            (EGLClientBuffer) (guintptr) data->texture, NULL);
        if (got_egl_error ("eglCreateImageKHR"))
          goto mem_error;

        mem[0] =
            gst_egl_image_allocator_wrap (allocator, display,
            image, GST_VIDEO_GL_TEXTURE_TYPE_RGB,
            flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);
        n_mem = 1;
      }
      break;
    }
    case GST_VIDEO_FORMAT_RGB16:{
      EGLImageKHR image;
      gsize size;

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_RGB, GST_VIDEO_INFO_WIDTH (&info),
          GST_VIDEO_INFO_HEIGHT (&info), &size);
      if (mem[0]) {
        stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 1;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        data = g_slice_new0 (GstEGLGLESImageData);

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 2);
        size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);

        glGenTextures (1, &data->texture);
        if (got_gl_error ("glGenTextures"))
          goto mem_error;

        glBindTexture (GL_TEXTURE_2D, data->texture);
        if (got_gl_error ("glBindTexture"))
          goto mem_error;

        /* Set 2D resizing params */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        /* If these are not set the texture image unit will return
         * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
         * * frames. For a deeper explanation take a look at the OpenGL ES
         * * documentation for glTexParameter */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        if (got_gl_error ("glTexParameteri"))
          goto mem_error;

        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
            GST_VIDEO_INFO_WIDTH (&info),
            GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
            NULL);
        if (got_gl_error ("glTexImage2D"))
          goto mem_error;

        image =
            eglCreateImageKHR (gst_egl_display_get (display),
            eglcontext, EGL_GL_TEXTURE_2D_KHR,
            (EGLClientBuffer) (guintptr) data->texture, NULL);
        if (got_egl_error ("eglCreateImageKHR"))
          goto mem_error;

        mem[0] =
            gst_egl_image_allocator_wrap (allocator, display,
            image, GST_VIDEO_GL_TEXTURE_TYPE_RGB,
            flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);
        n_mem = 1;
      }
      break;
    }
    case GST_VIDEO_FORMAT_NV12:
    case GST_VIDEO_FORMAT_NV21:{
      EGLImageKHR image;
      gsize size[2];

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
              0), GST_VIDEO_INFO_COMP_HEIGHT (&info, 0), &size[0]);
      mem[1] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA,
          GST_VIDEO_INFO_COMP_WIDTH (&info, 1),
          GST_VIDEO_INFO_COMP_HEIGHT (&info, 1), &size[1]);

      if (mem[0] && mem[1]) {
        stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (&info);
        offset[1] = size[0];
        stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 2;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
        GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        if (mem[0])
          gst_memory_unref (mem[0]);
        if (mem[1])
          gst_memory_unref (mem[1]);
        mem[0] = mem[1] = NULL;

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 0));
        stride[1] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 1) * 2);
        offset[1] = stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 0);
        size[0] = offset[1];
        size[1] = stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 1);

        for (i = 0; i < 2; i++) {
          data = g_slice_new0 (GstEGLGLESImageData);

          glGenTextures (1, &data->texture);
          if (got_gl_error ("glGenTextures"))
            goto mem_error;

          glBindTexture (GL_TEXTURE_2D, data->texture);
          if (got_gl_error ("glBindTexture"))
            goto mem_error;

          /* Set 2D resizing params */
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

          /* If these are not set the texture image unit will return
           * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
           * * frames. For a deeper explanation take a look at the OpenGL ES
           * * documentation for glTexParameter */
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
          if (got_gl_error ("glTexParameteri"))
            goto mem_error;

          if (i == 0)
            glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
                GST_VIDEO_INFO_COMP_WIDTH (&info, i),
                GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE,
                GL_UNSIGNED_BYTE, NULL);
          else
            glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
                GST_VIDEO_INFO_COMP_WIDTH (&info, i),
                GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE_ALPHA,
                GL_UNSIGNED_BYTE, NULL);

          if (got_gl_error ("glTexImage2D"))
            goto mem_error;

          image =
              eglCreateImageKHR (gst_egl_display_get (display),
              eglcontext, EGL_GL_TEXTURE_2D_KHR,
              (EGLClientBuffer) (guintptr) data->texture, NULL);
          if (got_egl_error ("eglCreateImageKHR"))
            goto mem_error;

          mem[i] =
              gst_egl_image_allocator_wrap (allocator, display,
              image,
              (i ==
                  0 ? GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE :
                  GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA),
              flags, size[i], data,
              (GDestroyNotify) gst_egl_gles_image_data_free);
        }

        n_mem = 2;
      }
      break;
    }
    case GST_VIDEO_FORMAT_I420:
    case GST_VIDEO_FORMAT_YV12:
    case GST_VIDEO_FORMAT_Y444:
    case GST_VIDEO_FORMAT_Y42B:
    case GST_VIDEO_FORMAT_Y41B:{
      EGLImageKHR image;
      gsize size[3];

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
              0), GST_VIDEO_INFO_COMP_HEIGHT (&info, 0), &size[0]);
      mem[1] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
              1), GST_VIDEO_INFO_COMP_HEIGHT (&info, 1), &size[1]);
      mem[2] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
              2), GST_VIDEO_INFO_COMP_HEIGHT (&info, 2), &size[2]);

      if (mem[0] && mem[1] && mem[2]) {
        stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (&info);
        offset[1] = size[0];
        stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (&info);
        offset[2] = size[1];
        stride[2] = size[2] / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 3;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
        GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
        GST_MINI_OBJECT_FLAG_SET (mem[2], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        if (mem[0])
          gst_memory_unref (mem[0]);
        if (mem[1])
          gst_memory_unref (mem[1]);
        if (mem[2])
          gst_memory_unref (mem[2]);
        mem[0] = mem[1] = mem[2] = NULL;

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 0));
        stride[1] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 1));
        stride[2] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 2));
        size[0] = stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 0);
        size[1] = stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 1);
        size[2] = stride[2] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 2);
        offset[0] = 0;
        offset[1] = size[0];
        offset[2] = offset[1] + size[1];

        for (i = 0; i < 3; i++) {
          data = g_slice_new0 (GstEGLGLESImageData);

          glGenTextures (1, &data->texture);
          if (got_gl_error ("glGenTextures"))
            goto mem_error;

          glBindTexture (GL_TEXTURE_2D, data->texture);
          if (got_gl_error ("glBindTexture"))
            goto mem_error;

          /* Set 2D resizing params */
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

          /* If these are not set the texture image unit will return
           * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
           * * frames. For a deeper explanation take a look at the OpenGL ES
           * * documentation for glTexParameter */
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
          if (got_gl_error ("glTexParameteri"))
            goto mem_error;

          glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
              GST_VIDEO_INFO_COMP_WIDTH (&info, i),
              GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE,
              GL_UNSIGNED_BYTE, NULL);

          if (got_gl_error ("glTexImage2D"))
            goto mem_error;

          image =
              eglCreateImageKHR (gst_egl_display_get (display),
              eglcontext, EGL_GL_TEXTURE_2D_KHR,
              (EGLClientBuffer) (guintptr) data->texture, NULL);
          if (got_egl_error ("eglCreateImageKHR"))
            goto mem_error;

          mem[i] =
              gst_egl_image_allocator_wrap (allocator, display,
              image, GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE,
              flags, size[i], data,
              (GDestroyNotify) gst_egl_gles_image_data_free);
        }

        n_mem = 3;
      }
      break;
    }
    case GST_VIDEO_FORMAT_RGBA:
    case GST_VIDEO_FORMAT_BGRA:
    case GST_VIDEO_FORMAT_ARGB:
    case GST_VIDEO_FORMAT_ABGR:
    case GST_VIDEO_FORMAT_RGBx:
    case GST_VIDEO_FORMAT_BGRx:
    case GST_VIDEO_FORMAT_xRGB:
    case GST_VIDEO_FORMAT_xBGR:
    case GST_VIDEO_FORMAT_AYUV:{
      gsize size;
      EGLImageKHR image;

      mem[0] =
          gst_egl_image_allocator_alloc (allocator, display,
          GST_VIDEO_GL_TEXTURE_TYPE_RGBA, GST_VIDEO_INFO_WIDTH (&info),
          GST_VIDEO_INFO_HEIGHT (&info), &size);
      if (mem[0]) {
        stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
        n_mem = 1;
        GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
      } else {
        data = g_slice_new0 (GstEGLGLESImageData);

        stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 4);
        size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);

        glGenTextures (1, &data->texture);
        if (got_gl_error ("glGenTextures"))
          goto mem_error;

        glBindTexture (GL_TEXTURE_2D, data->texture);
        if (got_gl_error ("glBindTexture"))
          goto mem_error;

        /* Set 2D resizing params */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        /* If these are not set the texture image unit will return
         * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
         * * frames. For a deeper explanation take a look at the OpenGL ES
         * * documentation for glTexParameter */
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        if (got_gl_error ("glTexParameteri"))
          goto mem_error;

        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
            GST_VIDEO_INFO_WIDTH (&info),
            GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        if (got_gl_error ("glTexImage2D"))
          goto mem_error;

        image =
            eglCreateImageKHR (gst_egl_display_get (display),
            eglcontext, EGL_GL_TEXTURE_2D_KHR,
            (EGLClientBuffer) (guintptr) data->texture, NULL);
        if (got_egl_error ("eglCreateImageKHR"))
          goto mem_error;

        mem[0] =
            gst_egl_image_allocator_wrap (allocator, display,
            image, GST_VIDEO_GL_TEXTURE_TYPE_RGBA,
            flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);

        n_mem = 1;
      }
      break;
    }
    default:
      g_assert_not_reached ();
      break;
  }

  buffer = gst_buffer_new ();
  gst_buffer_add_video_meta_full (buffer, 0, format, width, height,
      GST_VIDEO_INFO_N_PLANES (&info), offset, stride);

  for (i = 0; i < n_mem; i++)
    gst_buffer_append_memory (buffer, mem[i]);

  return buffer;

mem_error:
  {
    GST_ERROR_OBJECT (GST_CAT_DEFAULT, "Failed to create EGLImage");

    if (data)
      gst_egl_gles_image_data_free (data);

    if (mem[0])
      gst_memory_unref (mem[0]);
    if (mem[1])
      gst_memory_unref (mem[1]);
    if (mem[2])
      gst_memory_unref (mem[2]);

    return NULL;
  }
}