本文主要介绍登录成功后进入主界面,主界面有视频列表,选中某个视频弹出播放界面进行播放
Qt之QListWidget控件的应用
QT+ffmpeg+多线程的视频播放器的基本使用
#include "indexwinget.h"
#include
indexWinget::indexWinget(QWidget *parent) : QWidget(parent)
{
this->resize(1120,800);
//设置窗体标题
this->setWindowTitle(tr("主界面"));
//视频列表窗口
videowins = new QListWidget();//创建列表控件
QVBoxLayout *right_main_layout7 = new QVBoxLayout(this);
videowins->setIconSize(QSize(320,370));
videowins->setViewMode(QListView::IconMode);//设置显示模式为图标模式
videowins->setMovement(QListView::Static);
videowins->setResizeMode(QListView::Adjust);
QString path = QString(QDir::currentPath()+"/image/IQY/bigImg");//图片路径
qDebug()<setText(fi.baseName());//设置列表项的文本
// newitem->setSizeHint(QSize(200,200));
videowins->addItem(newitem);//加载列表项到列表框
}
// 屏蔽水平滑动条
videowins->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//屏蔽垂直滑动条
videowins->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// 设置为像素滚动
videowins->setHorizontalScrollMode(QListWidget::ScrollPerPixel);
// 设置鼠标左键拖动
QScroller::grabGesture(videowins,QScroller::LeftMouseButtonGesture);
// videowins->setStyleSheet(R"(QListWidget {outline: none;border:1px solid white;background-color:black})");
videowins->setStyleSheet("QListWidget{outline: none;border:1px solid black;color:gray;background-color:black}"
"QListWidget::Item{padding-top:20px; padding-bottom:4px; }"
"QListWidget::Item:hover{background:rgb(50,52,57);color:green; }"
"QListWidget::item:selected{background:lightgray; color:redgreen }"
"QListWidget::item:selected:!active{border-width:0px; background:lightgreen; }"
);
videowins->setSpacing(20);//设置item间隔
videowins->show();
right_main_layout7->setContentsMargins(20, 30, 10, 20);
right_main_layout7->addWidget(videowins);
connect(videowins, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(clickedLeftItem(QListWidgetItem *)));//自定义区域添加点击事件的信号槽;连接
}
/*左下角list item点击事件 响应函数*/
void indexWinget::clickedLeftItem(QListWidgetItem * item)
{
qDebug()<<"clickedLeftItem";
qDebug()<text();
QString filename = "movie/"+item->text()+".avi";
qDebug()<hide();
player->show();
}
#include "fdecode.h"
#include
fdecode::fdecode()
{
}
fdecode::fdecode(QString fileName)
{
this->fileName = fileName;
}
void fdecode::openVideoStream(QString fileName)
{
//参数1:封装格式上下文->AVFormatContext->包含了视频信息(视频格式、大小等等...)双指针定义一颗星*,
//参数2:要打开流的路径(文件名)
//AVFormatContext保存视频(视频流)相关信息的结构体
AVFormatContext * formatContent = avformat_alloc_context();
/*2、打开视频文件*/
int res = avformat_open_input(&formatContent,fileName.toStdString().c_str(),nullptr,nullptr);//打开视频文件
if(res!=0)
{
qDebug()<<"打开视频失败";
return ;
}
/*3、打开成功之后相关的结构体信息放在了formatContent里面,接下来获取视频文件信息*/
//3.1先看有没有视频流信息(avformat_find_stream_info),进行判断的原因是有可能打开普通文件
res = avformat_find_stream_info(formatContent,nullptr);
if(res<0)
{
qDebug()<<"打开流媒体信息失败";
return ;
}
//AVFormatContext(含有解码器的id,去streams的流数组里面找视频流)->AVStream->AVCodecContext
//->codec(有解码器的AVCodec)->AVCodec(含有编解码器的id、类型)
//AVCodecContext 保存视频音频编解码相关的信息
int videoType = -1;
//3.2一个视频中有多股码流(用循环),存在AVFormatContext的streams数组中
for(int i=0;inb_streams;i++)
{
if(formatContent->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)//streams->有AVStream结构体,AVStream->codec
{
//找到视频流(只有一个)
videoType = i;//标识视频流这个类型
break;
}
}
if(videoType == -1)
{
qDebug()<<"没有找到视频流相关信息";
return;
}
//对视频的编码只有编码器是不够的还要有宽高格式等
//3.3根据视频流查找编码器对应的上下文对象结构体,存储编码器以及宽高格式等
AVCodecContext *codec = formatContent->streams[videoType]->codec;
/*4、有视频流,则查找对应视频流的解码器*/
AVCodec *decoder = avcodec_find_decoder(codec->codec_id);//需要解码器的id
if(decoder ==nullptr)
{
qDebug()<<"没有找到对应的解码器";
return;
}
/*5、找到解码器后打开解码器*/
//参数:1.初始化的上下文对象 2.打开的解码器 3.类似目录的东西(没有)
res = avcodec_open2(codec,decoder,nullptr);
if(res!=0)
{
qDebug()<<"解码器打开失败";
return;
}
//输出视频信息
//输出:文件格式
qDebug()<iformat->name);
//输出:解码器名称
qDebug()<name);
qDebug()<width).arg(codec->height);
//此函数打印输入或输出的详细信息
av_dump_format(formatContent, 0, fileName.toStdString().c_str(), 0);
/*6、获取到的每一帧码流(视频流)数据写到文件中,进行循环解码*/
AVPacket *pkt=nullptr;//pkt这时没有指向,要我们给他分配内存空间,希望把读出来的数据放到这块内存去
pkt = (AVPacket *)malloc(sizeof(AVPacket));
//码流数据是存到buffer里面,也需要我们动态开空间(AVBufferRef *buf;)
//开空间不知道一帧的码流数据是多少?其实编解码器告诉了宽高,以此可以计算出给码流数据开多大空间
int bufSize = codec->width*codec->height;//计算一帧(图)数据的大小
av_new_packet(pkt,bufSize);
AVFrame *pictureRGB = nullptr;//保存解码及剔除损坏数据后的像素数据(这里只是做准备)
pictureRGB = av_frame_alloc();
pictureRGB->width = codec->width;
pictureRGB->height = codec->height;
pictureRGB->format = codec->pix_fmt;//格式的设置
//要把解码得到的损坏的像素数据剔除,存到pictureRGB中,那这个数据有多大呢?
//获取解码后的一帧像素数据有多大
int numByte = avpicture_get_size(AV_PIX_FMT_RGB32,codec->width,codec->height);
//开的空间用来保存像素数据的大小
uint8_t *buffer = (uint8_t *)av_malloc(numByte*sizeof(uint8_t));
//初始化缓冲区,像素数据填充到AVFrame的pictureRGB里
avpicture_fill((AVPicture *)pictureRGB,buffer,AV_PIX_FMT_RGB32,codec->width,codec->height);
//因为解码之后要伸展,所以先进行转换规则的设置,转换完进入第七步解码
SwsContext *swsContent = nullptr;
swsContent = sws_getContext(codec->width,codec->height,codec->pix_fmt,
codec->width,codec->height,AV_PIX_FMT_RGB32,
SWS_BICUBIC,nullptr,nullptr,nullptr);//SWS_BICUBIC是视频像素数据格式转换算法类型
int count = 0;//保存帧数的变量
while(av_read_frame(formatContent,pkt) >= 0)//成功读到了数据(循环,一帧一帧读)
{
/*6.2AVPacket->AVStream,要判断读到的每一帧的码流数据是不是视频流*/
if(pkt->stream_index == videoType)
{
//是视频流则写到文件中
//fwrite(pkt->data,pkt->size,1,fp);//每次写一个结构体
//读到一帧是视频流就进行解码的动作
/*7、解码——得到RGB保存在AVFrame结构体里*/
int got_picture_ptr = -1;
AVFrame *picture = av_frame_alloc();//保存解码后原始的RGB数据
avcodec_decode_video2(codec,picture,&got_picture_ptr,pkt);
if(got_picture_ptr != 0)
{
//把解码得到的损坏的像素数据剔除,存到pictureRGB中
sws_scale(swsContent,picture->data,picture->linesize,0,picture->height,
pictureRGB->data,pictureRGB->linesize);
count++;
//if(count % 25 == 0)//实现每25帧保存一张图片
// {
// uchar* transData = (unsigned char*)pictureRGB->data[0];//格式装换
QImage desImage = QImage((uchar*)buffer,codec->width,codec->height,
QImage::Format_RGB32,nullptr,nullptr);
// desImage.save(QString("./pictures/rgbPicture%1.png").arg(count-25),"PNG", 100);
//每解码一帧图像给显示窗口发送一个显示图像的信号
emit sendImage(desImage);
msleep(25);//播放倍速设置,可以通过延时来调
}
}
//每次都存在同一块内存空间里,要清空上一次的操作
av_packet_unref(pkt);//不是free
}
qDebug()<<"保存码流数据和像素数据成功";
}
void fdecode::registerFFmpeg()
{
av_register_all();/*1、注册所有组件*/
}
void fdecode::run()
{
this->registerFFmpeg();
this->openVideoStream(this->fileName);
}
#include "playwidget.h"
playWidget::playWidget()
{
}
playWidget::playWidget(QString filename)
{
this->resize(600,388);
//先创建解码线程对象
fdec = new fdecode(filename);
//关联信号和槽
connect(fdec,SIGNAL(sendImage(QImage)),this,SLOT(receiveImage(QImage)));
fdec->start();
}
void playWidget::paintEvent(QPaintEvent *)
{
//绘制用到QPainter对象
QPainter painter(this);
if(!this->img.isNull())
{
painter.drawImage(QRect(0,0,600,368),this->img);
}
}
void playWidget::receiveImage(QImage img)
{
this->img = img;
this->update();
}
代码中针对的是H264格式的视频的播放,所以在进行选择视频时注意视频格式,否则会播放失败
原创不易,转载请注明出处:
Qt实现登录后播放视频(二阶段--2)
实现登录注册参考链接:
Qt使用MVC、数据库单例模式实现登录注册
本文源码链接:
Qt实现登录后播放视频-编解码文档类资源