Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  qtvlcwidget.cpp   Sprache: C

 

#include "qtvlcwidget.h"
#include <QMouseEvent>
#include <QOpenGLShaderProgram>
#include <QCoreApplication>
#include <QOpenGLFramebufferObject>
#include <QOpenGLFunctions>
#include <QOffscreenSurface>
#include <QThread>
#include <QSemaphore>
#include <QMutex>
#include <cmath>

#include <vlc/vlc.h>

class VLCVideo
{
public:
    VLCVideo(QtVLCWidget *widget)
        :mWidget(widget)
    {
        /* Use default format for context. */
        mContext = new QOpenGLContext(widget);

        /* Use offscreen surface to render the buffers */
        mSurface = new QOffscreenSurface(nullptr, widget);

        /* Widget doesn't have an OpenGL context right now, we'll get it later. */
        QObject::connect(widget, &QtVLCWidget::contextReady, [this](QOpenGLContext *render_context) {
            /* Video view is now ready, we can start */
            mSurface->setFormat(mWidget->format());
            mSurface->create();

            mContext->setFormat(mWidget->format());
            mContext->setShareContext(render_context);
            mContext->create();

            videoReady.release();
        });
    }

    ~VLCVideo()
    {
        cleanup(this);
    }

    /// return whether we are using OpenGLES or OpenGL, which is needed to know
    /// whether we use the libvlc OpenGLES2 engine or the OpenGL one
    bool isOpenGLES()
    {
        return mContext->isOpenGLES();
    }

    /// return the texture to be displayed
    QOpenGLFramebufferObject *getVideoFrame()
    {
        QMutexLocker locker(&m_text_lock);
        if (m_updated) {
            std::swap(m_idx_swap, m_idx_display);
            m_updated = false;
        }
        return mBuffers[m_idx_display].get();
    }

    void onResize(QSize size)
    {
        QMutexLocker lock(&m_cb_lock);
        m_windowSize = size;
        if (!report_size_change)
            return;
        report_size_change(reportOpaque, size.width(), size.height());
    }

    void onMouseMove(QPoint pos)
    {
        QMutexLocker lock(&m_cb_lock);
        if (!report_mouse_move)
            return;
        report_mouse_move(reportOpaque, pos.x(), pos.y());
    }

    void onMousePress(Qt::MouseButton button)
    {
        QMutexLocker lock(&m_cb_lock);
        if (!report_mouse_press)
            return;
        bool ok;
        auto vlcButton = qtToVlcMouseButton(button, &ok);
        if (!ok)
            return;
        report_mouse_press(reportOpaque, vlcButton);
    }

    void onMouseRelease(Qt::MouseButton button)
    {
        QMutexLocker lock(&m_cb_lock);
        if (!report_mouse_release)
            return;
        bool ok;
        auto vlcButton = qtToVlcMouseButton(button, &ok);
        if (!ok)
            return;
        report_mouse_release(reportOpaque, vlcButton);
    }

    static void setReportCallbacks(void* data,
        libvlc_video_output_resize_cb report_size_change,
        libvlc_video_output_mouse_move_cb report_mouse_move,
        libvlc_video_output_mouse_press_cb report_mouse_press,
        libvlc_video_output_mouse_release_cb report_mouse_release,
        void* reportOpaque)
    {
        VLCVideo* that = static_cast<VLCVideo*>(data);
        QMutexLocker lock(&that->m_cb_lock);
        that->reportOpaque = reportOpaque;
        that->report_size_change = report_size_change;
        that->report_mouse_move = report_mouse_move;
        that->report_mouse_press = report_mouse_press;
        that->report_mouse_release = report_mouse_release;

        //report initial window size
        if (report_size_change && that->m_windowSize.isValid())
            report_size_change(that->reportOpaque, that->m_windowSize.width(), that->m_windowSize.height());
    }

    /// this callback will create the surfaces and FBO used by VLC to perform its rendering
    static bool resizeRenderTextures(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);

        for (auto &buffer : that->mBuffers)
            buffer = std::make_unique<QOpenGLFramebufferObject>(cfg->width, cfg->height);

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

        that->mBuffers[that->m_idx_render]->bind();

        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)
    {
        Q_UNUSED(cfg);
        Q_UNUSED(out);

        if (!QOpenGLContext::supportsThreadedOpenGL())
            return false;

        VLCVideo* that = static_cast<VLCVideo*>(*data);

        /* Wait for rendering view to be ready. */
        that->videoReady.acquire();

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

        that->videoReady.release();

        if (that->m_width == 0 && that->m_height == 0)
            return;
        for (auto &buffer : that->mBuffers)
            buffer.reset(nullptr);
    }

    //This callback is called after VLC performs drawing calls
    static void swap(void* data)
    {
        VLCVideo* that = static_cast<VLCVideo*>(data);
        QMutexLocker locker(&that->m_text_lock);
        that->m_updated = true;
        that->mWidget->update();
        std::swap(that->m_idx_swap, that->m_idx_render);
        that->mBuffers[that->m_idx_render]->bind();
    }

    // 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)
            that->mContext->makeCurrent(that->mSurface);
        else
            that->mContext->doneCurrent();
        return true;
    }

    // This callback is called by VLC to get OpenGL functions.
    static void* get_proc_address(void* data, const char* current)
    {
        VLCVideo* that = static_cast<VLCVideo*>(data);
        /* Qt usual expects core symbols to be queryable, even though it's not
         * mentioned in the API. Cf QPlatformOpenGLContext::getProcAddress.
         * Thus, we don't need to wrap the function symbols here, but it might
         * fail to work (not crash though) on exotic platforms since Qt doesn't
         * commit to this behaviour. A way to handle this in a more stable way
         * would be to store the mContext->functions() table in a thread local
         * variable, and wrap every call to OpenGL in a function using this
         * thread local state to call the correct variant. */

        return reinterpret_cast<void*>(that->mContext->getProcAddress(current));
    }

private:
    libvlc_video_output_mouse_button_t qtToVlcMouseButton(Qt::MouseButton button, bool* ok)
    {
        assert(ok != nullptr);
        *ok = true;
        switch (button)
        {
        case Qt::LeftButton:
            return libvlc_video_output_mouse_button_left;
        case Qt::RightButton:
            return libvlc_video_output_mouse_button_right;
        case Qt::MiddleButton:
            return libvlc_video_output_mouse_button_middle;
        default:
            *ok = false;
            return libvlc_video_output_mouse_button_left;
        }
    }

    QtVLCWidget *mWidget;
    QOpenGLContext *mContext;
    QOffscreenSurface *mSurface;
    QSemaphore videoReady;

    //FBO data
    unsigned m_width = 0;
    unsigned m_height = 0;
    QMutex m_text_lock;
    std::unique_ptr<QOpenGLFramebufferObject> mBuffers[3];
    size_t m_idx_render = 0;
    size_t m_idx_swap = 1;
    size_t m_idx_display = 2;
    bool m_updated = false;

    QSize m_windowSize;

    QMutex m_cb_lock;
    void* reportOpaque = nullptr;
    libvlc_video_output_resize_cb report_size_change = nullptr;
    libvlc_video_output_mouse_move_cb report_mouse_move = nullptr;
    libvlc_video_output_mouse_press_cb report_mouse_press = nullptr;
    libvlc_video_output_mouse_release_cb report_mouse_release = nullptr;

};


QtVLCWidget::QtVLCWidget(QWidget *parent)
    : QOpenGLWidget(parent),
      vertexBuffer(QOpenGLBuffer::VertexBuffer),
      vertexIndexBuffer(QOpenGLBuffer::IndexBuffer)
{
    setMouseTracking(true);

    // --transparent causes the clear color to be transparent. Therefore, on systems that
    // support it, the widget will become transparent apart from the logo.

    const char *args[] = {
        "--verbose=2"
    };
    m_vlc = libvlc_new(sizeof(args) / sizeof(*args), args);

    mVLC = std::make_unique<VLCVideo>(this);
}

bool QtVLCWidget::playMedia(const char* url)
{
    m_media = libvlc_media_new_location(url);
    if (m_media == nullptr) {
        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 == nullptr) {
        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,
        mVLC->isOpenGLES() ? libvlc_video_engine_gles2 : libvlc_video_engine_opengl,
        VLCVideo::setup, VLCVideo::cleanup, VLCVideo::setReportCallbacks, VLCVideo::resizeRenderTextures, VLCVideo::swap,
        VLCVideo::make_current, VLCVideo::get_proc_address, nullptr, nullptr,
        mVLC.get());

    // Play the video
    libvlc_media_player_play (m_mp);

    return true;
}

QtVLCWidget::~QtVLCWidget()
{
    cleanup();
}

QSize QtVLCWidget::minimumSizeHint() const
{
    return QSize(50, 50);
}

QSize QtVLCWidget::sizeHint() const
{
    return QSize(400, 400);
}

void QtVLCWidget::cleanup()
{
    stop();

    if (m_vlc)
        libvlc_release(m_vlc);
    m_vlc = nullptr;

    if (m_program == nullptr)
        return;

    makeCurrent();
    vertexBuffer.destroy();
    vertexIndexBuffer.destroy();
    m_program.reset(nullptr);
    doneCurrent();
}

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

static const char *vertexShaderSource =
    "attribute vec2 position;\n"
    "varying vec2 texcoord;\n"
    "void main()\n"
    "{\n"
    "    gl_Position = vec4(position, 0.0, 1.0);\n"
    "    texcoord = position * vec2(0.5) + vec2(0.5);\n"
    "}\n";

static const char *fragmentShaderSource =
    /* Precision is available but no-op on GLSL 130 (see [3], section 4.5.2)
     * and mandatory for OpenGL ES. It was first reserved on GLSL 120 and
     * didn't exist in GLSL <= 110 (= OpenGL 2.0). Since it's a no-op, the
     * easiest solution is to never use it for OpenGL code.
     *
     * [1]: https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.1.10.pdf
     * [2]: https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.1.20.pdf
     * [3]: https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.1.30.pdf
     */

    "#ifdef GL_ES\n"
    "precision highp float;\n"
    "#endif\n"

    "\n"
    "uniform sampler2D texture;\n"
    "\n"
    "varying vec2 texcoord;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    gl_FragColor = texture2D(texture, texcoord);\n"
    "}\n";

/*
 * Data used to seed our vertex array and element array buffers:
 */

static const GLfloat g_vertex_buffer_data[] = {
    -1.0f, -1.0f,
     1.0f, -1.0f,
    -1.0f,  1.0f,
     1.0f,  1.0f
};
static const GLushort g_element_buffer_data[] = { 0, 1, 2, 3 };

void QtVLCWidget::initializeGL()
{
    // In this example the widget's corresponding top-level window can change
    // several times during the widget's lifetime. Whenever this happens, the
    // QOpenGLWidget's associated context is destroyed and a new one is created.
    // Therefore we have to be prepared to clean up the resources on the
    // aboutToBeDestroyed() signal, instead of the destructor. The emission of
    // the signal will be followed by an invocation of initializeGL() where we
    // can recreate all resources.
    connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &QtVLCWidget::cleanup);

    vertexBuffer.create();
    vertexBuffer.bind();
    vertexBuffer.allocate(g_vertex_buffer_data, sizeof(g_vertex_buffer_data));

    vertexIndexBuffer.create();
    vertexIndexBuffer.bind();
    vertexIndexBuffer.allocate(g_element_buffer_data, sizeof(g_element_buffer_data));

    m_program = std::make_unique<QOpenGLShaderProgram>();
    m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
    m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
    m_program->link();

    m_program->setUniformValue("texture", 0);

    m_program->bindAttributeLocation("position", 0);

    emit contextReady(context());
}

void QtVLCWidget::paintGL()
{
    QOpenGLFunctions *GL = context()->functions();
    QOpenGLFramebufferObject *fbo = mVLC->getVideoFrame();
    if (fbo != nullptr && GL != nullptr)
    {
        m_program->bind();

        GL->glClearColor(1.0, 0.5, 0.0, 1.0);

        GL->glActiveTexture(GL_TEXTURE0);
        GL->glBindTexture(GL_TEXTURE_2D, fbo->texture());

        vertexBuffer.bind();
        m_program->setAttributeArray("position", (const QVector2D *)nullptr, sizeof(GLfloat)*2);

        m_program->enableAttributeArray("position");

        vertexIndexBuffer.bind();
        GL->glDrawElements(
            GL_TRIANGLE_STRIP,  /* mode */
            4,                  /* count */
            GL_UNSIGNED_SHORT,  /* type */
            (void*)0            /* element array buffer offset */
        );

        m_program->disableAttributeArray("position");
    }
}

void QtVLCWidget::resizeGL(int w, int h)
{
    mVLC->onResize(QSize(w, h));
}

void QtVLCWidget::mouseMoveEvent(QMouseEvent *event)
{
    QOpenGLWidget::mouseMoveEvent(event);
    mVLC->onMouseMove(event->pos());
}

void QtVLCWidget::mousePressEvent(QMouseEvent *event)
{
    QOpenGLWidget::mousePressEvent(event);
    mVLC->onMousePress(event->button());
}

void QtVLCWidget::mouseReleaseEvent(QMouseEvent *event)
{
    QOpenGLWidget::mouseReleaseEvent(event);
    mVLC->onMouseRelease(event->button());
}

Messung
CHZG
85999693

¤ Dauer der Verarbeitung: 0.2 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=1104856
#Domains=417804