Android openh264 編解碼重點記錄
阿新 • • 發佈:2019-01-05
編譯工具:CYGWIN
只要進入到openh264根目錄 就能夠直接根據github提供的編譯步驟進行編譯,之後會獲得openh264相關的動態和靜態庫.我的openh264是15年8月下載的 下載地址編碼部分:
1 從android獲取攝像頭資料使用的格式是NV21(yuv420sp),由於手機拍攝預設是橫屏,所以獲取到資料需要將資料進行旋轉(是否有更好的方式處理 之後再研究). 順時針旋轉90°,從stackoverflow上找的注意:旋轉之後的寬高在放進去編碼時需要調換過來,不然等到後面解碼出來會出現顯示的長寬反了 2 openh264編碼資料只接收yuv i420(yuv420p)資料(別的暫時還沒試),所以在這裡進行了YUV420SP轉YUV420P的步驟,程式碼如下:private byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight) { byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2]; // Rotate the Y luma int i = 0; for (int x = 0; x < imageWidth; x++) { for (int y = imageHeight - 1; y >= 0; y--) { yuv[i] = data[y * imageWidth + x]; i++; } } // Rotate the U and V color components i = imageWidth * imageHeight * 3 / 2 - 1; for (int x = imageWidth - 1; x > 0; x = x - 2) { for (int y = 0; y < imageHeight / 2; y++) { yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x]; i--; yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + (x - 1)]; i--; } } return yuv; }
這樣就能編碼了public byte[] nv21ToI420(byte[] yuv420sp, int width, int height) { int framesize = width * height; byte[] yuv420 = new byte[framesize * 3 / 2]; int i = 0, j = 0; // copy y for (i = 0; i < framesize; i++) { yuv420[i] = yuv420sp[i]; } i = 0; for (j = 0; j < framesize / 2; j += 2) { yuv420[i + framesize] = yuv420sp[j + framesize]; yuv420[i + framesize * 5 / 4] = yuv420sp[j + 1 + framesize]; i++; } return yuv420; }
解碼部分
1 使用官方提供的編解碼步驟,解碼出來的資料重點,需要將Y、U、V三部分進行組合成一個YUV420資料2 之後將這個YUV資料進行轉換成ARGB以便Android顯示unsigned char* buf = new unsigned char[m_iWidth * m_iHeight * 3 / 2]; int a = 0; for (int i = 0; i < m_iHeight; i++) { memcpy(buf + a, data[0] + i * bufInfo.UsrData.sSystemBuffer.iStride[0], m_iWidth); a += m_iWidth; } for (int i = 0; i < m_iHeight / 2; i++) { memcpy(buf + a, data[1] + i * bufInfo.UsrData.sSystemBuffer.iStride[1], m_iWidth / 2); a += m_iWidth / 2; } for (int i = 0; i < m_iHeight / 2; i++) { memcpy(buf + a, data[2] + i * bufInfo.UsrData.sSystemBuffer.iStride[1], m_iWidth / 2); a += m_iWidth / 2; }
jbyte* yuv420p = reinterpret_cast<jbyte*>(buf);
jint* rgb = new jint[frameSize];
int i = 0, j = 0, yp = 0;
int up = 0, vp = 0, u = 0, v = 0;
for (j = 0, yp = 0; j < m_iHeight; j++) {
up = frameSize + (j >> 2) * m_iWidth;
vp = frameSize * 5 / 4 + (j >> 2) * m_iWidth;
u = 0;
v = 0;
for (i = 0; i < m_iWidth; i++, yp++) {
int y = (0xff & ((int) yuv420p[yp]));
if (y < 0)
y = 0;
if ((i & 1) == 0) {
u = (0xff & yuv420p[up++]);
v = (0xff & yuv420p[vp++]);
}
int y1192 = y_table[y];
int r = r_yv_table[y][u];
int g = (y1192 - g_v_table[u] - g_u_table[v]);
int b = b_yu_table[y][v];
if (g < 0)
g = 0;
else if (g > 262143)
g = 262143;
rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000)
| ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
}
}
env->SetIntArrayRegion(result, 0, frameSize, rgb);
delete[] rgb;
這段程式碼由網上找來的,稍微修改,改成I420轉ARGB
解碼出來之後就可以到Android顯示了,顯示用的是opengl,程式碼太多就不放出來了,網上很多。
============================================================================================ 2016-5-18 yuv的顯示直接用opengl顯示了,而不必轉成rgb再去顯示了 ============================================================================================ 2016-10-21 一段時間沒時間去研究視訊顯示,現在要用的時候發現一個問題:前置攝像頭和後置攝像頭的視訊排版不一樣 前置攝像頭和後置攝像頭區別
1.preview輸出的data資料: 以橫屏為標準 前置攝像頭是反方想的,即正上方向右,後置攝像頭和視訊顯示出來的影象是正的 即正上方向左
2.旋轉的時候就需要注意:
後置攝像頭是正常旋轉,前置攝像頭需要左右調換再旋轉
ps:記住前置攝像頭是相反的 3 前置攝像頭和後置攝像頭區別
1.preview輸出的data資料:
前置攝像頭是反方想的,即正上方向右,後置攝像頭和視訊顯示出來的影象是正的 即正上方向左
2.旋轉的時候就需要注意:
後置攝像頭是正常旋轉,前置攝像頭需要左右調換再旋轉
3.yuv顏色顯示:
後置攝像頭正常Y-U-V 而前置攝像頭是Y-V-U