視頻錄制——2.加上實(shí)時(shí)美顏

要加上實(shí)時(shí)美顏沼琉,就要編寫(xiě)texture -> 幀緩沖區(qū)的過(guò)程傻昙。

texture -> 幀緩沖區(qū)的過(guò)程是用OpenGL繪圖。
OpenGL是一臺(tái)管理渲染管線的狀態(tài)機(jī)贾惦。
渲染管線有一個(gè)出口绞惦,一個(gè)入口杰刽。
入口可以指向一個(gè)texture雁乡,出口可以指向幀緩沖區(qū)或一個(gè)FBO曲饱。
幀緩沖區(qū)是顯存中特殊的一塊,儲(chǔ)存經(jīng)渲染管線加工后得到的二維像素?cái)?shù)據(jù),它對(duì)應(yīng)的FBO索引為0。

幾個(gè)步驟:

  1. 輸出 -> cameraFrameBuffer象对,覆蓋為(0沥邻,0,0邮利,0)
    輸入 -> 攝像頭紋理
    用cameraProgram繪制 -> 頂點(diǎn)經(jīng)過(guò)Matrix調(diào)整贸诚,cameraTexture為攝像頭紋理
  2. 輸出 -> gaussFrameBuffer械念,覆蓋為(0,0,0,0)
    輸入 -> cameraTexture
    用gaussProgram繪制 -> 頂點(diǎn)位置不變、gaussTexture為磨皮后的攝像頭紋理
  3. 輸出 -> 幀緩沖區(qū) ,覆蓋為(0,0赛蔫,0,0)
    輸入 -> cameraTexture彤恶、gaussTexture术徊、smoothTexture
    用smoothProgram繪制 -> 幀緩沖區(qū)為美白后的二維像素?cái)?shù)據(jù)

*每次glDrawArrays前,都要先把輸出的FBO覆蓋為(0,0,0,0)。
*如果一個(gè)texture綁定到一個(gè)FBO,那么對(duì)FBO的寫(xiě)入操作會(huì)影響texture。這被用來(lái)進(jìn)行render to texture该镣。

常用的GL接口:

// 創(chuàng)建n個(gè)紋理,索引用textures裝載返回
public static native void glGenTextures(int n, java.nio.IntBuffer textures);

// 創(chuàng)建n個(gè)FBO,索引用framebuffers裝載返回
public static native void glGenFramebuffers(int n, java.nio.IntBuffer framebuffers);

// 把入口指向索引為texture的texture擦耀,texture的類型為target涩堤;特別地眷蜓,當(dāng)texture= 0時(shí)不使用紋理
public static native void glBindTexture(int target, int texture);

// 把出口指向索引為framebuffer的FBO胎围,F(xiàn)BO的類型為target;特別地福荸,當(dāng)framebuffer = 0時(shí)指向幀緩沖區(qū)
public static native void glBindFramebuffer(int target, int framebuffer);

// 用bitmap填充texture
// target:texture的類型
// level:質(zhì)量等級(jí)
// internalformat:圖像格式
// type:數(shù)據(jù)格式
// border:邊框?qū)挾?public static void texImage2D(int target, int level, int internalformat, Bitmap bitmap, int type, int border)

// 把texture綁定到FBO
// target:texture的類型
// attachment:FBO的接入點(diǎn)
// textarget:texture的索引
// level:質(zhì)量等級(jí)
public static native void glFramebufferTexture2D(int target, int attachment, int textarget, int texture, int level);

// 設(shè)置用來(lái)覆蓋出口指向的FBO或幀緩沖區(qū)的RGBA值(還沒(méi)有覆蓋)
public static native void glClearColor(float red, float green, float blue, float alpha);

// 用上一個(gè)接口設(shè)置的RGBA值來(lái)覆蓋出口指向的FBO或幀緩沖區(qū)(覆蓋了)颤介;
// mask指明覆蓋哪一層滚朵,如GLES20.GL_COLOR_BUFFER_BIT覆蓋顏色層
public static native void glClear(int mask);

// 設(shè)置視口位置及尺寸
public static native void glViewport(int x, int y, int width, int height);

// 開(kāi)始繪制
// mode:以怎樣的行為繪制
// first:起始處偏移量
// count:頂點(diǎn)數(shù)量
public static native void glDrawArrays(int mode, int first, int count);

*注意:所有“創(chuàng)建”的行為只是在OpenGL的命名空間中創(chuàng)建了一個(gè)名字(索引)学赛,只有在綁定后才真正為texture或FBO分配空間

關(guān)于GLSL

磨皮和美白的算法要用GLSL寫(xiě)Shader程序,記錄一下常用的GLSL和載入方法

// attribute修飾符表示由APP傳來(lái)的頂點(diǎn)數(shù)據(jù),只用于vertex
attribute vec2 position;
attribute vec2 inputTextureCoordinate;

// uniform修飾符表示由APP傳來(lái)的常量给梅,可用于vertex和fragment
uniform float texelWidthOffset;
uniform float texelHeightOffset;

// varying修飾符表示由vertex初始化,供fragment使用的值
varying vec2 blurCoordinates[3];

void main() {
    // gl_Position是內(nèi)建變量迅办,表示頂點(diǎn)的輸出位置
    gl_Position = vec4(position.xy,0,1);
    vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);
    blurCoordinates[0] = inputTextureCoordinate.xy;
    blurCoordinates[1] = inputTextureCoordinate.xy + singleStepOffset * optimizedGaussianOffsets[0];
    blurCoordinates[2] = inputTextureCoordinate.xy - singleStepOffset * optimizedGaussianOffsets[1];
}
String s = (上面那一段代碼);
// 創(chuàng)建一個(gè)Shader宅静,返回它的索引
int shader = GLES20.glCreateShader(GL_VERTEX_SHADER);
// 把源碼綁定到這個(gè)Shader
GLES20.glShaderSource(shader, s);
// 編譯源碼
GLES20.glCompileShader(shader);
// 查看是否編譯成功
// compiled裝載是否成功,GL_TRUE或GL_FALSE
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
// 如果編譯失敗站欺,刪除Shader
if(compiled[0] == GL_FALSE) {
    GLES20.glDeleteShader(shader);
    shader = 0;
}elase {  // 如果編譯成功
    // 創(chuàng)建一個(gè)Program
    int program= GLES20.glCreateProgram();
    // 把shader加入Program
    GLES20.glAttachShader(program, shader);
    // 釋放shader資源
    GLES20.glDeleteShader(vertexShader );
    // 鏈接程序
    GLES20.glLinkProgram(program);
    // 獲取program的鏈接情況
    GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
    // 若鏈接失敗則刪除program
    if (linkStatus[0] == GL_FALSE) {
        GLES20.glDeleteProgram(program);
        program = 0;
    } else {    // 如果鏈接成功
        // 使用program
        GLES20.glUseProgram(program);
        // 獲取變量名的id姨夹,location是shader程序中聲明為attribute的變量名
        int id = GLES20.glGetAttribLocation(program, location);
        // 允許shader從VBO讀取這個(gè)變量的值
        GLES20.glEnableVertexAttribArray(id);
        // 設(shè)置索引為0的VBO為傳輸媒介,即APP向這個(gè)VBO寫(xiě)入數(shù)據(jù)矾策,shader從這個(gè)VBO讀取數(shù)據(jù)
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
        // 設(shè)置向VBO寫(xiě)入的數(shù)據(jù)磷账,注意只有在調(diào)用glDrawArrays時(shí)才真正寫(xiě)入
        // size:變量的屬性的數(shù)量,比如vec2類型的變量num = 2贾虽,vec3類型的變量num = 3
        // type:變量的屬性的類型
        // normalized:如果寫(xiě)入的不是type類型的數(shù)據(jù)逃糟,是否要?dú)w一化
        // stride:每個(gè)數(shù)據(jù)的間隔
        // arrayBuffer:寫(xiě)入的數(shù)據(jù)
        GLES20.glVertexAttribPointer(id, size, type, normalized, stride, arrayBuffer);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子绰咽,更是在濱河造成了極大的恐慌菇肃,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件取募,死亡現(xiàn)場(chǎng)離奇詭異琐谤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)玩敏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)斗忌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人旺聚,你說(shuō)我怎么就攤上這事织阳。” “怎么了翻屈?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)妻坝。 經(jīng)常有香客問(wèn)我伸眶,道長(zhǎng),這世上最難降的妖魔是什么刽宪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任厘贼,我火速辦了婚禮,結(jié)果婚禮上圣拄,老公的妹妹穿的比我還像新娘嘴秸。我一直安慰自己,他們只是感情好庇谆,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布岳掐。 她就那樣靜靜地躺著,像睡著了一般饭耳。 火紅的嫁衣襯著肌膚如雪串述。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天寞肖,我揣著相機(jī)與錄音纲酗,去河邊找鬼。 笑死新蟆,一個(gè)胖子當(dāng)著我的面吹牛觅赊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播琼稻,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼吮螺,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起规脸,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤坯约,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后莫鸭,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體闹丐,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年被因,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了卿拴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡梨与,死狀恐怖堕花,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粥鞋,我是刑警寧澤缘挽,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站呻粹,受9級(jí)特大地震影響壕曼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜等浊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一腮郊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧筹燕,春花似錦轧飞、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至制妄,卻和暖如春援奢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背忍捡。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工集漾, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人砸脊。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓具篇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親凌埂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子驱显,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容