+++ /dev/null
-/*
- * GStreamer
- * Copyright (C) 2012 Matthew Waters <ystree00@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdio.h>
-
-#include "gl.h"
-#include "gstgldownload.h"
-
-/**
- * SECTION:gstgldownload
- * @short_description: an object that downloads GL textures
- * @see_also: #GstGLUpload, #GstGLMemory
- *
- * #GstGLDownload is an object that downloads GL textures into system memory.
- *
- * A #GstGLDownload can be created with gst_gl_download_new()
- */
-
-#define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
-#define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
-#define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
-#define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
-#define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
-
-static gboolean _do_download (GstGLDownload * download, GstBuffer * inbuf);
-static gboolean _init_download (GstGLDownload * download);
-static gboolean _gst_gl_download_perform_with_data_unlocked (GstGLDownload *
- download, GLuint texture_id, GLuint texture_target,
- gpointer data[GST_VIDEO_MAX_PLANES]);
-static void gst_gl_download_reset (GstGLDownload * download);
-
-/* *INDENT-ON* */
-/* Define the maximum number of planes we can handle - max 2 views per buffer */
-#define GST_GL_DOWNLOAD_MAX_VIEWS 2
-#define GST_GL_DOWNLOAD_MAX_PLANES (GST_VIDEO_MAX_PLANES * GST_GL_DOWNLOAD_MAX_VIEWS)
-
-struct _GstGLDownloadPrivate
-{
- const gchar *YUY2_UYVY;
- const gchar *I420_YV12;
- const gchar *AYUV;
- const gchar *ARGB;
- const gchar *vert_shader;
-
- GstBuffer *inbuf;
- /* Temporary wrapped texture for perform_with_data download */
- GstGLMemory *in_tex;
-
- /* Output data planes */
- gpointer out_data[GST_GL_DOWNLOAD_MAX_PLANES];
-};
-
-GST_DEBUG_CATEGORY_STATIC (gst_gl_download_debug);
-#define GST_CAT_DEFAULT gst_gl_download_debug
-
-#define DEBUG_INIT \
- GST_DEBUG_CATEGORY_INIT (gst_gl_download_debug, "gldownload", 0, "download");
-
-G_DEFINE_TYPE_WITH_CODE (GstGLDownload, gst_gl_download, GST_TYPE_OBJECT,
- DEBUG_INIT);
-static void gst_gl_download_finalize (GObject * object);
-
-#define GST_GL_DOWNLOAD_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
- GST_TYPE_GL_DOWNLOAD, GstGLDownloadPrivate))
-
-static void
-gst_gl_download_class_init (GstGLDownloadClass * klass)
-{
- g_type_class_add_private (klass, sizeof (GstGLDownloadPrivate));
-
- G_OBJECT_CLASS (klass)->finalize = gst_gl_download_finalize;
-}
-
-static void
-gst_gl_download_init (GstGLDownload * download)
-{
-
- download->priv = GST_GL_DOWNLOAD_GET_PRIVATE (download);
-
- gst_video_info_init (&download->info);
-}
-
-/**
- * gst_gl_download_new:
- * @context: a #GstGLContext
- *
- * Returns: a new #GstGLDownload object
- */
-GstGLDownload *
-gst_gl_download_new (GstGLContext * context)
-{
- GstGLDownload *download;
-
- download = g_object_new (GST_TYPE_GL_DOWNLOAD, NULL);
-
- download->context = gst_object_ref (context);
- download->convert = gst_gl_color_convert_new (context);
-
- return download;
-}
-
-static void
-gst_gl_download_finalize (GObject * object)
-{
- GstGLDownload *download;
-
- download = GST_GL_DOWNLOAD (object);
-
- gst_gl_download_reset (download);
-
- if (download->convert) {
- gst_object_unref (download->convert);
- download->convert = NULL;
- }
-
- if (download->context) {
- gst_object_unref (download->context);
- download->context = NULL;
- }
-
- G_OBJECT_CLASS (gst_gl_download_parent_class)->finalize (object);
-}
-
-static void
-gst_gl_download_reset (GstGLDownload * download)
-{
- if (download->priv->in_tex) {
- gst_memory_unref ((GstMemory *) download->priv->in_tex);
- download->priv->in_tex = NULL;
- }
-}
-
-/**
- * gst_gl_download_set_format:
- * @download: a #GstGLDownload
- * @out_info: a #GstVideoInfo
- *
- * Initializes @download with the information required for download.
- */
-void
-gst_gl_download_set_format (GstGLDownload * download, GstVideoInfo * out_info)
-{
- g_return_if_fail (download != NULL);
- g_return_if_fail (GST_VIDEO_INFO_FORMAT (out_info) !=
- GST_VIDEO_FORMAT_UNKNOWN);
- g_return_if_fail (GST_VIDEO_INFO_FORMAT (out_info) !=
- GST_VIDEO_FORMAT_ENCODED);
-
- GST_OBJECT_LOCK (download);
-
- if (gst_video_info_is_equal (&download->info, out_info)) {
- GST_OBJECT_UNLOCK (download);
- return;
- }
-
- gst_gl_download_reset (download);
- download->initted = FALSE;
- download->info = *out_info;
-
- GST_OBJECT_UNLOCK (download);
-}
-
-static GstCaps *
-_set_caps_features (const GstCaps * caps, const gchar * feature_name)
-{
- GstCaps *tmp = gst_caps_copy (caps);
- guint n = gst_caps_get_size (tmp);
- guint i = 0;
-
- for (i = 0; i < n; i++) {
- GstCapsFeatures *features;
-
- features = gst_caps_features_new (feature_name, NULL);
- gst_caps_set_features (tmp, i, features);
- }
-
- return tmp;
-}
-
-GstCaps *
-gst_gl_download_transform_caps (GstGLContext * context,
- GstPadDirection direction, GstCaps * caps, GstCaps * filter)
-{
- GstCaps *gl_templ, *templ, *result, *tmp;
-
- templ =
- gst_caps_from_string (GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS));
- gl_templ =
- gst_caps_from_string (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
- (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, GST_GL_COLOR_CONVERT_FORMATS));
-
- if (direction == GST_PAD_SRC) {
- tmp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST);
- result = _set_caps_features (tmp, GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
- gst_caps_unref (tmp);
- tmp = result;
- } else {
- tmp = gst_caps_ref (caps);
- }
-
- result =
- gst_gl_color_convert_transform_caps (context, direction, tmp, filter);
- gst_caps_unref (tmp);
- tmp = result;
-
- if (direction == GST_PAD_SINK) {
- result = _set_caps_features (tmp, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
- gst_caps_unref (tmp);
- tmp = result;
- result = gst_caps_intersect_full (tmp, templ, GST_CAPS_INTERSECT_FIRST);
- gst_caps_unref (tmp);
- tmp = result;
- }
-
- if (filter) {
- result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
- gst_caps_unref (tmp);
- } else {
- result = tmp;
- }
- gst_caps_unref (templ);
- gst_caps_unref (gl_templ);
-
- return result;
-}
-
-/**
- * gst_gl_download_perform_with_data:
- * @download: a #GstGLDownload
- * @texture_id: the texture id to download
- * @texture_target: the GL texture target
- * @data: (out): where the downloaded data should go
- *
- * Downloads @texture_id into @data. @data size and format is specified by
- * the #GstVideoFormat passed to gst_gl_download_set_format()
- *
- * This method can only be used for download a single view.
- *
- * Returns: whether the download was successful
- */
-gboolean
-gst_gl_download_perform_with_data (GstGLDownload * download,
- GLuint texture_id, GLuint texture_target,
- gpointer data[GST_VIDEO_MAX_PLANES])
-{
- gboolean ret;
-
- g_return_val_if_fail (download != NULL, FALSE);
-
- GST_OBJECT_LOCK (download);
- ret =
- _gst_gl_download_perform_with_data_unlocked (download,
- texture_id, texture_target, data);
- GST_OBJECT_UNLOCK (download);
-
- return ret;
-}
-
-/* This method only supports one input texture */
-static gboolean
-_gst_gl_download_perform_with_data_unlocked (GstGLDownload * download,
- GLuint texture_id, GLuint texture_target,
- gpointer data[GST_VIDEO_MAX_PLANES])
-{
- guint i;
- gboolean res;
- GstBuffer *inbuf;
- guint out_width, out_height;
-
- g_return_val_if_fail (download != NULL, FALSE);
- g_return_val_if_fail (texture_id > 0, FALSE);
- g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&download->info) !=
- GST_VIDEO_FORMAT_UNKNOWN
- && GST_VIDEO_INFO_FORMAT (&download->info) != GST_VIDEO_FORMAT_ENCODED,
- FALSE);
-
- for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&download->info); i++) {
- g_return_val_if_fail (data[i] != NULL, FALSE);
- }
-
- if (!download->priv->in_tex) {
- GstVideoInfo temp_info;
-
- gst_video_info_set_format (&temp_info, GST_VIDEO_FORMAT_RGBA,
- GST_VIDEO_INFO_WIDTH (&download->info),
- GST_VIDEO_INFO_HEIGHT (&download->info));
-
- download->priv->in_tex =
- gst_gl_memory_wrapped_texture (download->context,
- texture_id, texture_target, &temp_info, 0, NULL, NULL, NULL);
- }
-
-
- out_width = GST_VIDEO_INFO_WIDTH (&download->info);
- out_height = GST_VIDEO_INFO_HEIGHT (&download->info);
-
- GST_TRACE ("doing download of texture:%u (%ux%u)",
- download->priv->in_tex->tex_id, out_width, out_height);
-
- download->priv->in_tex->tex_id = texture_id;
-
- inbuf = gst_buffer_new ();
- gst_buffer_append_memory (inbuf,
- gst_memory_ref ((GstMemory *) download->priv->in_tex));
-
- for (i = 0; i < GST_VIDEO_MAX_PLANES; i++)
- download->priv->out_data[i] = data[i];
- /* Clear remaining planes for safety */
- while (i < GST_GL_DOWNLOAD_MAX_PLANES)
- download->priv->out_data[i++] = NULL;
-
- res = _do_download (download, inbuf);
-
- download->priv->inbuf = NULL;
- gst_buffer_unref (inbuf);
-
- return res;
-}
-
-static gboolean
-_init_download (GstGLDownload * download)
-{
- GstVideoFormat v_format;
- GstCaps *in_caps, *out_caps;
- GstCapsFeatures *out_gl_features;
- gboolean res;
-
- v_format = GST_VIDEO_INFO_FORMAT (&download->info);
-
- if (download->initted)
- return TRUE;
-
- GST_TRACE ("initializing texture download for format %s",
- gst_video_format_to_string (v_format));
-
- if (USING_GLES2 (download->context) && !USING_GLES3 (download->context)) {
- /* GL_RGBA is the only officially supported texture format in GLES2 */
- if (v_format == GST_VIDEO_FORMAT_RGB || v_format == GST_VIDEO_FORMAT_BGR) {
- gst_gl_context_set_error (download->context, "Cannot download RGB "
- "textures in GLES2");
- return FALSE;
- }
- }
-
- out_gl_features =
- gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
- out_caps = gst_video_info_to_caps (&download->info);
- gst_caps_set_features (out_caps, 0, out_gl_features);
-
- in_caps = gst_caps_copy (out_caps);
- gst_caps_set_simple (in_caps, "format", G_TYPE_STRING, "RGBA", NULL);
-
- res = gst_gl_color_convert_set_caps (download->convert, in_caps, out_caps);
-
- gst_caps_unref (in_caps);
- gst_caps_unref (out_caps);
-
- return res;
-}
-
-static gboolean
-_do_download (GstGLDownload * download, GstBuffer * inbuf)
-{
- GstBuffer *outbuf;
- GstMapInfo map_info;
- gboolean ret = TRUE;
- gint i;
- GstVideoInfo *info;
- guint views, out_planes;
- gpointer *data = download->priv->out_data;
-
- if (!download->initted) {
- if (!_init_download (download)) {
- GST_DEBUG_OBJECT (download, "Failed to initialise");
- return FALSE;
- }
- }
-
- outbuf = gst_gl_color_convert_perform (download->convert, inbuf);
- if (!outbuf) {
- GST_DEBUG_OBJECT (download, "Failed to colour convert for output");
- return FALSE;
- }
-
- info = &download->info;
- if (GST_VIDEO_INFO_MULTIVIEW_MODE (info) ==
- GST_VIDEO_MULTIVIEW_MODE_SEPARATED)
- views = GST_VIDEO_INFO_VIEWS (info);
- else
- views = 1;
- out_planes = GST_VIDEO_INFO_N_PLANES (info) * views;
-
- for (i = 0; i < out_planes; i++) {
- GstMemory *out_mem = gst_buffer_peek_memory (outbuf, i);
- gpointer temp_data = ((GstGLBaseBuffer *) out_mem)->data;
- ((GstGLBaseBuffer *) out_mem)->data = data[i];
-
- if (!gst_memory_map (out_mem, &map_info, GST_MAP_READ)) {
- GST_ERROR_OBJECT (download, "Failed to map memory");
- ret = FALSE;
- }
- gst_memory_unmap (out_mem, &map_info);
- ((GstGLBaseBuffer *) out_mem)->data = temp_data;
- GST_MINI_OBJECT_FLAG_SET (out_mem, GST_GL_BASE_BUFFER_FLAG_NEED_DOWNLOAD);
- }
-
- gst_buffer_unref (outbuf);
-
- return ret;
-}
-
-static gboolean
-_gst_gl_download_perform_unlocked (GstGLDownload * download,
- GstBuffer * inbuf, GstBuffer * outbuf)
-{
- guint i;
- gboolean res = FALSE;
- guint out_width, out_height;
- GstVideoFrame out_frame;
-
- g_return_val_if_fail (download != NULL, FALSE);
- g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&download->info) !=
- GST_VIDEO_FORMAT_UNKNOWN
- && GST_VIDEO_INFO_FORMAT (&download->info) != GST_VIDEO_FORMAT_ENCODED,
- FALSE);
-
- out_width = GST_VIDEO_INFO_WIDTH (&download->info);
- out_height = GST_VIDEO_INFO_HEIGHT (&download->info);
-
- GST_TRACE_OBJECT (download, "doing download of buffer %" GST_PTR_FORMAT
- " (%ux%u)", inbuf, out_width, out_height);
-
- /* FIXME: Map multiple views */
- if (!gst_video_frame_map (&out_frame, &download->info, outbuf, GST_MAP_WRITE))
- return FALSE;
-
- for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&download->info); i++) {
- if (out_frame.data[i] == NULL)
- goto fail;
- download->priv->out_data[i] = out_frame.data[i];
- }
- while (i < GST_GL_DOWNLOAD_MAX_PLANES)
- download->priv->out_data[i++] = NULL;
-
- res = _do_download (download, inbuf);
-
-fail:
- gst_video_frame_unmap (&out_frame);
- download->priv->inbuf = NULL;
-
- return res;
-}
-
-/**
- * gst_gl_download_perform:
- * @download: a #GstGLDownload
- * @inbuf: (transfer none): a #GstBuffer input buffer
- * @outbuf: (transfer none) (out): a #GstBuffer output buffer
- *
- * Downloads the contents of @inbuf into @outbuf.
- *
- * The output buffer contents must match the #GstVideoFormat passed
- * to gst_gl_download_set_format(), and the input buffer must
- * contain #GstGLMemory memory items.
- *
- * This method supports downloading multiple views.
- *
- * Returns: whether the download was successful
- */
-gboolean
-gst_gl_download_perform (GstGLDownload * download,
- GstBuffer * inbuf, GstBuffer * outbuf)
-{
- gboolean ret;
-
- g_return_val_if_fail (download != NULL, FALSE);
-
- GST_OBJECT_LOCK (download);
- ret = _gst_gl_download_perform_unlocked (download, inbuf, outbuf);
- GST_OBJECT_UNLOCK (download);
-
- return ret;
-}