基于QT播放器的实现(一)Rgb、YUV格式

  • 色度空间转换
  • YUV转RGB的公式
  • 对本地RGB32视频图像的播放

色度空间转换

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()表示将类型转化成intint height = ui->lineEdit_height->text().toInt();//视频播放帧数设置if(ui->fpsBox->currentIndex()==0)//如果下拉框中的数值是25fpsmThread->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()表示将类型转化成intint 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格式(附带代码)相关推荐

  1. 单片机及接口课程设计报告-------基于音乐播放器

    目录 课设目的.内容....................................................................................... 1. ...

  2. VLC+Qt播放器对比测试

    开发环境:VS2017 + Qt5.12.5 + Vlc3.0 事先说明 为什么做这个东西. 各个播放器都有各自的优缺点.LibVlc太大,启动慢,对于播放一些短小的特效音视频不太好用,而且进度反馈也 ...

  3. 基于exoplayer播放器的高斯模糊视频滤镜

    最近项目需求,视频滤镜要用高斯模糊.奈何网上全是图片高斯模糊,且模糊的强度不够,效果并不是自己需要的. 于是,打算自己写一个. exoPlayer播放器自带滤镜,所以用这个播放器来做. 滤镜的话,用到 ...

  4. iOS实现基于VLC播放器的封装效果

    前言: 在一些特定场景下,我们获取到的音视频,由于格式比较特殊,用avplayer等播放器是无法播放的,此时,我们可以借助强大的VLC播放器来处理. 原理这里不再赘述,下面我们讲一下如何添加VLC播放 ...

  5. 基于exoplayer播放器的高斯模糊视频滤镜,整合aar文件,给伸手党

    接入步骤如下: 接入步骤 1.aar文件拷贝至app下libs文件夹内 2.在app下的build.gradle中添加(最外层) repositories {flatDir {dirs 'libs'} ...

  6. JQuery播放器代理--IE下支持wma格式

    Jplayer代理类   1/**//**   2*   3* Media 代理   4* @param Object p_play:播放器   5*/   6var media_player_pro ...

  7. JY播放器【蜻蜓FM电脑端,附带下载功能】

    今天给大家带来一款神器----JY播放器.可以不用打开网页就在电脑端听蜻蜓FM的节目,而且可以直接下载,对于我这种强迫症患者来说真的是神器.我是真的不喜欢电脑任务栏上面密密麻麻. 目前已经支持平台(蜻 ...

  8. JY播放器【喜马拉雅FM电脑端,附带下载功能】

    今天给大家带来一款神器----JY播放器.可以不用打开网页就在电脑端听喜马拉雅FM的节目,而且可以直接下载,对于我这种强迫症患者来说真的是神器.我是真的不喜欢电脑任务栏上面密密麻麻的. 目前已经支持平 ...

  9. 视频与图像RGB/YUV格式详解

    计算机彩色显示器显示色彩的原理与彩色电视机一样,都是采用R(Red).G(Green).B(Blue)相加混色的原理:通过发射出三种不同强度的电子束,使屏幕内侧覆盖的红.绿.蓝磷光材料发光而产生色彩. ...

  10. 基于海思3559 高效率的 0延时 0拷贝 qt播放器方案

    海思的有很好的mpp SDK, 播放视频流的,可以快速的从VDEC(解码)到 VO(显示),但是当我们UI需求比较复杂的时候,需要很多操作界面,比如快进,后退,比如调节摄像头位置等等,这些复杂的UI ...

最新文章

  1. mdkstc系列器件支持包下载_Find X2系列 Android 11 Beta1 测试版发布
  2. 《去哪网编程题》统计字符
  3. iOS实现经典登录页面,手机号自动格式化
  4. vue省市区三级联动mysql,js/json,html/jsp
  5. python中协程与函数的区别_python 协程与go协程的区别
  6. 过完年进入BAT 需要做哪些准备
  7. 今天最好的生日礼物就是重新找到目标
  8. HDU-2502 月之数 组合数
  9. c语言 字节 半字 字,PLC的位,半字节,字节,字介绍
  10. The P4 Language Specification v1.0.2 Parser
  11. 虚拟机ping不通宿主机,宿主机能ping通虚拟机
  12. 792. 高精度减法
  13. 水仙花数c语言程序解析,C语言求水仙花数代码解析
  14. MyEclipse6.5的反编译插件的安装
  15. Moodle安装完全手册
  16. HP M280 鼠标驱动
  17. C语言的内存问题总结
  18. 可视化工具 roto 3t
  19. Unity Loading转场学习笔记
  20. UE4 C++ 动态读取图片

热门文章

  1. shl归纳推理测试题库_强生2020秋招笔试面试经验合集
  2. 论文的重复率修改方法
  3. 好项目,不私藏!适用于单片机开发的开源轮子
  4. java删除非空文件夹
  5. windows下,可替换telnet的工具tcping.exe
  6. wincc7.5官网下载及安装配置(适配window10超详细教程)
  7. dnf服务器运行库,游戏运行库|3DM游戏必备运行库合集安装包(史上最全) V3.0
  8. oracle查询undo表空间使用率,检查Undo表空间使用情况
  9. 中国电信与阿里巴巴签署全面战略合作协议
  10. 视频监控存储解决方案——快速、可靠的视频存储