static GstMemory *
gst_egl_image_allocator_wrap (GstEGLImageAllocator * allocator,
    GstGLContextEGL * context, EGLImageKHR image, GstVideoGLTextureType type,
    GstMemoryFlags flags, gsize size, gpointer user_data,
    GstEGLImageDestroyNotify user_data_destroy)
{
  GstEGLImageMemory *mem = NULL;

  g_return_val_if_fail (context != NULL, NULL);
  g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL);

  if (!allocator) {
    allocator = gst_egl_image_allocator_obtain ();
  }

  mem = g_slice_new (GstEGLImageMemory);
  gst_memory_init (GST_MEMORY_CAST (mem), flags,
      GST_ALLOCATOR (allocator), NULL, size, 0, 0, size);

  gst_object_unref (allocator);

  mem->context = gst_object_ref (context);
  mem->image = image;
  mem->type = type;
  mem->orientation = GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL;

  mem->user_data = user_data;
  mem->user_data_destroy = user_data_destroy;

  return GST_MEMORY_CAST (mem);
}
예제 #2
0
GstMemory *
gst_egl_image_allocator_wrap (GstAllocator * allocator,
    GstEGLDisplay * display, EGLImageKHR image, GstEGLImageType type,
    GstMemoryFlags flags, gsize size, gpointer user_data,
    GDestroyNotify user_data_destroy)
{
  GstEGLImageMemory *mem;

  g_return_val_if_fail (display != NULL, NULL);
  g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL);
  g_return_val_if_fail (type != GST_EGL_IMAGE_MEMORY_TYPE_INVALID, NULL);

  if (!allocator) {
    allocator = gst_egl_image_allocator_obtain ();
  }

  mem = g_slice_new (GstEGLImageMemory);
  gst_memory_init (GST_MEMORY_CAST (mem), flags,
      allocator, NULL, size, 0, 0, size);

  mem->display = gst_egl_display_ref (display);
  mem->image = image;
  mem->type = type;

  mem->user_data = user_data;
  mem->user_data_destroy = user_data_destroy;

  return GST_MEMORY_CAST (mem);
}
GstMemory *
gst_egl_image_memory_from_dmabuf (GstGLContext * context,
    gint dmabuf, GstVideoInfo * in_info, gint plane, gsize offset)
{
  GstGLContextEGL *ctx_egl = GST_GL_CONTEXT_EGL (context);
  GstEGLImageAllocator *allocator;
  gint fourcc;
  gint atti = 0;
  EGLint attribs[13];
  EGLImageKHR img = EGL_NO_IMAGE_KHR;

  allocator = gst_egl_image_allocator_obtain ();
  fourcc = _drm_fourcc_from_info (in_info, plane);

  GST_DEBUG ("fourcc %.4s (%d) plane %d (%dx%d)",
      (char *) &fourcc, fourcc, plane,
      GST_VIDEO_INFO_COMP_WIDTH (in_info, plane),
      GST_VIDEO_INFO_COMP_HEIGHT (in_info, plane));

  attribs[atti++] = EGL_WIDTH;
  attribs[atti++] = GST_VIDEO_INFO_COMP_WIDTH (in_info, plane);
  attribs[atti++] = EGL_HEIGHT;
  attribs[atti++] = GST_VIDEO_INFO_COMP_HEIGHT (in_info, plane);

  attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
  attribs[atti++] = fourcc;

  attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
  attribs[atti++] = dmabuf;

  attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
  attribs[atti++] = offset;
  attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
  attribs[atti++] = GST_VIDEO_INFO_PLANE_STRIDE (in_info, plane);

  attribs[atti] = EGL_NONE;

  for (int i = 0; i < atti; i++)
    GST_LOG ("attr %i: %08X", i, attribs[i]);

  g_assert (atti == 12);

  img = ctx_egl->eglCreateImage (ctx_egl->egl_display, EGL_NO_CONTEXT,
      EGL_LINUX_DMA_BUF_EXT, NULL, attribs);

  if (!img) {
    GST_WARNING_OBJECT (allocator, "eglCreateImage failed: %s",
        gst_gl_context_egl_get_error_string ());
    return NULL;
  }

  return gst_egl_image_allocator_wrap (allocator, ctx_egl, img, 0, 0,
      in_info->size, NULL, NULL);
}
예제 #4
0
파일: testegl.c 프로젝트: 01org/gst-omx
static GstPadProbeReturn
query_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
  APP_STATE_T *state = (APP_STATE_T *) user_data;
  GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info);

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_ALLOCATION:{
      GstBufferPool *pool;
      GstStructure *config;
      GstCaps *caps;
      GstVideoInfo info;
      gboolean need_pool;
      guint size;
      GstAllocator *allocator;
      GstAllocationParams params;

      gst_allocation_params_init (&params);

      gst_query_parse_allocation (query, &caps, &need_pool);

      if (!caps) {
        GST_ERROR ("allocation query without caps");
        return GST_PAD_PROBE_OK;
      }

      if (!gst_video_info_from_caps (&info, caps)) {
        GST_ERROR ("allocation query with invalid caps");
        return GST_PAD_PROBE_OK;
      }

      g_mutex_lock (state->queue_lock);
      pool = state->pool ? gst_object_ref (state->pool) : NULL;
      g_mutex_unlock (state->queue_lock);

      if (pool) {
        GstCaps *pcaps;

        /* we had a pool, check caps */

        config = gst_buffer_pool_get_config (pool);
        gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
        GST_DEBUG ("check existing pool caps %" GST_PTR_FORMAT
            " with new caps %" GST_PTR_FORMAT, pcaps, caps);

        if (!gst_caps_is_equal (caps, pcaps)) {
          GST_DEBUG ("pool has different caps");
          /* different caps, we can't use this pool */
          gst_object_unref (pool);
          pool = NULL;
        }
        gst_structure_free (config);
      }

      GST_DEBUG ("pool %p", pool);
      if (pool == NULL && need_pool) {
        GstVideoInfo info;

        if (!gst_video_info_from_caps (&info, caps)) {
          GST_ERROR ("allocation query has invalid caps %"
              GST_PTR_FORMAT, caps);
          return GST_PAD_PROBE_OK;
        }

        GST_DEBUG ("create new pool");
        state->pool = pool =
            gst_egl_image_buffer_pool_new (state, state->display);
        GST_DEBUG ("done create new pool %p", pool);
        /* the normal size of a frame */
        size = info.size;

        config = gst_buffer_pool_get_config (pool);
        /* we need at least 2 buffer because we hold on to the last one */
        gst_buffer_pool_config_set_params (config, caps, size, 2, 0);
        gst_buffer_pool_config_set_allocator (config, NULL, &params);
        if (!gst_buffer_pool_set_config (pool, config)) {
          gst_object_unref (pool);
          GST_ERROR ("failed to set pool configuration");
          return GST_PAD_PROBE_OK;
        }
      }

      if (pool) {
        /* we need at least 2 buffer because we hold on to the last one */
        gst_query_add_allocation_pool (query, pool, size, 2, 0);
        gst_object_unref (pool);
      }

      /* First the default allocator */
      if (!gst_egl_image_memory_is_mappable ()) {
        allocator = gst_allocator_find (NULL);
        gst_query_add_allocation_param (query, allocator, &params);
        gst_object_unref (allocator);
      }

      allocator = gst_egl_image_allocator_obtain ();
      GST_WARNING ("Allocator obtained %p", allocator);

      if (!gst_egl_image_memory_is_mappable ())
        params.flags |= GST_MEMORY_FLAG_NOT_MAPPABLE;
      gst_query_add_allocation_param (query, allocator, &params);
      gst_object_unref (allocator);

      gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
      gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL);
      gst_query_add_allocation_meta (query,
          GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL);

      GST_DEBUG ("done alocation");
      return GST_PAD_PROBE_OK;
    }
      break;
    default:
      break;
  }

  return GST_PAD_PROBE_OK;
}
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;
  }
}
void
gst_egl_image_memory_init (void)
{
  gst_egl_image_allocator_obtain ();
}