基于Qt播放器的实现详解(支持Rgb,YUV格式)

目录
  • 色度空间转换
  • YUV转RGB的公式
  • 对本地RGB32视频图像的播放
    • 1、绘图显示函数 打开目录函数
    • 2、按开始播放的槽函数
    • 3、启动线程 进行播放
    • 4、格式转换函数
    • 5、实现进度条与暂停的各类函数
    • 6、各类槽函数的连接

色度空间转换

YUV颜色模型其实常用于视频传输和图像压缩。由于人类的眼睛,对亮度的敏感度远超过对色彩的敏感度,所以视频传输过程中,为了减小带宽,通常将色彩分量 UV的比例减小,以达到降低带宽的目的。这就出现了YUV4:4:4、YUV4:2:2、YUV4:1:1等格式。

RGB32使用32位来表示一个像素,RGB分量各用去8位,剩下的8位用作Alpha通道或者不用。(ARGB32就是带Alpha通道的RGB32。)注意在内存中RGB各分量的排列顺序为:BGRA BGRA BGRA…。通常可以使用RGB32数据结构来操作一个像素,它的定义为:

typedef struct RGB32 {
BYTE    rgbBlue;      // 蓝色分量
BYTE    rgbGreen;     // 绿色分量
BYTE    rgbRed;       // 红色分量
BYTE    rgbReserved;  // 保留字节(用作Alpha通道或忽略)
} RGB32;

YUV转RGB的公式

R = Y + 1.402 * (V-128) G = Y – 0.34413 * (U-128) – 0.71414*(V-128) B= Y + 1.772*(U-128)

对本地RGB32视频图像的播放

1、绘图显示函数 打开目录函数

void MainWindow ::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setBrush(Qt::black);
    QRect rect = ui->widget_video->geometry();
    painter.drawRect(rect);

    if (mImage.size().width() <= 0) return;
    //将图像按比例缩放成和窗口一样大小
    QImage img = mImage.scaled(ui->widget_video->size(),Qt::KeepAspectRatio);
    int x = ui->widget_video->width() - img.width();
    int y = ui->widget_video->height() - img.height();
    x /= 2;
    y /= 2;
    x += ui->widget_video->x();
    y += ui->widget_video->y();
    painter.drawImage(QPoint(x,y),img); //画出图像
}
/*接收信号函数传递来过的图像,并准备执行绘画函数*/
void MainWindow::slotGetOneFrame(QImage img)
{
    mImage = img;
    update(); //调用update将执行 paintEvent函数
}
/*打开目录按键的槽函数*/
void MainWindow::on_pushButton_open_clicked()
{
    QString s = QFileDialog::getOpenFileName(this, "", "视频绝对路径","rgb flie(*.rgb);;yuv file(*.yuv)");
    if (!s.isEmpty())
    {
        s.replace("/","\\");
        ui->lineEdit_filepath->setText(s);//将字符串写入lineEdit_filepath文本框
    }

}

2、按开始播放的槽函数

void MainWindow::on_pushButton_display_clicked()
{
    /*提取三个文本框的内容*/
    QString filePath = ui->lineEdit_filepath->text();
    int width = ui->lineEdit_2_width->text().toInt();//toInt()表示将类型转化成int
    int height = ui->lineEdit_height->text().toInt();
  //视频播放帧数设置
    if(ui->fpsBox->currentIndex()==0)//如果下拉框中的数值是25fps
        mThread->Setfps_25();
    else//否则
        mThread->Setfps_30();
    maxValue=filenumber();//滑动条最大值获取
    //设定滑条的范围,确保滑条的每一步为一帧
    ui->horizontalSlider->setRange(0,maxValue-1);//设定滑动条的范围
    mThread->startPlay(filePath,width,height);//启动线程显示播放
}

3、启动线程 进行播放

void TransCodeThread::startPlay(QString infile,int width,int height)
{
    mFilePath = infile;
    mWidth = width;
    mHeight = height;
    start();//启动线程执行run()
}

/*在独立线程中对视频进行解码,并通过信号函数sig_GetOneFrame传送每一帧图像*/
void TransCodeThread::run()
{
        time.start();
        char filePath[1024]={0};
        strcpy(filePath,mFilePath.toUtf8().data());
        FILE *fp_yuv_rgb = fopen(filePath,"rb");  //打开视频文件
        int width = mWidth;
        int height = mHeight;
        if (fp_yuv_rgb == NULL) return;
        /**判断文件类型**/
        QString fileright = mFilePath.right(3);
        if(fileright =="rgb")
           {
             m_filetype=1;
           }
        else if(fileright =="yuv")
           {
              m_filetype=0;
           }
        //获取文件的大小
        fseek( fp_yuv_rgb,0,SEEK_END );  //把文件指针定位到文件尾
        int file_size=ftell( fp_yuv_rgb );//获取文件的大小
        fseek( fp_yuv_rgb,0,SEEK_SET );//把文件指针指向开头

        int yuvSize = width * height *3/2  ;
        BYTE *yuvBuffer = (BYTE *)malloc(yuvSize);
        int rgbSize = width *height *sizeof(RGB32);//RGB32为一个结构体   32位
        BYTE *rgbBuffer = (BYTE *)malloc(rgbSize);
        //调试显示
         qDebug()<<file_size;
         qDebug()<<maxValue;
        int ReadedSize = 0;//已读文件大小初始化
        for(int i=0;; i++)
        {
            if (feof(fp_yuv_rgb))//文件读取结束
            {
              //qDebug()<<m_i;
              break;
            }
            int readedsize;
            if(isMoved)//按下滑块,则修改读取指针的位置
            {

                //获取文件指针的位置(滑条被分为与帧数同等分)
                int pointPosition = file_size * (double)SliderPosition/maxValue;
                fseek( fp_yuv_rgb, pointPosition , SEEK_SET );
                ReadedSize = pointPosition ;
            }
            if(m_filetype==1)//rgb
            {
                readedsize= fread(rgbBuffer,1,rgbSize,fp_yuv_rgb);//注释,YUV2RGB
               // qDebug()<<readedsize;
            }
            else//yuv
            {
                readedsize=  fread(yuvBuffer,1,yuvSize,fp_yuv_rgb);//读取yuv文件
                Yuv420p2Rgb32(yuvBuffer, rgbBuffer, width, height);//转换
            }
             //把这个RGB数据 用QImage加载
            QImage tmpImg((uchar *)rgbBuffer,width,height,QImage::Format_RGB32);
            QImage image = tmpImg.copy(); //把图像复制一份 传递给界面显示
            if(fps == 25)
            {
                msleep(20);
            }
            else if(fps == 30)
            {
                msleep(10);
            }
            emit sig_GetOneFrame(image);  //发送信号
            //更新已读取文件大小,更改滑块位置
            ReadedSize += readedsize;
            if(!isMoved)
                emit moveSlider(((double)ReadedSize/file_size)*maxValue);//发送进度条移动信号  已读的比例
            int time_Diff = time.elapsed();//消逝的时间
            float f = time_Diff/1000.0;//秒转换为毫秒
            float TotalTime = 0 ;
            TotalTime += f;//播放的总时间
            QString TT = QString("%1").arg(TotalTime);
            qDebug() << TT;
        }
        //释放内存
        free(yuvBuffer);
        free(rgbBuffer);
}

4、格式转换函数

void TransCodeThread::Yuv420p2Rgb32(const BYTE *yuvBuffer_in,const BYTE *rgbBuffer_out,int width,int height)
{
    BYTE *yuvBuffer = (BYTE *)yuvBuffer_in;
    RGB32 *rgb32Buffer = (RGB32 *)rgbBuffer_out;

    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            int index = y * width + x;

            int indexY = y * width + x;
            int indexU = width * height + y / 2 * width / 2 + x / 2;
            int indexV = width * height + width * height / 4 + y / 2 * width / 2 + x / 2;

            BYTE Y = yuvBuffer[indexY];
            BYTE U = yuvBuffer[indexU];
            BYTE V = yuvBuffer[indexV];

            RGB32 *rgbNode = &rgb32Buffer[index];

            rgbNode->rgbRed = Y + 1.402 * (V-128);
            rgbNode->rgbGreen = Y - 0.34413 * (U-128) - 0.71414*(V-128);
            rgbNode->rgbBlue = Y + 1.772*(U-128);
        }
    }
}

5、实现进度条与暂停的各类函数

//获取视频帧数
int  MainWindow::filenumber()
{
    /*提取三个文本框的内容*/
    QString filePath = ui->lineEdit_filepath->text();
    int width = ui->lineEdit_2_width->text().toInt();//toInt()表示将类型转化成int
    int height = ui->lineEdit_height->text().toInt();
    char curfilePath[1024]={0};
    strcpy(curfilePath,filePath.toUtf8().data());
    FILE *fp_yuv_rgb = fopen(curfilePath,"rb");
    //文件指针移到文件尾
    fseek( fp_yuv_rgb,0,SEEK_END );
    //获取文件的大小
    int file_size=ftell( fp_yuv_rgb );

    int yuvSize = width * height * 3/2  ;
    int rgbSize = width *height *sizeof(RGB32);
    /**计算帧数 判断文件类型**/
    QString fileright = filePath.right(3);
    static int number;
    if(fileright =="rgb")
       {
          number = file_size/rgbSize;
       }
    else if(fileright =="yuv")
       {
          number = file_size/yuvSize;
       }
     return number;
}
//改变滑块位置的槽函数
void MainWindow::ChangeSliderPosition(int position)
{
    ui->horizontalSlider->setValue(position);
}

//滑块按下槽函数
void MainWindow::on_horizontalSlider_sliderPressed()
{
    //qDebug()<<"anxia ";
    mThread->isMoved = true;
}
//滑块移动槽函数  实时获取滑块的位置
void MainWindow::on_horizontalSlider_sliderMoved(int position)
{
    mThread->SliderPosition = position;
}
// 滑块松开槽函数
void MainWindow::on_horizontalSlider_sliderReleased()
{
    mThread->isMoved = false;
}
//暂停按钮槽函数
void MainWindow::on_pushButton_pause_clicked()
{
    mThread->SliderPosition = ui->horizontalSlider->value();
    mThread->isMoved = !mThread->isMoved;
}

6、各类槽函数的连接

/*构造函数*/
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);//创建ui页面
    mThread = new TransCodeThread;//创建类对象

    /*槽与信号链接*/
    connect(mThread,SIGNAL(sig_GetOneFrame(QImage)),this,SLOT(slotGetOneFrame(QImage)));//进行图像传递和接收
    connect(mThread,&TransCodeThread::moveSlider, this, &MainWindow::ChangeSliderPosition);
}

/*析构函数*/
MainWindow::~MainWindow()
{
    delete ui;//删除ui界面
}

以上就是基于Qt播放器的实现详解(支持Rgb,YUV格式)的详细内容,更多关于Qt播放器的资料请关注我们其它相关文章!

(0)

相关推荐

  • QT实现简单音乐播放器

    基于QT实现一个多功能媒体播放器,它能播放音频(如mp3),视频 媒体播放器界面,有进度条,可展示总播放时间.当前播放时间,进度条可拖动,有播放.暂停键,有快进.快退键,上一曲下一曲,静音,调节音量,双击播放歌曲,以及简单的歌词同步. 主界面如下: 创建三个本地文件夹分别存放MV,歌词和音乐文件 工程结构目录如下(整个结构没有设计好,所以每个视频都要单独创建文件): mainwindow.h代码如下: #ifndef MAINWINDOW_H #define MAINWINDOW_H #incl

  • 基于Qt编写简易的视频播放器

    目录 一.前言 二.效果图 三.体验地址 四.相关代码 五.功能特点 5.1 基础功能 5.2 特色功能 5.3 视频控件 5.4 内核ffmpeg 一.前言 花了一年多的时间,终于把这个超级播放器做成了自己想要的架构,用户的需求是一方面,自己架构方面的提升也是一方面,最主要是将界面和解码解耦了,这样才能动态的挂载不同的解码内核到不同的窗体,多对多关系,而且解耦和才能方便的实现共享解码,整个设计参照了Qt的设计思路,将各种功能做成不同的类组件,同时还有多层基类的设计,最大的提炼共性,本组件设计的

  • 基于Qt实现简易GIF播放器的示例代码

    目录 一.项目介绍 二.项目基本配置 三.UI界面设计 四.主程序实现 4.1 mainwindow.h头文件 4.2 mainwindow.cpp源文件 五.效果演示 一.项目介绍 利用Qt设计一个简易GIF播放器,可以播放GIF动画.其基本功能有载入文件.播放.暂停.停止.快进和快退. 二.项目基本配置 新建一个Qt案例,项目名称为“GIFTest”,基类选择“QMainWindow”,创建UI界面复选框的选中状态,完成项目创建. 三.UI界面设计 UI界面如下: 界面中创建了8个控件,其名

  • 基于Qt实现视频播放器功能

    目录 一.功能介绍 二.代码 三.运行 一.功能介绍 能实现视频播放 二.代码 mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QMediaPlayer> #include <QMediaPlaylist> #include <QPushButton> #include <QSlider> #include <QV

  • 基于Qt播放器的实现详解(支持Rgb,YUV格式)

    目录 色度空间转换 YUV转RGB的公式 对本地RGB32视频图像的播放 1.绘图显示函数 打开目录函数 2.按开始播放的槽函数 3.启动线程 进行播放 4.格式转换函数 5.实现进度条与暂停的各类函数 6.各类槽函数的连接 色度空间转换 YUV颜色模型其实常用于视频传输和图像压缩.由于人类的眼睛,对亮度的敏感度远超过对色彩的敏感度,所以视频传输过程中,为了减小带宽,通常将色彩分量 UV的比例减小,以达到降低带宽的目的.这就出现了YUV4:4:4.YUV4:2:2.YUV4:1:1等格式. RG

  • 网页播放器Object使用详解

    一.代码 复制代码 代码如下: <object ID="javademo" CLASSID="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" HEIGHT="280" WIDTH="200"> <param name="AUTOSTART" value="0"> <param name="SHUFFLE&qu

  • WMV网页播放器参数中文详解

    复制代码 代码如下: <object id="mePlay" classid="CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95" codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,0,5,0803" standby="Loading Windows Media Pl

  • 基于C#实现屏幕取色器的示例详解

    目录 实践过程 效果 代码 实践过程 效果 代码 public partial class Form1 : Form { public Form1() { InitializeComponent(); } [DllImport("gdi32.dll")] static public extern uint GetPixel(IntPtr hDC, int XPos, int YPos); [DllImport("gdi32.dll")] static public

  • 基于Maven的pom.xml文件详解

    如下所示: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd "> <!-- 父项

  • 基于Django contrib Comments 评论模块(详解)

    老版本的Django中自带一个评论框架.但是从1.6版本后,该框架独立出去了,也就是本文的评论插件. 这个插件可给models附加评论,因此常被用于为博客文章.图片.书籍章节或其它任何东西添加评论. 一.快速入门 快速使用步骤: 安装包:pip install django-contrib-comments 在django的settings中的INSTALLED_APPS处添加'django.contrib.sites'进行app注册,并设置SITE_ID值. 在django的settings中

  • windows第七层负载均衡_基于IIS的ARR负载均衡详解

    载均衡有很多种方法,有硬件负载均衡,软件负载均衡,还可以从域名解析下手. 不过,今天只讲软件负载均衡. 软件负载均衡一般分两种,从网络协议来讲(tcp/ip),主要集中在第四层和第七层进行负载均衡. 第四层就是基于IP进行负载均衡.后面还有一篇文章讲这个. 第七层就是应用层.比如各种的WEB服务器.今天就讲讲IIS的负载均衡. 第七层的Web负载均衡,很多web服务器都支持,比如IIS,Nginx,apache等.现在主要讲一下windosw下IIS如何使用负载均衡 IIS使用ARR反向代理,实

  • Python机器学习应用之基于BP神经网络的预测篇详解

    目录 一.Introduction 1 BP神经网络的优点 2 BP神经网络的缺点 二.实现过程 1 Demo 2 基于BP神经网络的乳腺癌分类预测 三.Keys 一.Introduction 1 BP神经网络的优点 非线性映射能力:BP神经网络实质上实现了一个从输入到输出的映射功能,数学理论证明三层的神经网络就能够以任意精度逼近任何非线性连续函数.这使得其特别适合于求解内部机制复杂的问题,即BP神经网络具有较强的非线性映射能力. 自学习和自适应能力:BP神经网络在训练时,能够通过学习自动提取输

  • Qt使用QWT绘制柱状图详解

    目录 1:设置QChart的整体背景色 2:设置有效区域的背景色 3:设置X.Y坐标轴数据 4:设置网格线 5:插入实际数据 6:X轴刻度值优化 7:设置X轴文本偏移 8:设置每个柱状体的宽度 9:设置每个柱状体的偏移量 10:修改鼠标的显示状态 有的时候我们会遇到这样一种功能,需要在柱状图中显示不同颜色的柱状体,每个主状态代表的状态不同,那么如果只是用简单的QChart是难以实现的. QT中提供了一个叫做QWT的库.QWT,全称是Qt Widgets for Technical Applica

  • 得物基于StarRocks的OLAP需求实践详解

    目录 1. 什么是 StarRocks 2. 系统架构 3. 存储架构 3.1 表的存储 4. 需求背景 案例一: 案例二: 5. 经验分享 6. 未来规划 1. 什么是 StarRocks 新一代极速全场景MPP数据库,可以用 StarRocks 来支持多种数据分析场景的极速分析: 架构简洁,采用了全面向量化引擎,并配备全新设计的 CBO 优化器,查询速度(尤其是多表关联查询): 很好地支持实时数据分析,并能实现对实时更新数据的高效查询, 还支持现代化物化视图,以进一步加速查询: 用户可以灵活

随机推荐