QT+FFMPEG实现视频播放包括头文件以及源文件
时间: 2023-08-13 18:03:11 浏览: 252
以下是一个简单的基于QT和FFmpeg实现视频播放的示例程序:
头文件:
```c++
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer>
#include <QImage>
#include <QPixmap>
#include <QThread>
#include <QDebug>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
namespace Ui {
class MainWindow;
}
class VideoThread : public QThread
{
Q_OBJECT
public:
explicit VideoThread(QObject *parent = nullptr);
~VideoThread();
void run();
void setFileName(QString fileName);
void stop();
signals:
void sendImage(QImage image);
private:
QString m_fileName;
bool m_stopFlag;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_actionOpen_triggered();
void updateImage(QImage image);
private:
Ui::MainWindow *ui;
VideoThread *m_videoThread;
};
#endif // MAINWINDOW_H
```
源文件:
```c++
#include "mainwindow.h"
#include "ui_mainwindow.h"
VideoThread::VideoThread(QObject *parent) :
QThread(parent),
m_stopFlag(false)
{
}
VideoThread::~VideoThread()
{
stop();
wait();
}
void VideoThread::setFileName(QString fileName)
{
m_fileName = fileName;
}
void VideoThread::stop()
{
m_stopFlag = true;
}
void VideoThread::run()
{
AVFormatContext *pFormatCtx = nullptr;
AVCodecContext *pCodecCtxOrig = nullptr;
AVCodecContext *pCodecCtx = nullptr;
AVCodec *pCodec = nullptr;
AVFrame *pFrame = nullptr;
AVPacket packet;
int frameFinished;
int videoStream;
struct SwsContext *sws_ctx = nullptr;
av_register_all();
if(avformat_open_input(&pFormatCtx, m_fileName.toStdString().c_str(), nullptr, nullptr)!=0)
{
qDebug() << "avformat_open_input failed.";
return;
}
if(avformat_find_stream_info(pFormatCtx, nullptr)<0)
{
qDebug() << "avformat_find_stream_info failed.";
return;
}
av_dump_format(pFormatCtx, 0, m_fileName.toStdString().c_str(), 0);
videoStream=-1;
for(unsigned int i=0; i<pFormatCtx->nb_streams; i++)
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoStream=i;
break;
}
if(videoStream==-1)
{
qDebug() << "videoStream not found.";
return;
}
pCodecCtxOrig=pFormatCtx->streams[videoStream]->codec;
pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
if(pCodec==nullptr)
{
qDebug() << "Unsupported codec.";
return;
}
pCodecCtx = avcodec_alloc_context3(pCodec);
if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0)
{
qDebug() << "Couldn't copy codec context.";
return;
}
if(avcodec_open2(pCodecCtx, pCodec, nullptr)<0)
{
qDebug() << "Could not open codec.";
return;
}
pFrame=av_frame_alloc();
QImage image;
int dstWidth = pCodecCtx->width;
int dstHeight = pCodecCtx->height;
sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
dstWidth, dstHeight, AV_PIX_FMT_RGB32,
SWS_BILINEAR, nullptr, nullptr, nullptr);
while(av_read_frame(pFormatCtx, &packet)>=0 && !m_stopFlag)
{
if(packet.stream_index==videoStream)
{
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if(frameFinished)
{
QImage image(dstWidth, dstHeight, QImage::Format_RGB32);
uint8_t *dst_data[4] = {image.bits(), nullptr, nullptr, nullptr};
int dst_linesize[4] = {image.bytesPerLine(), 0, 0, 0};
sws_scale(sws_ctx, (const uint8_t * const*)pFrame->data, pFrame->linesize,
0, pCodecCtx->height, dst_data, dst_linesize);
emit sendImage(image);
}
}
av_packet_unref(&packet);
}
av_free(pFrame);
avcodec_close(pCodecCtx);
avcodec_free_context(&pCodecCtx);
avformat_close_input(&pFormatCtx);
sws_freeContext(sws_ctx);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
m_videoThread(nullptr)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionOpen_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open Video"), ".", tr("Video Files (*.mp4)"));
if (fileName.isEmpty())
{
return;
}
if(m_videoThread == nullptr)
{
m_videoThread = new VideoThread(this);
connect(m_videoThread, SIGNAL(sendImage(QImage)), this, SLOT(updateImage(QImage)));
}
m_videoThread->setFileName(fileName);
m_videoThread->start();
}
void MainWindow::updateImage(QImage image)
{
ui->label->setPixmap(QPixmap::fromImage(image));
}
```
在.pro文件中添加如下代码:
```c++
LIBS += -lavcodec
LIBS += -lavformat
LIBS += -lavutil
LIBS += -lswscale
```
这是一个简化版的视频播放程序,可以在QT中选择一个视频文件进行播放。该程序使用了QT的UI设计,以及FFmpeg的解码和图片格式转换功能。其中,VideoThread类继承自QThread,用于在后台解码视频文件并发送QImage给主线程进行显示。在主线程中,我们使用QTimer来调用updateImage()函数更新UI界面,接收VideoThread发送的QImage并将其显示在QLabel中。
阅读全文