android環境下網路攝影機資料擷取及顯示,android資料擷取
以前項目涉及些網路攝影機預覽及資料處理操作,當時的需求是除了做網路攝影機預覽外,還要顯示文字、個性映像等,當初在尋找資料實現相關模組時,發現很多資料講的比較繁瑣,不夠簡潔,這裡將自己的實現方式分享出來,希望能夠為正在做相關工作的同學提供些思路。不過這裡先順便提一下,如果單純的做網路攝影機預覽,不在預覽資料時做添加文字、映像等額外操作,可以用surfaceview方式,效能上會更好些。
這裡將網路攝影機採集及視頻映像繪製放在一個模組中,比較便於管理及維護,同時在使用時,因為該類繼承自view類,所以可以向操作很多view類一樣,將其添加到任何布局中,在與採集的資料寬高比例保持一致的前提下,在頁面顯示上可以非常靈活的控制視圖尺寸大小。不過使用這種方式實現網路攝影機預覽,最大的瓶頸是在旋轉yuv資料及將其轉為rgb資料時,計算比較耗時,一般情況下採集640*480資料還好,但對於960*720資料來說,手機效能一般的話,就會顯得比較卡了。解決方式在做資料旋轉時,可以嘗試採用ndk c的方式,以提高運行效率,在做yuv轉rgb時,也可以嘗試用ndk c的方式,但是最好的方式是採用gpu shader方式,直接渲染yuv資料,即將採集的yuv資料以紋理的方式上傳至gpu,然後由gpu完成yuv轉rgb並顯示。下面是相關代碼:
public class CameraView extends View implements PreviewCallback{// 源視訊框架寬/高private int srcFrameWidth = 640;private int srcFrameHeight = 480;private int frameSize = srcFrameWidth * srcFrameHeight;private int qtrFrameSize = srcFrameWidth * srcFrameHeight >> 2;// 幀預覽貼圖private Bitmap previewBmp = null;private Rect previewRect = null;private Camera camera = null;// 圖層private BaseLayer[] layers = null;// 資料擷取private int[] rgb_data = null;private byte[] yuvdata = null;// 網路攝影機前置/後置public static final int CAMERA_BACK = 0;public static final int CAMERA_FRONT = 1;private int curCameraIndex = CAMERA_BACK;public CameraView(Context _context){super(_context);}public CameraView(Context _context, AttributeSet _attrs){super(_context, _attrs);}public CameraView(Context context, int previewWidth, int previewHeight, int cameraIndex){super(context);curCameraIndex = cameraIndex;rgb_data = new int[frameSize];yuvdata = new byte[frameSize * 3 / 2];previewBmp = Bitmap.createBitmap(srcFrameHeight, srcFrameWidth, Config.ARGB_8888);previewRect = new Rect(0, 0, previewWidth, previewHeight);// 定義圖層layers = new BaseLayer[2];layers[0] = new TextLayer(context, 0, false);layers[1] = new ImageLayer(context, 1, false);// 文字((TextLayer)layers[0]).setFontParams(32, Color.CYAN);((TextLayer)layers[0]).setTextPos(100, 300);((TextLayer)layers[0]).setContent("天氣還不錯....");layers[0].setVisible(true);// 映像((ImageLayer)layers[1]).setImagePos(100, 150);layers[1].setVisible(true);// 初始化並開啟網路攝影機startCamera(cameraIndex);this.setBackgroundColor(Color.parseColor("#82858b"));}// 根據索引初始化網路攝影機public void startCamera(int cameraIndex){// 先停止網路攝影機stopCamera();// 再初始化並開啟網路攝影機if (camera == null){camera = Camera.open(cameraIndex);Camera.Parameters params = camera.getParameters();params.setPreviewSize(srcFrameWidth, srcFrameHeight);params.setPreviewFormat(ImageFormat.NV21);camera.setParameters(params);camera.setPreviewCallback(this);camera.startPreview();}}// 停止並釋放網路攝影機public void stopCamera(){if (camera != null){camera.setPreviewCallback(null);camera.stopPreview();camera.release();camera = null;}}// 繪製@Overrideprotected void onDraw(Canvas canvas){super.onDraw(canvas);// 填充資料(因為資料已經旋轉過,此時寬與高需要互換)previewBmp.setPixels(rgb_data, 0, srcFrameHeight, 0, 0, srcFrameHeight, srcFrameWidth);// 繪製圖層for (BaseLayer layer : layers){if (layer.isVisible()){layer.drawLayer(previewBmp);}}// 貼圖canvas.drawBitmap(previewBmp, null, previewRect, null);}// 擷取網路攝影機視頻資料@Overridepublic void onPreviewFrame(byte[] data, Camera camera){int i = 0, j = 0, k = 0;int uvHeight = srcFrameHeight >> 1;// 旋轉yuv資料if (curCameraIndex == CAMERA_BACK){// 旋轉yfor (i = 0; i < srcFrameWidth; i++){for (j = srcFrameHeight - 1; j >= 0; j--){yuvdata[k] = data[srcFrameWidth * j + i];k++;}}// 旋轉uvfor (i = 0; i < srcFrameWidth; i += 2){ for (j = uvHeight - 1; j >= 0; j--) { yuvdata[k] = data[frameSize + srcFrameWidth * j + i + 1];// cb/u yuvdata[k + qtrFrameSize] = data[frameSize + srcFrameWidth * j + i];// cr/v k++; }}}else{// 旋轉yfor (i = srcFrameWidth - 1; i >= 0; i--){for (j = srcFrameHeight - 1; j >= 0; j--){yuvdata[k] = data[srcFrameWidth * j + i];k++;}}// 旋轉uvfor (i = srcFrameWidth - 2; i >= 0; i -= 2){ for (j = uvHeight - 1; j >= 0; j--) { yuvdata[k] = data[frameSize + srcFrameWidth * j + i + 1];// cb/u yuvdata[k + qtrFrameSize] = data[frameSize + srcFrameWidth * j + i];// cr/v k++; }}}// yuv轉rgb(因為資料已經旋轉過,此時寬與高需要互換)int yp = 0;for (i = 0, yp = 0; i < srcFrameWidth; i++){int uvp = frameSize + (i >> 1) * uvHeight, u = 0, v = 0;for (j = 0; j < srcFrameHeight; j++, yp++){int y = (0xff & yuvdata[yp]) - 16;if ((j & 1) == 0){u = (0xff & yuvdata[uvp + (j>>1)]) - 128;v = (0xff & yuvdata[uvp + qtrFrameSize + (j>>1)]) - 128;}int y1192 = 1192 * y;int r = (y1192 + 1634 * v);int g = (y1192 - 833 * v - 400 * u);int b = (y1192 + 2066 * u);if (r < 0) r = 0; else if (r > 262143) r = 262143;if (g < 0) g = 0; else if (g > 262143) g = 262143;if (b < 0) b = 0; else if (b > 262143) b = 262143;rgb_data[i*srcFrameHeight + j] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);}// for}// forinvalidate();}}工程下載連結:http://download.csdn.net/detail/u013085897/8652979