網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
色度空間轉(zhuǎn)換
YUV顏色模型其實(shí)常用于視頻傳輸和圖像壓縮。由于人類的眼睛,對(duì)亮度的敏感度遠(yuǎn)超過(guò)對(duì)色彩的敏感度,所以視頻傳輸過(guò)程中,為了減小帶寬,通常將色彩分量 UV的比例減小,以達(dá)到降低帶寬的目的。這就出現(xiàn)了YUV4:4:4、YUV4:2:2、YUV4:1:1等格式。
RGB32使用32位來(lái)表示一個(gè)像素,RGB分量各用去8位,剩下的8位用作Alpha通道或者不用。(ARGB32就是帶Alpha通道的RGB32。)注意在內(nèi)存中RGB各分量的排列順序?yàn)椋築GRA BGRA BGRA…。通常可以使用RGB32數(shù)據(jù)結(jié)構(gòu)來(lái)操作一個(gè)像素,它的定義為:
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)
對(duì)本地RGB32視頻圖像的播放
1、繪圖顯示函數(shù) 打開(kāi)目錄函數(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); //畫(huà)出圖像
}
/*接收信號(hào)函數(shù)傳遞來(lái)過(guò)的圖像,并準(zhǔn)備執(zhí)行繪畫(huà)函數(shù)*/
void MainWindow::slotGetOneFrame(QImage img)
{
mImage = img;
update(); //調(diào)用update將執(zhí)行 paintEvent函數(shù)
}
/*打開(kāi)目錄按鍵的槽函數(shù)*/
void MainWindow::on_pushButton_open_clicked()
{
QString s = QFileDialog::getOpenFileName(this, "", "視頻絕對(duì)路徑","rgb flie(*.rgb);;yuv file(*.yuv)");
if (!s.isEmpty())
{
s.replace("/","\\");
ui->lineEdit_filepath->setText(s);//將字符串寫(xiě)入lineEdit_filepath文本框
}
}
2、按開(kāi)始播放的槽函數(shù)
void MainWindow::on_pushButton_display_clicked()
{
/*提取三個(gè)文本框的內(nèi)容*/
QString filePath = ui->lineEdit_filepath->text();
int width = ui->lineEdit_2_width->text().toInt();//toInt()表示將類型轉(zhuǎn)化成int
int height = ui->lineEdit_height->text().toInt();
//視頻播放幀數(shù)設(shè)置
if(ui->fpsBox->currentIndex()==0)//如果下拉框中的數(shù)值是25fps
mThread->Setfps_25();
else//否則
mThread->Setfps_30();
maxValue=filenumber();//滑動(dòng)條最大值獲取
//設(shè)定滑條的范圍,確保滑條的每一步為一幀
ui->horizontalSlider->setRange(0,maxValue-1);//設(shè)定滑動(dòng)條的范圍
mThread->startPlay(filePath,width,height);//啟動(dòng)線程顯示播放
}
3、啟動(dòng)線程 進(jìn)行播放
void TransCodeThread::startPlay(QString infile,int width,int height)
{
mFilePath = infile;
mWidth = width;
mHeight = height;
start();//啟動(dòng)線程執(zhí)行run()
}
/*在獨(dú)立線程中對(duì)視頻進(jìn)行解碼,并通過(guò)信號(hào)函數(shù)sig_GetOneFrame傳送每一幀圖像*/
void TransCodeThread::run()
{
time.start();
char filePath[1024]={0};
strcpy(filePath,mFilePath.toUtf8().data());
FILE *fp_yuv_rgb = fopen(filePath,"rb"); //打開(kāi)視頻文件
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 );//把文件指針指向開(kāi)頭
int yuvSize = width * height *3/2 ;
BYTE *yuvBuffer = (BYTE *)malloc(yuvSize);
int rgbSize = width *height *sizeof(RGB32);//RGB32為一個(gè)結(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)換
}
//把這個(gè)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ā)送信號(hào)
//更新已讀取文件大小,更改滑塊位置
ReadedSize += readedsize;
if(!isMoved)
emit moveSlider(((double)ReadedSize/file_size)*maxValue);//發(fā)送進(jìn)度條移動(dòng)信號(hào) 已讀的比例
int time_Diff = time.elapsed();//消逝的時(shí)間
float f = time_Diff/1000.0;//秒轉(zhuǎn)換為毫秒
float TotalTime = 0 ;
TotalTime += f;//播放的總時(shí)間
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、實(shí)現(xiàn)進(jìn)度條與暫停的各類函數(shù)
//獲取視頻幀數(shù)
int MainWindow::filenumber()
{
/*提取三個(gè)文本框的內(nèi)容*/
QString filePath = ui->lineEdit_filepath->text();
int width = ui->lineEdit_2_width->text().toInt();//toInt()表示將類型轉(zhuǎn)化成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);
/**計(jì)算幀數(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;
}
//滑塊移動(dòng)槽函數(shù) 實(shí)時(shí)獲取滑塊的位置
void MainWindow::on_horizontalSlider_sliderMoved(int position)
{
mThread->SliderPosition = position;
}
// 滑塊松開(kāi)槽函數(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頁(yè)面
mThread = new TransCodeThread;//創(chuàng)建類對(duì)象
/*槽與信號(hào)鏈接*/
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界面
}
原文鏈接:https://blog.csdn.net/m0_60259116/article/details/128292985
相關(guān)推薦
- 2022-07-23 .Net創(chuàng)建型設(shè)計(jì)模式之工廠方法模式(Factory?Method)_基礎(chǔ)應(yīng)用
- 2022-11-24 AOP?Redis自定義注解實(shí)現(xiàn)細(xì)粒度接口IP訪問(wèn)限制_Redis
- 2022-10-15 Qt?TCP網(wǎng)絡(luò)通信學(xué)習(xí)_C 語(yǔ)言
- 2022-02-17 ERROR: but there is no HDFS_NAMENODE_USER defined.
- 2022-07-13 IO流分類以及分別使用字節(jié)流、字符流復(fù)制文本文件、復(fù)制圖片
- 2022-09-08 Pandas中DataFrame的基本操作之重新索引講解_python
- 2022-06-30 Oracle在PL/SQL中使用存儲(chǔ)過(guò)程_oracle
- 2022-04-28 C++實(shí)現(xiàn)班級(jí)成績(jī)管理系統(tǒng)_C 語(yǔ)言
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支