多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > android環境下攝像頭數據采集及顯示

android環境下攝像頭數據采集及顯示

來源:程序員人生   發布時間:2015-07-01 08:05:30 閱讀次數:5507次

       之前項目觸及些攝像頭預覽及數據處理操作,當時的需求是除做攝像頭預覽外,還要顯示文字、個性圖象等,當初在查找資料實現相干模塊時,發現很多資料講的比較繁瑣,不夠簡潔,這里將自己的實現方式分享出來,希望能夠為正在做相干工作的同學提供些思路。不過這里先順便提1下,如果單純的做攝像頭預覽,不在預覽數據時做添加文字、圖象等額外操作,可以用surfaceview方式,性能上會更好些。

       這里將攝像頭收集及視頻圖象繪制放在1個模塊中,比較便于管理及保護,同時在使用時,由于該類繼承自view類,所以可以向操作很多view類1樣,將其添加到任何布局中,在與收集的數據寬高比例保持1致的條件下,在頁面顯示上可以非常靈活的控制視圖尺寸大小。不過使用這類方式實現攝像頭預覽,最大的瓶頸是在旋轉yuv數據及將其轉為rgb數據時,計算比較耗時,1般情況下收集640*480數據還好,但對960*720數據來講,手機性能1般的話,就會顯得比較卡了。解決方式在做數據旋轉時,可以嘗試采取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; } } // 繪制 @Override protected 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); } // 獲得攝像頭視頻數據 @Override public void onPreviewFrame(byte[] data, Camera camera) { int i = 0, j = 0, k = 0; int uvHeight = srcFrameHeight >> 1; // 旋轉yuv數據 if (curCameraIndex == CAMERA_BACK) { // 旋轉y for (i = 0; i < srcFrameWidth; i++) { for (j = srcFrameHeight - 1; j >= 0; j--) { yuvdata[k] = data[srcFrameWidth * j + i]; k++; } } // 旋轉uv for (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 { // 旋轉y for (i = srcFrameWidth - 1; i >= 0; i--) { for (j = srcFrameHeight - 1; j >= 0; j--) { yuvdata[k] = data[srcFrameWidth * j + i]; k++; } } // 旋轉uv for (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 }// for invalidate(); } }
工程下載鏈接:http://download.csdn.net/detail/u013085897/8652979




生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 成人影院wwwwwwwwwww | 国产区图片区小说区亚洲区 | 男人天堂亚洲天堂 | 欧美中文日韩 | 伊人久久大香线焦在观看 | 伊人久久大香线蕉 | 国产精品96久久久久久久 | 亚洲 欧美 日韩在线一区 | 国产成人av在线 | 亚洲精品久久久久综合91 | 免费观看wwwwwww | 欧美亚洲另类在线观看 | 美女色哟哟| 国产精品免费久久久久影院 | 性欧美xxx极品另类 性欧美暴力猛交69hd | 色a在线 | jizzjizz大全| 亚洲精品麻豆 | 午夜视频啪啪 | 中文字幕动漫精品专区 | 久久久久性 | 日韩精品一区二区三区中文 | 亚洲伊人久久大香线蕉在观 | 国产精品免费一区二区三区 | 免费能看的黄色网址 | 国产福利免费看 | 动漫日本在线免费观看 | 最近中文字幕高清中文字幕网1 | 亚洲成人自拍网 | 国产成人精品免费视频网页大全 | 偷拍区小说区图片区另类呻吟 | 免费看一级欧美毛片 | 校园春色 亚洲色图 | 婷婷亚洲国产成人精品性色 | 欧美日韩亚洲视频 | 欧美三级久久 | 18视频免费网站 | 精品亚洲欧美高清不卡高清 | 国产91第一页 | 精品伊人久久久大香线蕉欧美 | 最近的免费中文字幕1 |