色度空间转换
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()<
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播放器的资料请关注脚本之家其它相关文章!