android camera之nv21旋轉

來源:互聯網
上載者:User

標籤:xss   vfs   擷取   amr   nal   err   aar   oom   提取   

這周做的一個android的camera開發,需要擷取到視訊框架資料,並且需要是nv21格式的byte數組,並且視訊框架的映像需要是正方向的。和android相機打過交道的都清楚,android的camera擷取到的圖片都是橫向的,因此,需要進行旋轉,對於映像的旋轉,其實bitmap這個類已經可以幫我們實現了,但是前提是你需要將你的資料格式轉換為Bitmap才行,但是我們如果通過setPreviewCallback來擷取視訊框架,擷取到的圖片都是nv21,如果裝換為bitmap後,又很難的轉換為nv21格式的資料。因此則需要面臨一個問題,如歌旋轉nv21格式的byte數組,首先先來講下nv21格式,講到nv21就也要說說yuv240和nv12:

NV12、NV21(屬於YUV420)

NV12和NV21屬於YUV420格式,是一種two-plane模式,即Y和UV分為兩個Plane,但是UV(CbCr)為交錯儲存,而不是分為三個plane。其提取方式與上一種類似,即Y‘00、Y‘01、Y‘10、Y‘11共用Cr00、Cb00

YUV420 planar資料存放區, 以720×488大小圖象YUV420 planar為例,

其儲存格式是: 共大小為(720×480×3>>1)位元組,

分為三個部分: Y分量:       (720×480)個位元組   U(Cb)分量:  (720×480>>2)個位元組     V(Cr)分量:   (720×480>>2)個位元組

三個部分內部均是行優先儲存,三個部分之間是Y,U,V 順序儲存。

即YUV資料的0--720×480位元組是Y分量值,    720×480--720×480×5/4位元組是U分量    720×480×5/4 --720×480×3/2位元組是V分量。

4 :2: 2 和4:2:0 轉換:

最簡單的方式:

YUV4:2:2 ---> YUV4:2:0  Y不變,將U和V訊號值在行(垂直方向)在進行一次隔行抽樣。 YUV4:2:0 ---> YUV4:2:2  Y不變,將U和V訊號值的每一行分別拷貝一份形成連續兩行資料。

在YUV420中,一個像素點對應一個Y,一個4X4的小方塊對應一個U和V。對於所有 YUV420映像,它們的Y值排列是完全相同的,因為只有Y的映像就是灰階映像。YUV420sp與YUV420p的資料格式它們的UV排列在原理上是完 全不同的。420p它是先把U存放完後,再存放V,也就是說UV它們是連續的。而420sp它是UV、UV這樣交替存放的。(見) 有了上面的理論,我就可以準確的計算出一個YUV420在記憶體中存放的大小。 width * hight =Y(總和) U = Y / 4   V = Y / 4

所以YUV420 資料在記憶體中的長度是 width * hight * 3 / 2,

 

假設一個解析度為8X4的YUV映像,它們的格式如:

圖:YUV420sp格式

 

圖:YUV420p資料格式如

具體的旋轉代碼如下:

public static byte[] rotateYUV420Degree90(byte[] data, int imageWidth, int imageHeight) {    byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2];    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++;        }    }    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;}private static byte[] rotateYUV420Degree180(byte[] data, int imageWidth, int imageHeight) {    byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2];    int i = 0;    int count = 0;    for (i = imageWidth * imageHeight - 1; i >= 0; i--) {        yuv[count] = data[i];        count++;    }    i = imageWidth * imageHeight * 3 / 2 - 1;    for (i = imageWidth * imageHeight * 3 / 2 - 1; i >= imageWidth            * imageHeight; i -= 2) {        yuv[count++] = data[i - 1];        yuv[count++] = data[i];    }    return yuv;}public static byte[] rotateYUV420Degree270(byte[] data, int imageWidth,                                     int imageHeight) {    byte[] yuv = new byte[imageWidth * imageHeight * 3 / 2];    int nWidth = 0, nHeight = 0;    int wh = 0;    int uvHeight = 0;    if (imageWidth != nWidth || imageHeight != nHeight) {        nWidth = imageWidth;        nHeight = imageHeight;        wh = imageWidth * imageHeight;        uvHeight = imageHeight >> 1;// uvHeight = height / 2    }    int k = 0;    for (int i = 0; i < imageWidth; i++) {        int nPos = 0;        for (int j = 0; j < imageHeight; j++) {            yuv[k] = data[nPos + i];            k++;            nPos += imageWidth;        }    }    for (int i = 0; i < imageWidth; i += 2) {        int nPos = wh;        for (int j = 0; j < uvHeight; j++) {            yuv[k] = data[nPos + i];            yuv[k + 1] = data[nPos + i + 1];            k += 2;            nPos += imageWidth;        }    }    return rotateYuv420Degree180(rotateYuv420Degree90(data, imageWidth, imageHeight), imageWidth, imageHeight);}

然後,如果你想要查看旋轉後的映像,則通過以下代碼即可:

YuvImage yuvimage = new YuvImage(                  data,                  ImageFormat.NV21,                  width,                  height,                  null);          baos = new ByteArrayOutputStream();          yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, baos);// 80--JPG圖片的品質[0-100],100最高          rawImage = baos.toByteArray();          //將rawImage轉換成bitmap          BitmapFactory.Options options = new BitmapFactory.Options();          options.inPreferredConfig = Bitmap.Config.RGB_565;          bitmap = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length, options);  

在這裡邊我們需要注意的是我們的寬和高,需要用轉移後的,不可使用轉移前的,否則會出現看到的圖片有重影的現象。  

  

android camera之nv21旋轉

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.