Camera2+GLsurfaceview+shader 攝像頭預(yù)覽實(shí)現(xiàn)以及shader濾鏡實(shí)現(xiàn)

一、Camera2的大致了解:
①凛剥、 CameraManager:作為整個(gè)框架的入口侠仇,用于初始化其他類;
②犁珠、CameraCharacteristics:通過(guò)CameraManager獲得逻炊,可提供Camera相關(guān)參數(shù);
③犁享、CameraDevice:通過(guò)CameraManager獲得余素,類似之前的Camera類,可以進(jìn)行預(yù)覽等操作炊昆,例如:設(shè)置顯示預(yù)覽的Surface桨吊。
④、CaptureRequest.Builder:通過(guò)CameraDevice獲得凤巨,可以設(shè)置預(yù)覽的相關(guān)配置视乐。
⑤、CameraCaptureSession:通過(guò)CameraDevice獲得敢茁,控制通過(guò)CaptureRequest.Builder進(jìn)行預(yù)覽佑淀。
使用流程:
CameraManager -> CameraDevice -> CaptureRequest.Builder-> CameraCaptureSession
(原文鏈接:https://blog.csdn.net/ccw0054/article/details/80339208
下面是對(duì)代碼的分析:
官方代碼:https://github.com/android/camera-samples
以下是一個(gè)demo的代碼:

private void openCamera(int width, int height) {
        if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            requestCameraPermission();
            return;
        }
        setUpCameraOutputs(width, height);
        Log.d("PCC","setup test");
        Activity activity = getActivity();
        CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
        try {
            if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
                throw new RuntimeException("Time out waiting to lock camera opening.");
            }

            Log.d("111","cameraid"+mCameraId);
            manager.openCamera("0", mStateCallback, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
        }
    }
private void setUpCameraOutputs(int width, int height) {
        Activity activity = getActivity();
        CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
        try {
            for (String cameraId : manager.getCameraIdList()) {
                Log.d("PC1",cameraId);
                CameraCharacteristics characteristics
                        = manager.getCameraCharacteristics(cameraId);

                // We don't use a front facing camera in this sample.
                Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
                if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
                    continue;
                }

                StreamConfigurationMap map = characteristics.get(
                        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                if (map == null) {
                    continue;
                }

                // For still image captures, we use the largest available size.
                Size largest = Collections.max(
                        Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
                        new CompareSizesByArea());
                // Find out if we need to swap dimension to get the preview size relative to sensor
                // coordinate.
                int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
                //noinspection ConstantConditions
                mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
                boolean swappedDimensions = false;
                Log.d("PC3",cameraId);
                switch (displayRotation) {
                    case Surface.ROTATION_0:
                    case Surface.ROTATION_180:
                        if (mSensorOrientation == 90 || mSensorOrientation == 270) {
                            swappedDimensions = true;
                        }
                        break;
                    case Surface.ROTATION_90:
                    case Surface.ROTATION_270:
                        if (mSensorOrientation == 0 || mSensorOrientation == 180) {
                            swappedDimensions = true;
                        }
                        break;
                    default:
                        Log.e(TAG, "Display rotation is invalid: " + displayRotation);
                }
                Point displaySize = new Point();
                activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
                int rotatedPreviewWidth = width;
                int rotatedPreviewHeight = height;
                int maxPreviewWidth = displaySize.x;
                int maxPreviewHeight = displaySize.y;

                if (swappedDimensions) {
                    rotatedPreviewWidth = height;
                    rotatedPreviewHeight = width;
                    maxPreviewWidth = displaySize.y;
                    maxPreviewHeight = displaySize.x;
                }

                if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
                    maxPreviewWidth = MAX_PREVIEW_WIDTH;
                }

                if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
                    maxPreviewHeight = MAX_PREVIEW_HEIGHT;
                }
                // Danger, W.R.! Attempting to use too large a preview size could exceed the camera
                // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
                // garbage capture data.
                mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
                        rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
                        maxPreviewHeight, largest);
                // We fit the aspect ratio of TextureView to the size of preview we picked.
                int orientation = getResources().getConfiguration().orientation;
                if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
                    autoFitTextureView.setAspectRatio(
                            mPreviewSize.getWidth(), mPreviewSize.getHeight());
                } else {
                    autoFitTextureView.setAspectRatio(
                            mPreviewSize.getHeight(), mPreviewSize.getWidth());
                }
                // Check if the flash is supported.
                Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
                mFlashSupported = available == null ? false : available;
                mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
                        ImageFormat.YUV_420_888, /*maxImages*/5);

                mCameraId = cameraId;
                return;
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            // Currently an NPE is thrown when the Camera2API is used but not supported on the
            // device this code runs.
            ErrorDialog.newInstance(getString(R.string.camera_error))
                    .show(getChildFragmentManager(), FRAGMENT_DIALOG);
        }
    }
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {

        @Override
        public void onOpened(@NonNull CameraDevice cameraDevice) {
            // This method is called when the camera is opened. We start camera preview here.
            mCameraOpenCloseLock.release();
            mCameraDevice = cameraDevice;
            //createCameraPreviewSession();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
            mCameraOpenCloseLock.release();
            cameraDevice.close();
            mCameraDevice = null;
        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int error) {
            mCameraOpenCloseLock.release();
            cameraDevice.close();
            mCameraDevice = null;
            Activity activity = getActivity();
            if (null != activity) {
                activity.finish();
            }
        }

    };
private void createCameraPreviewSession() {
        try {
            mSurfaceTexture.setDefaultBufferSize(MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT);
            Surface surface = new Surface(mSurfaceTexture);
            // This is the output Surface we need to start preview.
            // We set up a CaptureRequest.Builder with the output Surface.
            mPreviewRequestBuilder
                    = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mPreviewRequestBuilder.addTarget(surface);
            //mPreviewRequestBuilder.addTarget(mImageReader.getSurface());

            // Here, we create a CameraCaptureSession for camera preview.
            mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                    new CameraCaptureSession.StateCallback() {

                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                            // The camera is already closed
                            if (null == mCameraDevice) {
                                return;
                            }
                            // When the session is ready, we start displaying the preview.
                            mCaptureSession = cameraCaptureSession;
                            // Auto focus should be continuous for camera preview.
                            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                            // Flash is automatically enabled when necessary.
                            setAutoFlash(mPreviewRequestBuilder);
                            // Finally, we start displaying the camera preview.
                            mPreviewRequest = mPreviewRequestBuilder.build();
                            try {
                                mCaptureSession.setRepeatingRequest(mPreviewRequest,
                                        null, mBackgroundHandler);
                            } catch (CameraAccessException e) {
                                e.printStackTrace();
                            }
                        }

                        @Override
                        public void onConfigureFailed(
                                @NonNull CameraCaptureSession cameraCaptureSession) {
                            showToast("Failed");
                        }
                    }, mBackgroundHandler
            );
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

代碼中我們可以看到openCamera這個(gè)函數(shù)首先會(huì)設(shè)置一個(gè)輸出的大小以使得我們camera得到的data不被拉伸以至于造成變形,然后會(huì) CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);獲取camera的服務(wù)以啟動(dòng)manager.openCamera("0", mStateCallback, mBackgroundHandler)彰檬,這里的mStateCallback就對(duì)應(yīng)device回調(diào)的一個(gè)狀態(tài)伸刃,也是camera2特有的一個(gè)特性,告訴我們攝像頭的狀態(tài)逢倍。camera open之后我們需要?jiǎng)?chuàng)建一個(gè)createCameraPreviewSession活動(dòng)奕枝,在這個(gè)函數(shù)我們創(chuàng)建的surfacetexture與紋理ID進(jìn)行綁定,同時(shí)與mPreviewRequestBuilder進(jìn)行通信瓶堕,使得我們可以正常顯示預(yù)覽數(shù)據(jù)隘道。
二、GLsurfaceview的大致了解:
GLsurfaceview作為surfaceview的補(bǔ)充,加入了EGL的管理(個(gè)人理解:極大的提供了一個(gè)接口谭梗,讓我們方便的使用Opengl ES)忘晤,一提到GLsurfaceview首先會(huì)想到render,在render中往往存在以下代碼:

 private GLSurfaceView.Renderer renderer=new GLSurfaceView.Renderer() {
        @Override
        public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
          
       }
        @Override
        public void onSurfaceChanged(GL10 gl10, int width, int height) {
           
        }

        @Override
        public void onDrawFrame(GL10 gl10) {
          
        }
    };

render中分為onSurfaceCreated激捏、onSurfaceChanged和onDrawFrame三大塊设塔,onSurfaceCreated中我們常常會(huì)創(chuàng)建一個(gè)紋理坐標(biāo)和頂點(diǎn)坐標(biāo),而紋理中我們會(huì)使用一個(gè)紋理ID去綁定我們的surfaceTexture远舅,這樣就可以將紋理加載到我們的view中闰蛔,而頂點(diǎn)坐標(biāo)常常是用來(lái)確定頂點(diǎn)的顏色,以及坐標(biāo)的對(duì)應(yīng)图柏。通過(guò)紋理我們可以獲取到一個(gè)對(duì)象序六,通過(guò)頂點(diǎn)我們可以將我們的對(duì)象按照不同需求繪制出來(lái)!在做預(yù)覽的時(shí)候蚤吹,首先需要打開(kāi)攝像頭例诀,也就是一中的 openCamera函數(shù),接著我們會(huì)創(chuàng)建一個(gè)紋理對(duì)象(ID)裁着,創(chuàng)建好之后需要我們加載紋理坐標(biāo)和頂點(diǎn)坐標(biāo)繁涂,加載頂點(diǎn)時(shí)候,我們可以更改著色代碼二驰,對(duì)像素進(jìn)行操作扔罪,這些著色語(yǔ)言位于raw文件下,其中包含demo所寫的三種濾鏡的實(shí)現(xiàn)桶雀。
二值:

binary.png

邊緣:
edge.png

9分屏:
shared9.png

github代碼:https://github.com/Frank1481906280/GlCV4Android

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末矿酵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子背犯,更是在濱河造成了極大的恐慌坏瘩,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漠魏,死亡現(xiàn)場(chǎng)離奇詭異倔矾,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)柱锹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門哪自,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人禁熏,你說(shuō)我怎么就攤上這事壤巷。” “怎么了瞧毙?”我有些...
    開(kāi)封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵胧华,是天一觀的道長(zhǎng)寄症。 經(jīng)常有香客問(wèn)我,道長(zhǎng)矩动,這世上最難降的妖魔是什么有巧? 我笑而不...
    開(kāi)封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮悲没,結(jié)果婚禮上篮迎,老公的妹妹穿的比我還像新娘。我一直安慰自己示姿,他們只是感情好甜橱,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著栈戳,像睡著了一般岂傲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荧琼,一...
    開(kāi)封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天譬胎,我揣著相機(jī)與錄音差牛,去河邊找鬼命锄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛偏化,可吹牛的內(nèi)容都是我干的脐恩。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼侦讨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼驶冒!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起韵卤,我...
    開(kāi)封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤骗污,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后沈条,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體需忿,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年蜡歹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了屋厘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡月而,死狀恐怖汗洒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情父款,我是刑警寧澤溢谤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布瞻凤,位于F島的核電站,受9級(jí)特大地震影響世杀,放射性物質(zhì)發(fā)生泄漏鲫构。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一玫坛、第九天 我趴在偏房一處隱蔽的房頂上張望结笨。 院中可真熱鬧,春花似錦湿镀、人聲如沸炕吸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)赫模。三九已至,卻和暖如春蒸矛,著一層夾襖步出監(jiān)牢的瞬間瀑罗,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工雏掠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斩祭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓乡话,卻偏偏與公主長(zhǎng)得像摧玫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绑青,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345