Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rendering OpenGL with the Enlightenment Foundation Library #48

Open
MaxPerl opened this issue Dec 31, 2021 · 0 comments
Open

Rendering OpenGL with the Enlightenment Foundation Library #48

MaxPerl opened this issue Dec 31, 2021 · 0 comments

Comments

@MaxPerl
Copy link

MaxPerl commented Dec 31, 2021

Hello MPV experts,

I tried to adapt the SDL example to Efl/Elementary and to render the mpv context to a Glview widget.
Unfortunately MPV doesn't render to the Glview widget. Sometimes there is no video window, sometimes a seperate video window is shown. I really don't know, how to get ahead, and would be very thankful for every tip.

Thanks in advance and a happy New Year 2022,
Max

Here is my current code: (you can find it here):

// Build with: gcc -o mpv mpv.c `pkg-config --cflags --libs mpv elementary`

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#include <Elementary.h>

#include <mpv/client.h>
#include <mpv/render_gl.h>

static int count = 0;
static int render_event;

typedef struct _cb_data cbd;

struct _cb_data
{
   Evas_Object *glview;
   mpv_handle   *mpv;
   mpv_render_context *mpv_gl;
   GLuint fbo;
};

static cbd *cb_data = NULL;

static void die(const char *msg)
{
    fprintf(stderr, "%s\n", msg);
    exit(1);
}

static void *get_proc_address(void *fn_ctx, const char *name)
{
    Evas_Object *glview = fn_ctx;
    Evas_GL *gl = elm_glview_evas_gl_get(glview);
    void *addr = evas_gl_proc_address_get(gl,name);
    return addr;
}

void _render_update(void *ctx) {
    printf("CALL RENDER %d\n",count);
    count = 1;
    
}

Eina_Bool render_event_cb(void *data, int type, void *ev) {
    elm_glview_changed_set(cb_data->glview);
    return 1;
}

void _on_render(Evas_Object *obj)
{
    mpv_render_context *mpv_gl = cb_data->mpv_gl;
    Evas_Object *gl = cb_data->glview;
        
        int w, h;
    
        elm_glview_size_get(gl, &w, &h);
        printf("RENDER %d %d\n",w,h);
        
        mpv_render_param params[] = {
            // Specify the default framebuffer (0) as target. This will
            // render onto the entire screen. If you want to show the video
            // in a smaller rectangle or apply fancy transformations, you'll
            // need to render into a separate FBO and draw it manually.
            {MPV_RENDER_PARAM_OPENGL_FBO, &(mpv_opengl_fbo){
                    .fbo = 0,
                    .w = w,
                    .h = h,
            }},
            // Flip rendering (needed due to flipped GL coordinate system).
            {MPV_RENDER_PARAM_FLIP_Y, &(int){1}},
            {0}
        };
        // See render_gl.h on what OpenGL environment mpv expects, and
        // other API details.
        mpv_render_context_render(mpv_gl, params);
        
}

static Eina_Bool
on_mpv(void *data)
{
    mpv_handle *mpv = data;
    while (1) {
                    //printf("COUNT %d",count);
                    if (count) {
                        count = 0;
                        ecore_event_add(render_event,NULL, NULL,NULL);
                    }
                    mpv_event *mp_event = mpv_wait_event(mpv, 0);
                    if (mp_event->event_id == MPV_EVENT_NONE)
                        break;
                    if (mp_event->event_id == MPV_EVENT_LOG_MESSAGE) {
                        mpv_event_log_message *msg = mp_event->data;
                        // Print log messages about DR allocations, just to
                        // test whether it works. If there is more than 1 of
                        // these, it works. (The log message can actually change
                        // any time, so it's possible this logging stops working
                        // in the future.)
                        if (strstr(msg->text, "DR image"))
                            printf("log: %s", msg->text);
                        continue;
                    }
//                     ´
                }
   // Let the event continue to other callbacks which have not been called yet
   return ECORE_CALLBACK_PASS_ON;
}

void _init_gl(Evas_Object *glview) {
    
    mpv_render_param params[] = {
        {MPV_RENDER_PARAM_API_TYPE, MPV_RENDER_API_TYPE_OPENGL},
        {MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &(mpv_opengl_init_params){
            .get_proc_address = get_proc_address, glview,
        }},
        // Tell libmpv that you will call mpv_render_context_update() on render
        // context update callbacks, and that you will _not_ block on the core
        // ever (see <libmpv/render.h> "Threading" section for what libmpv
        // functions you can call at all when this is active).
        // In particular, this means you must call e.g. mpv_command_async()
        // instead of mpv_command().
        // If you want to use synchronous calls, either make them on a separate
        // thread, or remove the option below (this will disable features like
        // DR and is not recommended anyway).
        //{MPV_RENDER_PARAM_ADVANCED_CONTROL, &(int){1}},
        {0}
    };

    // This makes mpv use the currently set GL context. It will use the callback
    // (passed via params) to resolve GL builtin functions, as well as extensions.
    
    mpv_render_context *mpv_gl;
    if (mpv_render_context_create(&mpv_gl, cb_data->mpv, params) < 0)
        die("failed to initialize mpv GL context");
    
    cb_data->mpv_gl = mpv_gl;
    
    // When normal mpv events are available.
    //mpv_set_wakeup_callback(mpv, on_mpv_events, NULL);

    // When there is a need to call mpv_render_context_update(), which can
    // request a new frame to be rendered.
    // (Separate from the normal event handling mechanism for the sake of
    //  users which run OpenGL on a different thread.)
    render_event = ecore_event_type_new();
    ecore_event_handler_add(render_event,render_event_cb,NULL);
    mpv_render_context_set_update_callback(mpv_gl, _render_update, NULL);
    
}


int main(int argc, char *argv[])
{
    Evas_Object *win, *bx, *gl;
    if (!(cb_data = calloc(1, sizeof(cbd)))) return 1;

    
    //elm_config_engine_set("opengl_x11");
    //elm_config_accel_preference_set("opengl");
    
    elm_init(argc,argv);
    elm_config_accel_preference_set("opengl_x11");
    
    elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);

    win = elm_win_util_standard_add("glview simple", "GLView Simple");
    elm_win_autodel_set(win, EINA_TRUE);
   
    bx = elm_box_add(win);
    evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    elm_win_resize_object_add(win, bx);
    evas_object_show(bx);

    gl = elm_glview_add(win);
    evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
    evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    elm_glview_mode_set(gl, ELM_GLVIEW_ALPHA | ELM_GLVIEW_DEPTH);
    elm_glview_resize_policy_set(gl, ELM_GLVIEW_RESIZE_POLICY_RECREATE);
    elm_glview_render_policy_set(gl, ELM_GLVIEW_RENDER_POLICY_ALWAYS);
    elm_glview_init_func_set(gl, _init_gl);
    elm_glview_render_func_set(gl, _on_render);
    
    elm_box_pack_end(bx, gl);
    evas_object_show(gl);

    elm_object_focus_set(gl, EINA_TRUE);
    
    evas_object_resize(win, 320, 480);
    evas_object_show(win);
    
    
    mpv_handle *mpv = mpv_create();
    if (!mpv)
        die("context init failed");
    
    ecore_idler_add(on_mpv,mpv);
    
    // Some minor options can only be set before mpv_initialize().
    if (mpv_initialize(mpv) < 0)
        die("mpv init failed");
    
    mpv_request_log_messages(mpv, "debug");
    
    cb_data->glview = gl;
    cb_data->mpv = mpv;
    
    // Play this file.
     const char *cmd[] = {"loadfile", "./video.ogv", NULL};
     mpv_command_async(mpv,0, cmd);
    
    // run the mainloop and process events and callbacks
    elm_run();
            
    // Destroy the GL renderer and all of the GL objects it allocated. If video
    // is still running, the video track will be deselected.
    mpv_render_context_free(cb_data->mpv_gl);

    mpv_terminate_destroy(mpv);
    elm_shutdown();

    printf("properly terminated\n");
    return 0;
}
`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant