Experiments with VLC based video player, help needed

hi friends,
latest version of libvlc is implementing a nice feature, it allows the transfer of textures with decoded frame pictures via GL context sharing (instead of pixels array that had to be copied via the cpu in previous versions of the library). This of course leads to a much faster playback. The feature is still only in the development branch of libvlc, but this is not a reason to avoid experimenting with it :slight_smile: My idea is to write a simple addon to implement a video (and audio) player with libvlc, at the moment for Linux but it should not be too difficult to extend it to other platforms too.

At the moment I managed to install the library and successfully compile a simple example they provide (based on SDL2). The skeleton of an OF compatible class is there too, but I need some help with openGL stuff I am not familiar with.

The example code from videolan repository can be found here. The parts that I couldn’t yet port to openFrameworks are these:

In initialization (class constructor)

//VLC opengl context needs to be shared with SDL context
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
m_ctx = SDL_GL_CreateContext(window);

I found some hints about sharing GL context among different OF windows but this is a different case, it looks like the app should share context with whatever is the current one at any given time.

Then a couple of callbacks

    // This callback is called to set the OpenGL context
    static bool make_current(void* data, bool current)
    {
        VLCVideo* that = static_cast<VLCVideo*>(data);
        if (current)
            return SDL_GL_MakeCurrent(that->m_win, that->m_ctx) == 0;
        else
            return SDL_GL_MakeCurrent(that->m_win, 0) == 0;
    }

What would be the OF equivalent for the “MakeCurrent” calls? There is a “glXMakeCurrent” that looks like a good candidate, but it is not clear to me what its parameters should be in an OF app.

    // This callback is called by VLC to get OpenGL functions.
    static void* get_proc_address(void* /*data*/, const char* current)
    {
        return SDL_GL_GetProcAddress(current);
    }

As a replacement for the SDL_GL_getProcAddress call I put glXGetProcAddress((const GLubyte*)current) adding a #include <GL/glx.h> at the top, but I couldn’t test if it works.

So at the moment I could really use some help! That would be a good opportunity for me to learn something new and besides that a fast vlc based player may be useful to others as well.

thanks for helping
Davide

Hi David,

It’s a bit late but I was asking myself the same questions when I came to your post looking for answers, and as I finally found them I figured it might help others too.

First, on desktop OpenFrameworks uses GLFW so you can switch to its functions for context management : namely glfwMakeContextCurrent and glfwGetProcAddress.

oFx windows have a makeCurrent() method but no makeUnCurrent(), so to switch context you
can simply do the following in your callback function :

bool onMakeCurrent(bool enter) {
  GLFWwindow *new_ctx = enter ? shared_ctx_->getWindowContext() : nullptr;
  glfwMakeContextCurrent(new_ctx);
  return glfwGetCurrentContext() == new_ctx;
}

LibVLC needs a shared context for its thread but OpenFrameworks call makeCurrent() on every windows created using ofCreateWindow(), so you have to create your shared context free of the OpenFrameworks subsystem then create your rendering window with your shared context :

int main(){
  // GLFW settings (desktop mode).
  ofGLFWWindowSettings settings;

#if 1
  settings.setGLVersion(2, 0);  // will work.
#else
  settings.setGLVersion(3, 3);  // will work only on an OpenGL Compatibility Profile.
#endif

  // Anarcho-windowless shared context creation.
  std::shared_ptr<ofAppGLFWWindow> shared_ctx;
  {
    ofGLFWWindowSettings ctx_settings(settings);
    settings.title                = "";
    settings.numSamples           = 0;
    ctx_settings.doubleBuffering  = false;
    ctx_settings.visible          = false;
    ctx_settings.setSize(1, 1);

    shared_ctx = std::make_shared<ofAppGLFWWindow>();
    shared_ctx->setup(ctx_settings);
    shared_ctx->setVerticalSync(false);
  }

  // Rendering context, used by the main thread.
  std::shared_ptr<ofAppGLFWWindow> render_ctx;
  {
    settings.shareContextWith = shared_ctx;
    settings.title            = "VLC Video Viewer";
    settings.numSamples       = 4;
    settings.doubleBuffering  = true;
    settings.visible          = true;
    settings.setSize(960, 540);

    render_ctx = ofCreateWindow(settings);
    
    // We force v-sync on the rendering context to prevent potential race condition
    // when accessing libVLC's thread when decoding high-latency streams.
    render_ctx->setVerticalSync(true);
  }

  // Create the app with reference to the shared context to give to libVLC.
  std::shared_ptr<ofApp> app(new ofApp(shared_ctx));
  ofRunApp(render_ctx, app);
  ofRunMainLoop();
}

Lastly, if you request an OpenGL of version 3.2 or more it will likely crash due to libVLC expecting a Compatibility Profile for its context when Ofx set them to Core Profile.

You can refer to this Github issue for more details :slight_smile:

Cheers.

2 Likes

Im curious, why you want to use a vlc based player? I mean is there any advantage over gstreamer?

I would love to try out a ofVideoPlayer with a VLC backend.
VLC seems to perform quite well and plays a lot of video formats.
GStreamer is great too, but there are some hassles in macOS sometimes.

Ah sure, i was thinking in linux… i will also like to test to compare :slight_smile:

Hey @pandereto,

I’m not that familiar with gstreamer so I could not compare them as is, but as @dimitre suggested it rarely failed to play exotic formats with good performance for me, while oF’s videoPlayerExample can’t even run its video natively, so I wanted to test its hardware frame capture for high-latency streaming files.

Plus, I do not know for gstreamer, but it recognizes weird url redirection that return to a m3u playlist (like my beloved web radios playlist) without much added code.

I’m in the process of cleaning things a bit to hopefully get a proper ofVideoPlayer backend of it.
We’ll see :slight_smile:

2 Likes

Nice, is always good to have options to choose from, will test it also

1 Like