基于QT播放器的实现(一)Rgb、YUV格式(附带代码)
生活随笔
收集整理的這篇文章主要介紹了
基于QT播放器的实现(一)Rgb、YUV格式(附带代码)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
基于QT播放器的實現(xiàn)(一)Rgb、YUV格式
- 色度空間轉(zhuǎn)換
- YUV轉(zhuǎn)RGB的公式
- 對本地RGB32視頻圖像的播放
色度空間轉(zhuǎn)換
YUV顏色模型其實常用于視頻傳輸和圖像壓縮。由于人類的眼睛,對亮度的敏感度遠(yuǎn)超過對色彩的敏感度,所以視頻傳輸過程中,為了減小帶寬,通常將色彩分量 UV的比例減小,以達(dá)到降低帶寬的目的。這就出現(xiàn)了YUV4:4:4、YUV4:2:2、YUV4:1:1等格式。 RGB32使用32位來表示一個像素,RGB分量各用去8位,剩下的8位用作Alpha通道或者不用。(ARGB32就是帶Alpha通道的RGB32。)注意在內(nèi)存中RGB各分量的排列順序為:BGRA BGRA BGRA…。通常可以使用RGB32數(shù)據(jù)結(jié)構(gòu)來操作一個像素,它的定義為: typedef struct RGB32 { BYTE rgbBlue; // 藍(lán)色分量 BYTE rgbGreen; // 綠色分量 BYTE rgbRed; // 紅色分量 BYTE rgbReserved; // 保留字節(jié)(用作Alpha通道或忽略) } RGB32;YUV轉(zhuǎn)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、繪圖顯示函數(shù) 打開目錄函數(shù)
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); //畫出圖像 } /*接收信號函數(shù)傳遞來過的圖像,并準(zhǔn)備執(zhí)行繪畫函數(shù)*/ void MainWindow::slotGetOneFrame(QImage img) {mImage = img;update(); //調(diào)用update將執(zhí)行 paintEvent函數(shù) } /*打開目錄按鍵的槽函數(shù)*/ 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、按開始播放的槽函數(shù)
void MainWindow::on_pushButton_display_clicked() {/*提取三個文本框的內(nèi)容*/QString filePath = ui->lineEdit_filepath->text();int width = ui->lineEdit_2_width->text().toInt();//toInt()表示將類型轉(zhuǎn)化成intint height = ui->lineEdit_height->text().toInt();//視頻播放幀數(shù)設(shè)置if(ui->fpsBox->currentIndex()==0)//如果下拉框中的數(shù)值是25fpsmThread->Setfps_25();else//否則mThread->Setfps_30();maxValue=filenumber();//滑動條最大值獲取//設(shè)定滑條的范圍,確保滑條的每一步為一幀ui->horizontalSlider->setRange(0,maxValue-1);//設(shè)定滑動條的范圍mThread->startPlay(filePath,width,height);//啟動線程顯示播放 }3、啟動線程 進(jìn)行播放
void TransCodeThread::startPlay(QString infile,int width,int height) {mFilePath = infile;mWidth = width;mHeight = height;start();//啟動線程執(zhí)行run() }/*在獨立線程中對視頻進(jìn)行解碼,并通過信號函數(shù)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為一個結(jié)構(gòu)體 32位BYTE *rgbBuffer = (BYTE *)malloc(rgbSize); //調(diào)試顯示qDebug()<<file_size;qDebug()<<maxValue;int ReadedSize = 0;//已讀文件大小初始化for(int i=0;; i++){if (feof(fp_yuv_rgb))//文件讀取結(jié)束{//qDebug()<<m_i;break;}int readedsize;if(isMoved)//按下滑塊,則修改讀取指針的位置{//獲取文件指針的位置(滑條被分為與幀數(shù)同等分)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);//轉(zhuǎn)換}//把這個RGB數(shù)據(jù) 用QImage加載QImage tmpImg((uchar *)rgbBuffer,width,height,QImage::Format_RGB32);QImage image = tmpImg.copy(); //把圖像復(fù)制一份 傳遞給界面顯示if(fps == 25){msleep(20);}else if(fps == 30){msleep(10);}emit sig_GetOneFrame(image); //發(fā)送信號//更新已讀取文件大小,更改滑塊位置ReadedSize += readedsize;if(!isMoved)emit moveSlider(((double)ReadedSize/file_size)*maxValue);//發(fā)送進(jìn)度條移動信號 已讀的比例int time_Diff = time.elapsed();//消逝的時間float f = time_Diff/1000.0;//秒轉(zhuǎn)換為毫秒float TotalTime = 0 ;TotalTime += f;//播放的總時間QString TT = QString("%1").arg(TotalTime);qDebug() << TT;}//釋放內(nèi)存free(yuvBuffer);free(rgbBuffer); }4、格式轉(zhuǎn)換函數(shù)
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、實現(xiàn)進(jìn)度條與暫停的各類函數(shù)
//獲取視頻幀數(shù) int MainWindow::filenumber() {/*提取三個文本框的內(nèi)容*/QString filePath = ui->lineEdit_filepath->text();int width = ui->lineEdit_2_width->text().toInt();//toInt()表示將類型轉(zhuǎn)化成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);/**計算幀數(shù) 判斷文件類型**/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; } //改變滑塊位置的槽函數(shù) void MainWindow::ChangeSliderPosition(int position) { ui->horizontalSlider->setValue(position); }//滑塊按下槽函數(shù) void MainWindow::on_horizontalSlider_sliderPressed() {//qDebug()<<"anxia ";mThread->isMoved = true; } //滑塊移動槽函數(shù) 實時獲取滑塊的位置 void MainWindow::on_horizontalSlider_sliderMoved(int position) {mThread->SliderPosition = position; } // 滑塊松開槽函數(shù) void MainWindow::on_horizontalSlider_sliderReleased() {mThread->isMoved = false; } //暫停按鈕槽函數(shù) void MainWindow::on_pushButton_pause_clicked() {mThread->SliderPosition = ui->horizontalSlider->value();mThread->isMoved = !mThread->isMoved; }6、各類槽函數(shù)的連接
/*構(gòu)造函數(shù)*/ MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow) {ui->setupUi(this);//創(chuàng)建ui頁面mThread = new TransCodeThread;//創(chuàng)建類對象/*槽與信號鏈接*/connect(mThread,SIGNAL(sig_GetOneFrame(QImage)),this,SLOT(slotGetOneFrame(QImage)));//進(jìn)行圖像傳遞和接收connect(mThread,&TransCodeThread::moveSlider, this, &MainWindow::ChangeSliderPosition); }/*析構(gòu)函數(shù)*/ MainWindow::~MainWindow() {delete ui;//刪除ui界面 }總結(jié)
以上是生活随笔為你收集整理的基于QT播放器的实现(一)Rgb、YUV格式(附带代码)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端学习(1754):前端调试值之监控页
- 下一篇: 前端学习(1956)vue之电商管理系统