目录
本文在VS中使用QT环境,基于FFmpeg核心库,在QT子线程中解码播放本地视频!!
话不多少,直接上代码!!
一、具体实现
QtWidgetsApplication2.cpp
#include "QtWidgetsApplication2.h"
QtWidgetsApplication2::QtWidgetsApplication2(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
mythread* sth = new mythread(); //创建子线程对象
sth->moveToThread(thread); //将子线程对象移动到线程中
connect(sth, &mythread::send_data, this, &QtWidgetsApplication2::read_data); //获取子线程发送的数据显示在label上
connect(thread,&QThread::started,sth,&mythread::run); //线程开始信号链接
connect(ui.pushButton, &QPushButton::clicked, this , [=]() {
ui.label->setScaledContents(true); //label适应视频大小
thread->start(); //线程开始,播放视频
});
}
void QtWidgetsApplication2::closeEvent(QCloseEvent* event) //窗口关闭事件
{
thread->quit(); //退出线程
thread->wait(); //等待线程真正退出 (安全)
}
void mythread::run()
{
avdevice_register_all(); //硬件设备注册
avformat_network_init(); //网络注册
char filename[1024] = "C:\\Users\\suolide-zjq\\Desktop\\mp4\\1.mp4"; //文件路径
int avformat_open_ret = avformat_open_input(&formatcontext, filename, NULL, NULL); //打开文件
int avformat_find_ret = avformat_find_stream_info(formatcontext, NULL); //获取音视频流信息
for (int i = 0; i < formatcontext->nb_streams; i++) { //寻找视频流
if (formatcontext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
streamIndex = i;
break;
}
}
// 将参数从 AVCodecParameters 转换到 AVCodecContext
avcodec_parameters_to_context(codeccontext, formatcontext->streams[streamIndex]->codecpar);
//查找合适的解码器
const AVCodec* codec = avcodec_find_decoder(codeccontext->codec_id);
//打开解码器
int avcodec_open_ret = avcodec_open2(codeccontext, codec, NULL);
//输入视频帧初始化
AVFrame* frame = av_frame_alloc();
//数据包初始化
AVPacket* packet = av_packet_alloc();
//输出RGB帧初始化
AVFrame* frameRGB = av_frame_alloc();
//计算缓冲区大小并分配动态内存
uint8_t* pOutbuffer = (uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB24,
codeccontext->width, codeccontext->height, 1));
//初始化缓冲区
int ret = av_image_fill_arrays(frameRGB->data, frameRGB->linesize, pOutbuffer, AV_PIX_FMT_RGB24,
codeccontext->width, codeccontext->height, 1);
//获取图像转换上下文
SwsContext* sws = sws_getContext(codeccontext->width, codeccontext->height,
codeccontext->pix_fmt,
codeccontext->width, codeccontext->height,
AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
//循环解码
while (av_read_frame(formatcontext, packet) >= 0) {
if (packet->stream_index == streamIndex) {
//用于将一个封装好的媒体包(avpacket)发送给解码器上下文(avcodeccontext)
avcodec_send_packet(codeccontext, packet);
//获取解码后的帧,从0开始,直到解码完成
decode_video_ret = avcodec_receive_frame(codeccontext, frame);
if (decode_video_ret >= 0) {
//视频流数据转换为rgb图像数据
sws_scale(sws, frame->data, frame->linesize, 0, codeccontext->height, frameRGB->data, frameRGB->linesize);
//数据转换为图像
QImage image((uchar*)pOutbuffer, codeccontext->width, codeccontext->height, QImage::Format_RGB888);
//延时
QThread::msleep(30);
//显示图像
send_data(image);
}
}
}
}
void QtWidgetsApplication2::read_data(QImage image)
{
ui.label->setPixmap(QPixmap::fromImage(image)); //将image显示在label上
}
QtWidgetsApplication2::~QtWidgetsApplication2()
{}
QtWidgetsApplication2.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication2.h"
#include <QDebug>
#include <QLabel>
#include <QThread>
#include <QImage>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavdevice/avdevice.h>
#include <libavformat/version.h>
#include <libavutil/time.h>
#include <libavutil/mathematics.h>
#include <libavutil/imgutils.h>
}
class QtWidgetsApplication2 : public QMainWindow
{
Q_OBJECT
public:
QtWidgetsApplication2(QWidget *parent = nullptr);
~QtWidgetsApplication2();
QThread* thread = new QThread(this); //线程
void closeEvent(QCloseEvent* event); //关闭窗口事件
public slots:
void read_data(QImage image);
private:
Ui::QtWidgetsApplication2Class ui;
};
class mythread : public QObject
{
Q_OBJECT
public:
//析构函数,释放内存
~mythread()
{
avcodec_free_context(&codeccontext);
avformat_close_input(&formatcontext);
}
//创建封装格式上下文
AVFormatContext* formatcontext = avformat_alloc_context();
//创建解码器上下文
AVCodecContext* codeccontext = avcodec_alloc_context3(nullptr);
//视频流索引标志位
int streamIndex = -1;
//获取解码后的帧标志位
int decode_video_ret;
signals:
void send_data(QImage image);
public slots:
void run();
private:
QtWidgetsApplication2* parent;
};
main.cpp
#include "QtWidgetsApplication2.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtWidgetsApplication2 w;
w.show();
return a.exec();
}
二、实现效果
ui界面拖入label、pushbutton