/*
 *  output.c - Video output helpers
 *
 *  Copyright (C) 2012-2013 Intel Corporation
 *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2.1
 *  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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301 USA
 */

#include "gst/vaapi/sysdeps.h"
#include <string.h>
#include <gst/gst.h>
#if USE_DRM
# include <gst/vaapi/gstvaapidisplay_drm.h>
# include <gst/vaapi/gstvaapiwindow_drm.h>
#endif
#if USE_X11
# include <gst/vaapi/gstvaapidisplay_x11.h>
# include <gst/vaapi/gstvaapiwindow_x11.h>
# include <gst/vaapi/gstvaapipixmap_x11.h>
#endif
#if USE_GLX
# include <gst/vaapi/gstvaapidisplay_glx.h>
# include <gst/vaapi/gstvaapiwindow_glx.h>
#endif
#if USE_EGL
# include <gst/vaapi/gstvaapidisplay_egl.h>
# include <gst/vaapi/gstvaapiwindow_egl.h>
#endif
#if USE_WAYLAND
# include <gst/vaapi/gstvaapidisplay_wayland.h>
# include <gst/vaapi/gstvaapiwindow_wayland.h>
#endif
#include "output.h"

static const VideoOutputInfo *g_video_output;
static const VideoOutputInfo g_video_outputs[] = {
    /* Video outputs are sorted in test order for automatic characterisation */
#if USE_WAYLAND
    { "wayland",
      gst_vaapi_display_wayland_new,
      gst_vaapi_window_wayland_new
    },
#endif
#if USE_X11
    { "x11",
      gst_vaapi_display_x11_new,
      gst_vaapi_window_x11_new,
      gst_vaapi_pixmap_x11_new
    },
#endif
#if USE_GLX
    { "glx",
      gst_vaapi_display_glx_new,
      gst_vaapi_window_glx_new,
      gst_vaapi_pixmap_x11_new
    },
#endif
#if USE_DRM
    { "drm",
      gst_vaapi_display_drm_new,
      gst_vaapi_window_drm_new
    },
#endif
    { NULL, }
};

static gchar *g_output_name;
static gboolean g_list_outputs = FALSE;
static gboolean g_fullscreen = FALSE;

static gboolean g_egl_mode = FALSE;
static guint g_gles_version;

static GOptionEntry g_options[] = {
    { "list-outputs", 0,
      0,
      G_OPTION_ARG_NONE, &g_list_outputs,
      "list video outputs", NULL },
    { "output", 'o',
      0,
      G_OPTION_ARG_STRING, &g_output_name,
      "video output name", NULL },
    { "fullscreen", 'f',
      0,
      G_OPTION_ARG_NONE, &g_fullscreen,
      "fullscreen mode", NULL },
    { "egl", 0,
      0,
      G_OPTION_ARG_NONE, &g_egl_mode,
      "enable EGL rendering", NULL },
    { "gles-version", 0,
      0,
      G_OPTION_ARG_INT, &g_gles_version,
      "OpenGL|ES version (in --egl mode)", NULL },
    { NULL, }
};

static void
list_outputs(void)
{
    const VideoOutputInfo *o;

    g_print("Video outputs:");
    for (o = g_video_outputs; o->name != NULL; o++)
        g_print(" %s", o->name);
    g_print("\n");
}

gboolean
video_output_init(int *argc, char *argv[], GOptionEntry *options)
{
    GOptionContext *ctx;
    gboolean success;

#if !GLIB_CHECK_VERSION(2,31,0)
    if (!g_thread_supported())
        g_thread_init(NULL);
#endif

    ctx = g_option_context_new("- test options");
    if (!ctx)
        return FALSE;

    g_option_context_add_group(ctx, gst_init_get_option_group());
    g_option_context_add_main_entries(ctx, g_options, NULL);
    if (options)
        g_option_context_add_main_entries(ctx, options, NULL);
    success = g_option_context_parse(ctx, argc, &argv, NULL);
    g_option_context_free(ctx);

    if (g_list_outputs) {
        list_outputs();
        exit(0);
    }
    return success;
}

void
video_output_exit(void)
{
    g_free(g_output_name);
    gst_deinit();
}

const VideoOutputInfo *
video_output_lookup(const gchar *output_name)
{
    const VideoOutputInfo *o;

    if (!output_name)
        return NULL;

    for (o = g_video_outputs; o->name != NULL; o++) {
        if (g_ascii_strcasecmp(o->name, output_name) == 0)
            return o;
    }
    return NULL;
}

GstVaapiDisplay *
video_output_create_display(const gchar *display_name)
{
    const VideoOutputInfo *o = g_video_output;
    GstVaapiDisplay *egl_display, *display = NULL;

    if (!o) {
        if (g_output_name)
            o = video_output_lookup(g_output_name);
        else {
            for (o = g_video_outputs; o->name != NULL; o++) {
                display = o->create_display(display_name);
                if (display) {
                    if (gst_vaapi_display_get_display(display))
                        break;
                    gst_vaapi_display_unref(display);
                    display = NULL;
                }
            }
        }
        if (!o || !o->name)
            return NULL;
        g_print("Using %s video output\n", o->name);
        g_video_output = o;
    }

    if (!display)
        display = o->create_display(display_name);

    if (g_egl_mode) {
#if USE_EGL
        egl_display = gst_vaapi_display_egl_new (display, g_gles_version);
#else
        egl_display = NULL;
        g_print("error: unsupported EGL renderering mode\n");
#endif
        gst_vaapi_display_unref (display);
        if (!egl_display)
            return NULL;
        display = egl_display;
    }
    return display;
}

GstVaapiWindow *
video_output_create_window(GstVaapiDisplay *display, guint width, guint height)
{
    GstVaapiWindow *window;

    if (!g_video_output)
        return NULL;

#if USE_EGL
    if (g_egl_mode)
        window = gst_vaapi_window_egl_new(display, width, height);
    else
#endif
        window = g_video_output->create_window(display, width, height);
    if (!window)
        return NULL;

    /* Force fullscreen mode, should this be requested by the user */
    if (g_fullscreen)
        gst_vaapi_window_set_fullscreen(window, TRUE);
    return window;
}

GstVaapiPixmap *
video_output_create_pixmap(GstVaapiDisplay *display, GstVideoFormat format,
    guint width, guint height)
{
    if (!g_video_output || !g_video_output->create_pixmap)
        return NULL;
    return g_video_output->create_pixmap(display, format, width, height);
}
