qt 利用ffmpeg播放视频
时间: 2023-07-25 16:47:34 浏览: 293
要在Qt中使用FFmpeg播放视频,您需要使用FFmpeg库来解码视频文件并将其渲染到Qt的QVideoFrame对象中。下面是一些基本步骤:
1. 在Qt项目中添加FFmpeg库的头文件和链接库。
2. 创建一个类来处理视频的解码和渲染。您可以使用FFmpeg库中的AVFormatContext和AVCodecContext来打开视频文件并获取视频流的基本信息。
3. 通过调用avcodec_send_packet()和avcodec_receive_frame()函数,将解码后的视频帧存储到一个QVideoFrame对象中。
4. 使用Qt的QMediaPlayer类来渲染QVideoFrame对象,以便在Qt应用程序中显示视频。
下面是一个简单的示例代码片段,它演示了如何使用Qt和FFmpeg来播放视频:
```
#include <QApplication>
#include <QMainWindow>
#include <QMediaPlayer>
#include <QVideoWidget>
#include <QFileDialog>
#include <QMessageBox>
#include <QtAV>
#include <QVideoFrame>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
class VideoPlayer : public QMainWindow
{
Q_OBJECT
public:
VideoPlayer(QWidget *parent = 0);
~VideoPlayer();
private slots:
void openFile();
void play();
void pause();
void stop();
void videoFrameReady(QVideoFrame frame);
private:
QPushButton *m_openButton;
QPushButton *m_playButton;
QPushButton *m_pauseButton;
QPushButton *m_stopButton;
QVideoWidget *m_videoWidget;
QMediaPlayer *m_mediaPlayer;
AVCodecContext *m_codecContext;
AVFormatContext *m_formatContext;
SwsContext *m_swsContext;
};
VideoPlayer::VideoPlayer(QWidget *parent)
: QMainWindow(parent)
{
m_openButton = new QPushButton(tr("Open"), this);
connect(m_openButton, &QPushButton::clicked, this, &VideoPlayer::openFile);
m_playButton = new QPushButton(tr("Play"), this);
connect(m_playButton, &QPushButton::clicked, this, &VideoPlayer::play);
m_pauseButton = new QPushButton(tr("Pause"), this);
connect(m_pauseButton, &QPushButton::clicked, this, &VideoPlayer::pause);
m_stopButton = new QPushButton(tr("Stop"), this);
connect(m_stopButton, &QPushButton::clicked, this, &VideoPlayer::stop);
m_videoWidget = new QVideoWidget(this);
m_mediaPlayer = new QMediaPlayer(this, QMediaPlayer::VideoSurface);
m_mediaPlayer->setVideoOutput(m_videoWidget);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(m_videoWidget);
layout->addWidget(m_openButton);
layout->addWidget(m_playButton);
layout->addWidget(m_pauseButton);
layout->addWidget(m_stopButton);
QWidget *centralWidget = new QWidget(this);
centralWidget->setLayout(layout);
setCentralWidget(centralWidget);
}
VideoPlayer::~VideoPlayer()
{
avcodec_close(m_codecContext);
avformat_close_input(&m_formatContext);
sws_freeContext(m_swsContext);
}
void VideoPlayer::openFile()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", tr("Video Files (*.avi *.mp4 *.mkv)"));
if (fileName.isEmpty())
{
return;
}
m_formatContext = avformat_alloc_context();
if (avformat_open_input(&m_formatContext, fileName.toUtf8().data(), NULL, NULL) != 0)
{
QMessageBox::warning(this, tr("Error"), tr("Could not open file."));
return;
}
if (avformat_find_stream_info(m_formatContext, NULL) < 0)
{
QMessageBox::warning(this, tr("Error"), tr("Could not find stream info."));
return;
}
int videoStreamIndex = -1;
AVCodecParameters *codecParameters = NULL;
for (int i = 0; i < m_formatContext->nb_streams; i++)
{
codecParameters = m_formatContext->streams[i]->codecpar;
if (codecParameters->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStreamIndex = i;
break;
}
}
if (videoStreamIndex == -1)
{
QMessageBox::warning(this, tr("Error"), tr("Could not find video stream."));
return;
}
AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id);
if (codec == NULL)
{
QMessageBox::warning(this, tr("Error"), tr("Could not find codec."));
return;
}
m_codecContext = avcodec_alloc_context3(codec);
if (avcodec_parameters_to_context(m_codecContext, codecParameters) != 0)
{
QMessageBox::warning(this, tr("Error"), tr("Could not copy codec context."));
return;
}
if (avcodec_open2(m_codecContext, codec, NULL) < 0)
{
QMessageBox::warning(this, tr("Error"), tr("Could not open codec."));
return;
}
m_swsContext = sws_getContext(m_codecContext->width, m_codecContext->height, m_codecContext->pix_fmt, m_codecContext->width, m_codecContext->height, AV_PIX_FMT_RGB32, SWS_BILINEAR, NULL, NULL, NULL);
if (m_swsContext == NULL)
{
QMessageBox::warning(this, tr("Error"), tr("Could not create SwsContext."));
return;
}
AVPacket packet;
av_init_packet(&packet);
while (av_read_frame(m_formatContext, &packet) >= 0)
{
if (packet.stream_index == videoStreamIndex)
{
AVFrame *frame = av_frame_alloc();
int response = avcodec_send_packet(m_codecContext, &packet);
if (response < 0)
{
QMessageBox::warning(this, tr("Error"), tr("Could not send packet."));
return;
}
response = avcodec_receive_frame(m_codecContext, frame);
if (response == AVERROR(EAGAIN) || response == AVERROR_EOF)
{
continue;
}
else if (response < 0)
{
QMessageBox::warning(this, tr("Error"), tr("Could not receive frame."));
return;
}
QImage image(m_codecContext->width, m_codecContext->height, QImage::Format_RGBA8888);
uint8_t *dest[4] = { image.bits(), NULL, NULL, NULL };
int destLinesize[4] = { image.bytesPerLine(), 0, 0, 0 };
sws_scale(m_swsContext, frame->data, frame->linesize, 0, frame->height, dest, destLinesize);
QVideoFrame qFrame(image);
videoFrameReady(qFrame);
av_frame_unref(frame);
av_packet_unref(&packet);
}
}
}
void VideoPlayer::play()
{
m_mediaPlayer->play();
}
void VideoPlayer::pause()
{
m_mediaPlayer->pause();
}
void VideoPlayer::stop()
{
m_mediaPlayer->stop();
}
void VideoPlayer::videoFrameReady(QVideoFrame frame)
{
m_mediaPlayer->stop();
m_mediaPlayer->setVideoOutput(m_videoWidget);
m_mediaPlayer->setMedia(QMediaContent(), &frame);
m_mediaPlayer->play();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
VideoPlayer player;
player.show();
return app.exec();
}
```
在这个例子中,我们使用了Qt的QMediaPlayer类来播放视频帧,使用FFmpeg库中的AVFormatContext和AVCodecContext来解码视频文件并使用SwsContext来将解码后的视频帧渲染到QVideoFrame对象中。
阅读全文