QT 使用ffmpeg+QOpenGLWidget进行图像渲染

1、包含必须的头文件。

#include <QMainWindow>
#include <QTimer>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}

2、示例。

// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTimer>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    QTimer* m_timer;
    QOpenGLWidget* m_glWidget;
    AVFormatContext* m_formatCtx;
    AVCodecContext* m_codecCtx;
    AVFrame* m_frame;
    QOpenGLShaderProgram m_shaderProgram;
    QOpenGLBuffer m_vertexBuffer;

    void initializeFFmpeg();
    void initializeOpenGL();
    void updateFrame();

private slots:
    void onTimeout();
};

#endif // MAINWINDOW_H


// mainwindow.cpp
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    m_glWidget = new QOpenGLWidget(this);
    setCentralWidget(m_glWidget);

    m_timer = new QTimer(this);
    connect(m_timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
    m_timer->start(30); // 30ms刷新一次

    initializeFFmpeg();
    initializeOpenGL();
}

MainWindow::~MainWindow()
{
    av_frame_free(&m_frame);
    avcodec_close(m_codecCtx);
    avformat_close_input(&m_formatCtx);
    avformat_free_context(m_formatCtx);
}

void MainWindow::initializeFFmpeg()
{
    m_formatCtx = avformat_alloc_context();
    if (avformat_open_input(&m_formatCtx, "path_to_video_file", nullptr, nullptr) != 0) {
        qDebug() << "Failed to open video file";
        return;
    }

    if (avformat_find_stream_info(m_formatCtx, nullptr) < 0) {
        qDebug() << "Failed to find stream information";
        return;
    }

    int videoStreamIndex = -1;
    for (unsigned int i = 0; i < m_formatCtx->nb_streams; i++) {
        if (m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
            break;
        }
    }

    if (videoStreamIndex == -1) {
        qDebug() << "Failed to find video stream";
        return;
    }

    AVCodecParameters* codecPar = m_formatCtx->streams[videoStreamIndex]->codecpar;
    AVCodec* codec = avcodec_find_decoder(codecPar->codec_id);
    if (!codec) {
        qDebug() << "Failed to find decoder";
        return;
    }

    m_codecCtx = avcodec_alloc_context3(codec);
    if (!m_codecCtx) {
        qDebug() << "Failed to allocate codec context";
        return;
    }

    if (avcodec_parameters_to_context(m_codecCtx, codecPar) < 0) {
        qDebug() << "Failed to copy codec parameters to codec context";
        return;
    }

    if (avcodec_open2(m_codecCtx, codec, nullptr) != 0) {
        qDebug() << "Failed to open codec";
        return;
    }

    m_frame = av_frame_alloc();
    if (!m_frame) {
        qDebug() << "Failed to allocate frame";
        return;
    }
}

void MainWindow::initializeOpenGL()
{
    m_glWidget->makeCurrent();

    QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
    f->glEnable(GL_TEXTURE_2D);

    // 初始化纹理
    GLuint textureId;
    f->glGenTextures(1, &textureId);
    f->glBindTexture(GL_TEXTURE_2D, textureId);
    f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // 加载着色器程序
    m_shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,
                                            "attribute vec4 vertexIn;"
                                            "attribute vec2 textureIn;"
                                            "varying vec2 textureOut;"
                                            "void main(void) {"
                                            "    gl_Position = vertexIn;"
                                            "    textureOut = textureIn;"
                                            "}");
    m_shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,
                                            "uniform sampler2D textureYUV;"
                                            "varying vec2 textureOut";"
                                            "void main(void) {"
                                            " gl_FragColor = texture2D(textureYUV, textureOut);"
                                            "}");
    m_shaderProgram.link();

    // 创建顶点缓冲区
    GLfloat vertices[] = {
        -1.0f,  1.0f,
         1.0f,  1.0f,
        -1.0f, -1.0f,
         1.0f, -1.0f
    };

    m_vertexBuffer.create();
    m_vertexBuffer.bind();
    m_vertexBuffer.allocate(vertices, sizeof(vertices));
    m_vertexBuffer.release();
}

void MainWindow::updateFrame()
{
    AVPacket pkt;
    av_init_packet(&pkt);
    pkt.data = nullptr;
    pkt.size = 0;
    while (av_read_frame(m_formatCtx, &pkt) >= 0) {
    if (pkt.stream_index == m_videoStreamIndex) {
        int ret = avcodec_send_packet(m_codecCtx, &pkt);
        if (ret < 0) {
            qDebug() << "Error sending packet to decoder";
            break;
        }

        while (ret >= 0) {
            ret = avcodec_receive_frame(m_codecCtx, m_frame);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                break;
            else if (ret < 0) {
                qDebug() << "Error during decoding";
                break;
            }

            // 渲染图像到OpenGL窗口
            m_glWidget->makeCurrent();
            QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
            f->glBindTexture(GL_TEXTURE_2D, textureId);
            f->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frame->width, m_frame->height,
                               GL_BGR, GL_UNSIGNED_BYTE, m_frame->data[0]);
            m_glWidget->doneCurrent();

            av_frame_unref(m_frame);
        }
    }

    av_packet_unref(&pkt);
}

void MainWindow::onTimeout()
{
    updateFrame();
    m_glWidget->update();
}

// main.cpp
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

采用OpenGL渲染图像,相比传统的QImage效率着实要高很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值