Qt截屏 X265lib編碼 rtsp請(qǐng)求 rtp流發(fā)送 (截屏轉(zhuǎn)YUV 4:2:0)實(shí)現(xiàn)

一、QT實(shí)現(xiàn)截屏為QImage;

這個(gè)相對(duì)來(lái)說(shuō)網(wǎng)上資料比較多!
   #include <QGuiApplication> 
   #include <QPixmap>
   #include <QScreen>
   #include<QImage>
  int main(int argc, char *argv[])
   {
        QScreen *screen= QGuiApplication::primaryScreen(); //獲取屏幕接口
        QPixmap disktop_img= screen>grabWindow(0).scaled(
                    1024,768,Qt::IgnoreAspectRatio,Qt::SmoothTransformation
          ); //調(diào)整圖像大小為1024×768
        QImage disktop=disktop_img.toImage(); //轉(zhuǎn)換為QImage
//RGBA 32位轉(zhuǎn)換為RGB 24位
        QImage  disktop= disktop.convertToFormat(QImage::Format_RGB888);
}

二、實(shí)現(xiàn)QImage轉(zhuǎn)YUV:4:2:0

\color{rgb(255,125,125)}{ 什么是RGBA、什么是RGB?這個(gè)是理解YUV轉(zhuǎn)換的開(kāi)始!}
RGBA 是用32位bit來(lái)描述一個(gè)像素點(diǎn)的,比如寬1024 高768的QImage 實(shí)際大小為1024×768×32
一個(gè)像素點(diǎn):8位R、8位的G、8位的B、8位的透明A來(lái)組成。
RGB是用24位bit來(lái)表示一個(gè)像素點(diǎn)的,比如寬1024高768的QImage實(shí)際大小為1024×768×24
一個(gè)像素點(diǎn):8位的R、8位的G、8位的B組成。
\color{rgb(255,125,125)}{什么是YUV 4:2:0}
yuv是由灰度數(shù)據(jù)+U+V
Y的大小為:圖片的寬度×圖片的高度;
U的大小為:圖片的寬度×圖片的高度/4;
V的大小為:圖片的寬度×圖片的高度/4;
也就是說(shuō)你拿到一個(gè)YUV圖像你要知道圖像的寬度,高度,4:2:0因?yàn)閅UV圖像文件并不攜帶寬度,高度信息。也只有得到寬度高度才能在文件中切分出Y,U,V的值;
我們需要用下圖來(lái)理解YUV 4:2:0

yuv.jpg

這是一張寬13像素×13像素的RGB24位的原圖。
1、Y:遍歷每個(gè)像素(uint_8[3])計(jì)算出Y的數(shù)據(jù)列表;
2、U:每隔一行并且為奇數(shù)時(shí)計(jì)算一個(gè)U值存到U的列表中;
3、V:每隔一行并且為奇數(shù)時(shí)計(jì)算一個(gè)U值存到V的列表中;
Y的算法:0.299R+0.587G+0.114B;
U的算法:-0.169
R-0.331G+0.5B+128;
V的算法:0.5R-0.419G-0.081*G+128

#include<QByteArray>
#include<QList>
#include <QGuiApplication> 
#include <QPixmap>
#include <QScreen>
#include<QImage>
QList<QByteArray>  returnyuv(){ 
 //屏幕
QScreen *screen= QGuiApplication::primaryScreen(); 
//截屏
QPixmap disktop_img= screen->grabWindow(0).scaled(1024,768,Qt::IgnoreAspectRatio,Qt::SmoothTransformation); 
QImage disktop=disktop_img.toImage(); 
//rgba轉(zhuǎn)為rgb,也就是上面提到的rgb24;
disktop= disktop.convertToFormat(QImage::Format_RGB888);
 //rgb  轉(zhuǎn) yuv 4:2:0
QByteArray y_l,u_l,v_l,yuv; //Y ,U,V
uchar * d=disktop.bits();    //截屏QImage的數(shù)據(jù)
    //循環(huán)變量
    int i,j;
    int width=disktop.width();   //截屏QImage寬
    int height=disktop.height(); //截屏QImage高
    uint8_t r,g,b,y,u,v;            
    for(i=0;i<height;i++){      //遍歷截屏QImage的所有行.
        for(j=0;j<width;j++){    //遍歷當(dāng)前行的所有像素.
            int pos=i*(width*3)+j*3;   //行號(hào)*行寬=已遍歷行的數(shù)據(jù)+這一行的第幾個(gè)像素,3表示:一個(gè)像素占3個(gè)bit
      //一個(gè)像素的數(shù)據(jù)格式:[B,G,R]
            r=d[pos+2]; //取出當(dāng)前像素的R
            g=d[pos+1]; //取出當(dāng)前像素的G
            b=d[pos];     //取出當(dāng)前像素的B
            y=0.299*r+0.587*g+0.114*b;  //根據(jù)公式求出Y的值
            y_l.append(y);       //把值壓入Y的Bytearray;
            if(i%2==0 and j%2==0){ // 偶數(shù)行并且偶數(shù)像素(4個(gè)像素取1個(gè)像素計(jì)算出UV)
                u=-0.169*r-0.331*g+0.5*b+128;  //計(jì)算出U值
                           u_l.append(u);        //把U值壓入U(xiǎn)的Bytearray
                v=0.5*r-0.419*g-0.081*b+128;   //計(jì)算出V值
                           v_l.append(v);      //把V值壓入V的Bytearray
              }
        }
    }
    QList<QByteArray> yuv_byte;  //[Y[Qbytearray],U[Qbytearray],V[Qbytearray]]
    yuv_byte.append(y_l);
    yuv_byte.append(v_l);
    yuv_byte.append(u_l);
    return yuv_byte; //返回yuv
}

//驗(yàn)證轉(zhuǎn)換是否成功
int main(){
    QFile write_file_yuv("./tmp.yuv");
    write_file_yuv.open(QIODevice::WriteOnly);
    if (write_file_yuv.isOpen()){
         QByteArray tmp_file;
        QList<QByteArray> yuv_byte= returnyuv(); //調(diào)用截屏返回[y,u,v]
        for(int i=0;i<yuv_byte.length();i++){
            tmp_file.append(yuv_byte[i]);
        }
        write_file_yuv.write(tmp_file); //本地文件存儲(chǔ)
        write_file_yuv.flush();
        write_file_yuv.close();
    }
}

\color{rgb(125,125,125)}{使用yuv播放器驗(yàn)證}
yuview 播放器\color{rgb(255,0,0)}{注意:選擇格式為yuv 4:2:0,寬度為1024,高為768,yuv圖像不帶寬高信息,所以你必須知道你圖像的大小}

Overview.png

\color{rgb(255,0,0)}{yuv是x265接受的輸入方式是不支持rgb,也就是說(shuō)只有實(shí)現(xiàn)了yuv圖像才能繼續(xù)....}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

  • 為什么在頭文件中有的是使用前置聲明,而有的是包含頭文件? 如下代碼: 前置聲明(forward declarati...
    Joe_HUST閱讀 1,451評(píng)論 0 6
  • 今天看到了錘子校園招聘的筆試題: “滾動(dòng)截屏”的功能設(shè)計(jì) 簡(jiǎn)單思考了一下,準(zhǔn)備寫(xiě)個(gè)需求文檔練練手。 模塊1與大多數(shù)...
    bboyshao閱讀 1,780評(píng)論 0 6
  • 截屏,或者說(shuō)截圖,大概是我們除了復(fù)制/粘貼以外,比較常用的一個(gè)操作了.一般來(lái)說(shuō),有屏幕的地方就可以截屏.譬如電腦的...
    半坡城主閱讀 4,550評(píng)論 0 17
  • 1.初識(shí) Qt5 本書(shū)將為大家介紹使用 Qt 5.x 版本開(kāi)發(fā)應(yīng)用程序的不同方面。我們將專注于新的 Qt Quic...
    趙者也閱讀 2,773評(píng)論 0 8
  • 1.Qt概述 1.1 什么是Qt Qt是一個(gè)跨平臺(tái)的C++圖形用戶界面應(yīng)用程序框架。它為應(yīng)用程序開(kāi)發(fā)者提供建立藝術(shù)...
    你的社交帳號(hào)昵閱讀 8,889評(píng)論 0 10

友情鏈接更多精彩內(nèi)容