Qt实现登录后播放视频(二阶段--2)

23 篇文章 1 订阅

引言

本文主要介绍登录成功后进入主界面,主界面有视频列表,选中某个视频弹出播放界面进行播放

一、简述QListWidget和视频解码播放

1、QListWidget

Qt之QListWidget控件的应用

2、视频解码播放参考以下链接

QT+ffmpeg+多线程的视频播放器的基本使用

二、核心代码

1、主界面(含QListWidget)

#include "indexwinget.h"
#include <QDebug>
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()<<path;
    QDir dir(path);
    QStringList moviefilenames;
    moviefilenames << "*.png";
    qDebug()<<moviefilenames;

    QStringList files = dir.entryList(moviefilenames,QDir::Files|QDir::Readable,QDir::Name);
    qDebug()<<files;
    for (int i = 0; i < files.size(); ++i)
    {
        newitem = new QListWidgetItem(QIcon(QPixmap(path+"/"+files.at(i))),files.at(i));
        QFileInfo fi = files.at(i);
        newitem->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()<<item->text();
    QString filename = "movie/"+item->text()+".avi";
    qDebug()<<filename;
    player = new playWidget(filename);
//    this->hide();
    player->show();
}

2、视频解码类(继承线程类)

#include "fdecode.h"
#include <QDebug>
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;i<formatContent->nb_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()<<QString("文件格式: %1").arg(formatContent->iformat->name);
    //输出:解码器名称
    qDebug()<<QString("解码器名称: %1").arg(decoder->name);
    qDebug()<<QString("宽 %1 高 %2").arg(codec->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);

}

3、播放界面

#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实现登录后播放视频-编解码文档类资源

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
对于在QListWidgetItem中放置视频,您可以使用QVideoWidget来显示视频,并使用QMediaPlayer来控制视频播放。 以下是一个简单的示例,展示如何将视频添加到QListWidgetItem中: ```python from PyQt5.QtWidgets import QApplication, QListWidget, QListWidgetItem, QVideoWidget, QHBoxLayout from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent from PyQt5.QtCore import QSize, Qt app = QApplication([]) # 创建QListWidget list_widget = QListWidget() # 创建QVideoWidget video_widget = QVideoWidget() video_widget.setMinimumSize(QSize(300, 200)) # 创建QMediaPlayer media_player = QMediaPlayer(None, QMediaPlayer.VideoSurface) media_player.setVideoOutput(video_widget) # 加载视频文件 media_player.setMedia(QMediaContent(QUrl.fromLocalFile('myvideo.mp4'))) media_player.play() # 将QVideoWidget添加到QListWidgetItem中 list_item = QListWidgetItem() list_item.setSizeHint(QSize(300, 200)) list_widget.addItem(list_item) layout = QHBoxLayout() layout.addWidget(video_widget) list_item.setLayout(layout) # 添加QListWidgetItem到QListWidget中 list_widget.addItem(list_item) # 显示窗口 list_widget.show() app.exec_() ``` 在这个示例中,我们使用QVideoWidget来显示视频。我们还创建了一个QMediaPlayer来控制视频播放,并将视频输出连接到QVideoWidget。 然后,我们将QVideoWidget添加到QListWidgetItem中,并将其添加到QListWidget中。我们还设置了QListWidgetItem的大小,以便它可以正确地显示QVideoWidget。 最后,我们调用`app.exec_()`来运行应用程序并显示窗口。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ze言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值