Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  sdl_opengl_player.cpp   Sprache: C

 

//g++ sdl_opengl_player.cpp $(pkg-config --cflags --libs libvlc sdl2 gl)

/* SPDX-License-Identifier: WTFPL  */
/* Written by Pierre Lamot */

#include <cstdio>
#include <cstdlib>

#include <exception>
#include <mutex>
#include <vector>

#include <SDL2/SDL.h>
#define GL_GLEXT_PROTOTYPES 1
#include <SDL2/SDL_opengl.h>
#include <vlc/vlc.h>

/*
 * This program show how to use libvlc_video_set_output_callbacks API.
 *
 * The main idea is to set up libvlc to render into FBO, and to use a
 * triple buffer mechanism to share textures between VLC and the rendering
 * thread of our application
 */


// Shader sources
const GLchar* vertexSource =
    "attribute vec4 a_position;    \n"
    "attribute vec2 a_uv;          \n"
    "varying vec2 v_TexCoordinate; \n"
    "void main()                   \n"
    "{                             \n"
    "    v_TexCoordinate = a_uv;   \n"
    "    gl_Position = vec4(a_position.xyz, 1.0);  \n"
    "}                             \n";

const GLchar* fragmentSource =
    "uniform sampler2D u_videotex; \n"
    "varying vec2 v_TexCoordinate; \n"
    "void main()                   \n"
    "{                             \n"
    "    gl_FragColor = texture2D(u_videotex, v_TexCoordinate); \n"
    "}                             \n";

class VLCVideo
{
public:
    VLCVideo(SDL_Window *window):
        m_win(window)
    {
        const char *args[] = {
            "--verbose=4"
        };
        m_vlc = libvlc_new(sizeof(args) / sizeof(*args), args);

        //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);
    }

    ~VLCVideo()
    {
        stop();
        if (m_vlc)
            libvlc_release(m_vlc);
    }

    bool playMedia(const char* url)
    {
        m_media = libvlc_media_new_location(url);
        if (m_media == NULL) {
            fprintf(stderr, "unable to create media %s", url);
            return false;
        }
        m_mp = libvlc_media_player_new_from_media (m_vlc, m_media, NULL, NULL);
        if (m_mp == NULL) {
            fprintf(stderr, "unable to create media player");
            libvlc_media_release(m_media);
            return false;
        }
        // Define the opengl rendering callbacks
        libvlc_video_set_output_callbacks(m_mp, libvlc_video_engine_opengl,
            setup, cleanup, nullptr, resize, swap,
            make_current, get_proc_address, nullptr, nullptr,
            this);

        // Play the video
        libvlc_media_player_play (m_mp);

        return true;
    }

    void stop()
    {
        if (m_mp) {
            libvlc_media_player_release(m_mp);
            m_mp = nullptr;
        }
        if (m_media) {
            libvlc_media_release(m_media);
            m_media = nullptr;
        }
    }

    /// return the texture to be displayed
    GLuint getVideoFrame(bool* out_updated)
    {
        std::lock_guard<std::mutex> lock(m_text_lock);
        if (out_updated)
            *out_updated = m_updated;
        if (m_updated) {
            std::swap(m_idx_swap, m_idx_display);
            m_updated = false;
        }
        return m_tex[m_idx_display];
    }

    /// this callback will create the surfaces and FBO used by VLC to perform its rendering
    static bool resize(void* data, const libvlc_video_render_cfg_t *cfg,
                       libvlc_video_output_cfg_t *render_cfg)
    {
        VLCVideo* that = static_cast<VLCVideo*>(data);
        if (cfg->width != that->m_width || cfg->height != that->m_height)
            cleanup(data);

        glGenTextures(3, that->m_tex);
        glGenFramebuffers(3, that->m_fbo);

        for (int i = 0; i < 3; i++) {
            glBindTexture(GL_TEXTURE_2D, that->m_tex[i]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cfg->width, cfg->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

            glBindFramebuffer(GL_FRAMEBUFFER, that->m_fbo[i]);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, that->m_tex[i], 0);
        }
        glBindTexture(GL_TEXTURE_2D, 0);

        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

        if (status != GL_FRAMEBUFFER_COMPLETE) {
            return false;
        }

        that->m_width = cfg->width;
        that->m_height = cfg->height;

        glBindFramebuffer(GL_FRAMEBUFFER, that->m_fbo[that->m_idx_render]);

        render_cfg->u.opengl_format = GL_RGBA;
        render_cfg->full_range = true;
        render_cfg->colorspace = libvlc_video_colorspace_BT709;
        render_cfg->primaries  = libvlc_video_primaries_BT709;
        render_cfg->transfer   = libvlc_video_transfer_func_SRGB;
        render_cfg->orientation = libvlc_video_orient_top_left;

        return true;
    }

    // This callback is called during initialisation.
    static bool setup(void** data, const libvlc_video_setup_device_cfg_t *cfg,
                      libvlc_video_setup_device_info_t *out)
    {
        VLCVideo* that = static_cast<VLCVideo*>(*data);
        that->m_width = 0;
        that->m_height = 0;
        return true;
    }


    // This callback is called to release the texture and FBO created in resize
    static void cleanup(void* data)
    {
        VLCVideo* that = static_cast<VLCVideo*>(data);
        if (that->m_width == 0 && that->m_height == 0)
            return;

        glDeleteTextures(3, that->m_tex);
        glDeleteFramebuffers(3, that->m_fbo);
    }

    //This callback is called after VLC performs drawing calls
    static void swap(void* data)
    {
        VLCVideo* that = static_cast<VLCVideo*>(data);
        std::lock_guard<std::mutex> lock(that->m_text_lock);
        that->m_updated = true;
        std::swap(that->m_idx_swap, that->m_idx_render);
        glBindFramebuffer(GL_FRAMEBUFFER, that->m_fbo[that->m_idx_render]);
    }

    // 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;
    }

    // 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);
    }

private:
    //VLC objects
    libvlc_instance_t*  m_vlc = nullptr;
    libvlc_media_player_t* m_mp = nullptr;
    libvlc_media_t* m_media = nullptr;

    //FBO data
    unsigned m_width = 0;
    unsigned m_height = 0;
    std::mutex m_text_lock;
    GLuint m_tex[3];
    GLuint m_fbo[3];
    size_t m_idx_render = 0;
    size_t m_idx_swap = 1;
    size_t m_idx_display = 2;
    bool m_updated = false;

    //SDL context
    SDL_Window* m_win;
    SDL_GLContext m_ctx;
};

int main(int argc, char** argv)
{
    if (argc != 2) {
        fprintf(stderr, "usage: %s <uri>\n", argv[0]);
        return 1;
    }

    SDL_Window* wnd = SDL_CreateWindow("test",
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
    SDL_GL_SetSwapInterval(0);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

    SDL_GLContext glc = SDL_GL_CreateContext(wnd);

    VLCVideo video(wnd);

    SDL_Renderer* rdr = SDL_CreateRenderer(
        wnd, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);

    // Create Vertex Array Object
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // Create a Vertex Buffer Object and copy the vertex data to it
    GLuint vbo;
    glGenBuffers(1, &vbo);

    //vertex X, vertex Y, UV X, UV Y
    GLfloat vertices[] = {
        -0.5f,  0.5f, 0.f, 1.f,
        -0.5f, -0.5f, 0.f, 0.f,
         0.5f,  0.5f, 1.f, 1.f,
         0.5f, -0.5f, 1.f, 0.f
    };

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // Create and compile the vertex shader
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexSource, NULL);
    glCompileShader(vertexShader);

    // Create and compile the fragment shader
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
    glCompileShader(fragmentShader);

    {
        GLuint shader[] = {vertexShader, fragmentShader};
        const char *shaderName[] = {"vertex", "fragment"};
        for (int i = 0; i < 2; i++) {
            int len;
            glGetShaderiv(shader[i], GL_INFO_LOG_LENGTH, &len);
            if (len <= 1)
                continue;
            std::vector<char> infoLog(len);
            int charsWritten;
            glGetShaderInfoLog(shader[i], len, &charsWritten, infoLog.data());
            fprintf(stderr, "%s shader info log: %s\n", shaderName[i], infoLog.data());

            GLint status = GL_TRUE;
            glGetShaderiv(shader[i], GL_COMPILE_STATUS, &status);
            if (status == GL_FALSE) {
                fprintf(stderr, "compile %s shader failed\n", shaderName[i]);
                SDL_DestroyWindow(wnd);
                SDL_Quit();
                return 1;
            }
        }
    }

    // Link the vertex and fragment shader into a shader program
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    {
        int len;
        glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &len);
        if (len > 1) {
            std::vector<char> infoLog(len);
            int charsWritten;
            glGetProgramInfoLog(shaderProgram, len, &charsWritten, infoLog.data());
            fprintf(stderr, "shader program: %s\n", infoLog.data());
        }

        GLint status = GL_TRUE;
        glGetProgramiv(shaderProgram, GL_LINK_STATUS, &status);
        if (status == GL_FALSE) {
            fprintf(stderr, "unable to use program\n");
            SDL_DestroyWindow(wnd);
            SDL_Quit();
            return 1;
        }
    }

    glUseProgram(shaderProgram);

    // Specify the layout of the vertex data
    GLint posAttrib = glGetAttribLocation(shaderProgram, "a_position");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4*sizeof(float), 0);

    // Specify the layout of the vertex data
    GLint uvAttrib = glGetAttribLocation(shaderProgram, "a_uv");
    glEnableVertexAttribArray(uvAttrib);
    glVertexAttribPointer(uvAttrib, 2, GL_FLOAT, GL_FALSE, 4*sizeof(float), (GLvoid*)(2*sizeof(float)));

    // Specify the texture of the video
    GLint textUniform = glGetUniformLocation(shaderProgram, "u_videotex");
    glActiveTexture(GL_TEXTURE0);
    glUniform1i(textUniform, /*GL_TEXTURE*/0);

    //start playing the video
    if (!video.playMedia(argv[1])) {
        SDL_DestroyWindow(wnd);
        SDL_Quit();
        return 1;
    }

    bool updated = false;
    bool quit = false;
    while(!quit) {
        SDL_Event e;
        while(SDL_PollEvent(&e)) {
            if(e.type == SDL_QUIT)
                quit = true;
        }

        // Clear the screen to black
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Get the current video texture and bind it
        GLuint tex = video.getVideoFrame(&updated);
        glBindTexture(GL_TEXTURE_2D, tex);

        // Draw the video rectangle
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
        glBindTexture(GL_TEXTURE_2D, 0);

        SDL_GL_SwapWindow(wnd);
    };

    video.stop();

    SDL_DestroyWindow(wnd);
    SDL_Quit();

    return 0;
}

Messung
CHZG
839710093

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104848
#Domains=416964