系统应用篇(三)--Camera篇

目录

一、Camera应用的作用和重要性

二、Camera应用的类型和分类

三、Camera应用的架构和组件

四、Camera应用的定制和扩展

五、学习总结 


一、Camera应用的作用和重要性

相机应用的作用和重要性如下表格所示:

作用 重要性
1. 拍摄照片和录制视频 通过Camera应用,用户可以方便地拍摄照片和录制视频,记录重要时刻、美好回忆或者创作内容。相机功能是手机的基本功能之一,对于用户来说具有重要的实用价值和体验价值。
2. 视频通话和视频聊天 Camera应用也支持视频通话和视频聊天功能,用户可以通过相机进行面对面的远程沟通和交流,提高沟通的效率和质量。尤其在远程工作、远程教育等场景中,视频通话成为必不可少的工具。
3. 计算机视觉和图像处理 Camera应用为计算机视觉和图像处理提供了源数据,这对于开发人员和研究人员来说非常重要。通过相机获取的图像可以进行图像识别、人脸识别、场景分析等多种计算机视觉任务,为各种应用和研究领域提供数据支持。
4. 增强现实和虚拟现实 相机应用在增强现实(AR)和虚拟现实(VR)中扮演着重要的角色。通过相机获取实时图像,结合AR和VR技术,可以实现虚拟物体与真实世界的交互、虚拟场景的展示等,为用户带来身临其境的体验。
5. 多媒体应用 相机应用是多媒体应用的基础组成部分之一,与相册、图库等应用紧密关联。通过相机拍摄的照片和录制的视频可以进行编辑、分享、保存等操作,为用户提供丰富的多媒体体验。

        相机应用的作用和重要性,涵盖了拍摄照片和录制视频、视频通话和视频聊天、计算机视觉和图像处理、增强现实和虚拟现实以及多媒体应用等方面。这些功能使得相机应用在用户日常使用和开发领域中具有重要的地位和作用。


二、Camera应用的类型和分类

相机应用的类型和分类如下表格所示:

类型 描述
1. 原生相机应用 原生相机应用是由设备厂商或操作系统提供的默认相机应用程序。它通常具有基本的拍摄和录制功能,并随设备一同提供。原生相机应用通常具有良好的兼容性和稳定性。
2. 第三方相机应用 第三方相机应用是由独立开发者或公司开发的相机应用程序。它们提供了丰富的功能和定制选项,可以满足不同用户的需求。第三方相机应用通常具有更多的滤镜、特效、手动设置等高级功能。
3. 专业相机应用 专业相机应用是面向摄影爱好者、专业摄影师或摄影专业人士的应用程序。它们提供了更高级的摄影功能和控制选项,例如手动曝光、白平衡、焦距、快门速度等。专业相机应用通常具有更高的图像质量和更精确的控制能力。
4. 社交相机应用 社交相机应用专注于用户之间的分享和互动。它们通常具有内置的社交媒体集成,允许用户轻松地拍摄照片或录制视频,并直接分享到社交平台上。社交相机应用也常常提供滤镜、贴纸、标签等社交化的特性。
5. AR相机应用 AR相机应用结合了增强现实技术和相机功能,可以在相机预览中叠加虚拟物体、场景或效果。它们提供了沉浸式的增强现实体验,允许用户与虚拟内容进行交互、游戏或创作。AR相机应用在娱乐、教育、购物等领域有广泛应用。

        相机应用的不同类型和分类,包括原生相机应用、第三方相机应用、专业相机应用、社交相机应用和AR相机应用。每种类型的相机应用都具有不同的特点和定位,满足了不同用户的需求和使用场景。


三、Camera应用的架构和组件

相机应用的架构和组件如下表格所示:

架构和组件 描述
1. 硬件抽象层(HAL) 相机应用与相机硬件之间的接口层。HAL负责处理底层硬件驱动程序与操作系统之间的通信,提供相机功能的抽象接口,以便上层应用程序能够与不同的相机硬件进行交互。
2. 相机服务(Camera Service) 相机服务是相机应用的核心组件,负责管理相机硬件资源和处理相机功能。它与HAL进行交互,控制相机的打开、关闭、配置和数据传输等操作。相机服务还提供API供上层应用程序调用,实现相机的拍摄、录制、预览等功能。
3. 相机框架(Camera Framework) 相机框架是相机应用的高级组件,提供了更高级别的功能和控制选项。它包括相机API、相机参数设置、图像处理、拍摄模式、拍摄效果等。相机框架通过与相机服务进行交互,实现相机的各种功能和特性。
4. 相机界面(Camera UI) 相机界面是用户与相机应用进行交互的界面部分。它包括预览界面、设置界面、拍摄按钮、拍摄模式切换等。相机界面提供了直观的操作界面,让用户可以调整相机参数、预览图像、拍摄照片或录制视频等。
5. 图像处理引擎 图像处理引擎负责对相机捕获的图像进行处理和优化。它包括图像算法、滤镜、色彩校正、降噪等。图像处理引擎能够提高图像质量、增强细节、改善色彩和对比度等,让拍摄的照片更加出色。

        相机应用的架构和组件,包括硬件抽象层(HAL)、相机服务(Camera Service)、相机框架(Camera Framework)、相机界面(Camera UI)和图像处理引擎。这些组件共同协作,实现了相机应用的功能和特性。


四、Camera应用的定制和扩展

1.以高通的骁龙相机中实际需求为例:

  1. 解决相机拍照后无法存储在SD卡上的问题
  2. 强制有拍照倒计时声音
  3. 解决在相机预览黑屏时按相机键拍照出错的问题
  4. 增加相机在无照片时缩略图显示图库图标的功能
  5. 相机 前摄按键操作拍照 默认焦点不在拍照按钮上
  6. 录像后 切换前后摄按钮焦点异常
  7. 去掉骁龙相机在获取权限失败后的弹窗

2.解决方案:

1.在SDCard.java文件中的getDirectory()方法中设置sd卡的存储路径:

public String getDirectory() {
        if (mVolume == null) {
            return null;
        }
        if (mPath == null) {
            File[] dirs = mContext.getExternalFilesDirs(null);
            if (dirs != null) {
                String dir;
                for (int i=0; i

2. 在values目录下的bool.xml中将force_count_down_sound设置为true:




    false
    
    true
    
    false

3. 在PhotoModule.java中的onKeyDown()方法中的KEYCODE_CAMERA选项中,添加onShutterButtonFocus(true),就可解决该bug:

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_VOLUME_UP:
            case KeyEvent.KEYCODE_VOLUME_DOWN:
                if (CameraUtil.volumeKeyShutterDisable(mActivity)) {
                   return false;
                }
            case KeyEvent.KEYCODE_FOCUS:
                if (/*TODO: mActivity.isInCameraApp() &&*/ mFirstTimeInitialized) {
                    if (event.getRepeatCount() == 0) {
                        onShutterButtonFocus(true);
                    }
                    return true;
                }
                return false;
            case KeyEvent.KEYCODE_CAMERA:
                if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
                    //add begin
                    onShutterButtonFocus(true);
                    //add end
                    onShutterButtonClick();
                }
                return true;
        case KeyEvent.KEYCODE_DPAD_LEFT:
            if ( (mCameraState != PREVIEW_STOPPED) && (mFocusManager != null) &&
                  (mFocusManager.getCurrentFocusState() != mFocusManager.STATE_FOCUSING) &&
                  (mFocusManager.getCurrentFocusState() != mFocusManager.STATE_FOCUSING_SNAP_ON_FINISH) ) {
                if (mbrightness > MINIMUM_BRIGHTNESS) {
                    mbrightness-=mbrightness_step;
                    synchronized (mCameraDevice) {
                        /* Set the "luma-adaptation" parameter */
                        mParameters = mCameraDevice.getParameters();
                        mParameters.set("luma-adaptation", String.valueOf(mbrightness));
                        mCameraDevice.setParameters(mParameters);
                    }
                }
                brightnessProgressBar.setProgress(mbrightness);
                Editor editor = mPreferences.edit();
                editor.putInt(CameraSettings.KEY_BRIGHTNESS, mbrightness);
                editor.apply();
                brightnessProgressBar.setVisibility(View.INVISIBLE);
                mBrightnessVisible = true;
            }
            break;
           case KeyEvent.KEYCODE_DPAD_RIGHT:
            if ( (mCameraState != PREVIEW_STOPPED) && (mFocusManager != null) &&
                  (mFocusManager.getCurrentFocusState() != mFocusManager.STATE_FOCUSING) &&
                  (mFocusManager.getCurrentFocusState() != mFocusManager.STATE_FOCUSING_SNAP_ON_FINISH) ) {
                if (mbrightness < MAXIMUM_BRIGHTNESS) {
                    mbrightness+=mbrightness_step;
                    synchronized (mCameraDevice) {
                        /* Set the "luma-adaptation" parameter */
                        mParameters = mCameraDevice.getParameters();
                        mParameters.set("luma-adaptation", String.valueOf(mbrightness));
                        mCameraDevice.setParameters(mParameters);
                    }
                }
                brightnessProgressBar.setProgress(mbrightness);
                Editor editor = mPreferences.edit();
                editor.putInt(CameraSettings.KEY_BRIGHTNESS, mbrightness);
                editor.apply();
                brightnessProgressBar.setVisibility(View.INVISIBLE);
                mBrightnessVisible = true;
            }
            break;
            case KeyEvent.KEYCODE_DPAD_CENTER:
                // If we get a dpad center event without any focused view, move
                // the focus to the shutter button and press it.
                if (mFirstTimeInitialized && event.getRepeatCount() == 0) {
                    // Start auto-focus immediately to reduce shutter lag. After
                    // the shutter button gets the focus, onShutterButtonFocus()
                    // will be called again but it is fine.
                    onShutterButtonFocus(true);
                    mUI.pressShutterButton();
                }
                return true;
        }
        return false;
    }

4. 在CameraActivity.java中onPostExecute()方法添加该功能:

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if (bitmap == null) {
                //add begin
                mThumbnail = (ImageView) findViewById(R.id.preview_thumb);
                if (mThumbnail != null) {
                    // Clear the image resource when the bitmap is invalid.
                    try {
                        Drawable appIcon = getPackageManager().getActivityIcon(new ComponentName(
                                "com.google.android.apps.photosgo", "com.google.android.apps.photosgo.home.HomeActivity"));
                        mThumbnail.setImageDrawable(appIcon);
                        mThumbnail.setVisibility(View.VISIBLE);
                    } catch (PackageManager.NameNotFoundException e) {
                        mThumbnail.setImageDrawable(null);
                        mThumbnail.setVisibility(View.GONE);
                        e.printStackTrace();
                    }
                //add end
                }
            } else {
                updateThumbnail(bitmap);
            }

            mJpegData = null;
        }

 5.在PhotoModule.java的onShutterButtonFocus()中判断并设置快门按钮的焦点:

    @Override
    public void onShutterButtonFocus(boolean pressed) {
        if (mCameraDevice == null
                || mPaused || mUI.collapseCameraControls()
                || (mCameraState == SNAPSHOT_IN_PROGRESS)
                || (mCameraState == PREVIEW_STOPPED)
                || (null == mFocusManager)) {
            Log.v(TAG, "onShutterButtonFocus error case mCameraState = " + mCameraState
                + "mCameraDevice = " + mCameraDevice + "mPaused =" + mPaused);
            return;
        }

        synchronized(mCameraDevice) {
           if (mCameraState == LONGSHOT) {
               mLongshotActive = false;
               mCameraDevice.setLongshot(false);
               mUI.animateCapture(mLastJpegData);
               mLastJpegData = null;
               if (!mFocusManager.isZslEnabled()) {
                   setupPreview();
               } else {
                   setCameraState(IDLE);
                   mFocusManager.resetTouchFocus();
                   if (CameraUtil.FOCUS_MODE_CONTINUOUS_PICTURE.equals(
                           mFocusManager.getFocusMode())) {
                       mCameraDevice.cancelAutoFocus();
                   }
                   mUI.resumeFaceDetection();
               }
           }
        }

        // Do not do focus if there is not enough storage.
        if (pressed && !canTakePicture()) return;

        if (pressed) {
            mFocusManager.onShutterDown();
        } else {
            // for countdown mode, we need to postpone the shutter release
            // i.e. lock the focus during countdown.
            if (!mUI.isCountingDown()) {
                mFocusManager.onShutterUp();
            }
        }
		    //add begin
			if(PhotoUI.mThumbnail != null)
				PhotoUI.mThumbnail.setFocusable(false);	
					
					
			if(PhotoUI.mMenuButton != null)
				PhotoUI.mMenuButton.setFocusable(false);	
			
			if(PhotoUI.mSwitcher != null)
				PhotoUI.mSwitcher.setFocusable(false);	
			
			if(PhotoUI.mFrontBackSwitcher != null)
				PhotoUI.mFrontBackSwitcher.setFocusable(false);	

			if(PhotoUI.mShutterButton != null){
				PhotoUI.mShutterButton.setFocusedByDefault(true);
				PhotoUI.mShutterButton.setFocusable(true);
				PhotoUI.mShutterButton.setFocusableInTouchMode(true);
				PhotoUI.mShutterButton.requestFocus();
			}		
            //add end
    }

6. 在VideoModule.java中的子线程中设置前后摄按钮的焦点:

    Handler mSetViewFocusHandler = new Handler(){
		public void handleMessage(Message msg) {
			switch (msg.what){
				case  1:		
					if(VideoUI.mThumbnail != null)
						VideoUI.mThumbnail.setFocusable(true);	
					
					if(VideoUI.mPauseButton != null)
						VideoUI.mPauseButton.setFocusable(true);	
					
					if(VideoUI.mMuteButton != null)
						VideoUI.mMuteButton.setFocusable(true);	
					//add begin
					if(VideoUI.mFrontBackSwitcher != null)
						VideoUI.mFrontBackSwitcher.setFocusable(true);	
                    //add end										
					//if(VideoUI.mSurfaceView != null)
					//	VideoUI.mSurfaceView.setFocusable(true);						
					break;
				case 2:
					if(VideoUI.mThumbnail != null)
						VideoUI.mThumbnail.setFocusable(true);	
							
					if(VideoUI.mPauseButton != null)
						VideoUI.mPauseButton.setFocusable(true);	
							
					if(VideoUI.mMuteButton != null)
						VideoUI.mMuteButton.setFocusable(true);	
					//add begin
					if(VideoUI.mFrontBackSwitcher != null)
						VideoUI.mFrontBackSwitcher.setFocusable(true);
                    //add end						
				//	if(VideoUI.mSurfaceView != null)
					//	VideoUI.mSurfaceView.setFocusable(true);	
					if(VideoUI.mMenuButton != null)
						VideoUI.mMenuButton.setFocusable(true);
					
					if(VideoUI.mSwitcher != null)
						VideoUI.mSwitcher.setFocusable(true);	
					break;				
					
				default:
					break;
			}
		};

	};

7. 在PermissionsActivity.java中的onRequestPermissionsResult()将获取权限失败后的弹窗给finish()掉:

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {

        if (mShouldRequestCameraPermission) {
            if ((grantResults.length >= mIndexPermissionRequestCamera + 1) &&
                (grantResults[mIndexPermissionRequestCamera] ==
                        PackageManager.PERMISSION_GRANTED)) {
                mFlagHasCameraPermission = true;
            } else {
                mCriticalPermissionDenied = true;
            }
        }
        if (mShouldRequestMicrophonePermission) {
            if ((grantResults.length >= mIndexPermissionRequestMicrophone + 1) &&
                (grantResults[mIndexPermissionRequestMicrophone] ==
                        PackageManager.PERMISSION_GRANTED)) {
                mFlagHasMicrophonePermission = true;
            } else {
                mCriticalPermissionDenied = true;
            }
        }
        if (mShouldRequestStoragePermission) {
            if ((grantResults.length >= mIndexPermissionRequestStorageRead + 1) &&
                (grantResults[mIndexPermissionRequestStorageWrite] ==
                        PackageManager.PERMISSION_GRANTED) &&
                    (grantResults[mIndexPermissionRequestStorageRead] ==
                            PackageManager.PERMISSION_GRANTED)) {
                mFlagHasStoragePermission = true;
            } else {
                mCriticalPermissionDenied = true;
            }
        }

        if (mShouldRequestLocationPermission) {
            if ((grantResults.length >= mIndexPermissionRequestLocation + 1) &&
                (grantResults[mIndexPermissionRequestLocation] ==
                        PackageManager.PERMISSION_GRANTED)) {
                // Do nothing
            } else {
                // Do nothing
            }
        }

        if (mFlagHasCameraPermission && mFlagHasMicrophonePermission &&
                mFlagHasStoragePermission) {
            handlePermissionsSuccess();
        } else if (mCriticalPermissionDenied) {
//            modify begin
//            handlePermissionsFailure();
            finish();
            //modify end
        }
    }

五、学习总结

参考了Google API中关于Camera的介绍

要访问摄像头,使用相机和自动对焦功能,则清单文件里应包括以下内容: 



1.拍照流程要使用到以下的类并且按步骤进行:

  1. 从open(int)获取摄像头的实例;
  2. 使用getParameters()来获取默认的设置;
  3. 如果有必要,可调用setParameters(Camera.Parameters)来修改返回的对象;
  4. 调用setDisplayOrientation(int)以确保预览的正确方向;
  5. 【重要事项】:传递完全初始化的SurfaceHolder给setPreviewDisplay(SurfaceHolder)。如果没有surface, 相机将无法开始预览;
  6. 【重要事项】:调用startPreview()以开始更新预览图面。必须先开始预览,然后才能拍照;
  7. 当需要时,可调用takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)用来拍摄照片。等待回调提供实际图像数据;
  8. 拍照后,预览显示将停止。需要拍摄更多照片时,要再次调用startPreview();
  9. 调用stopPreview()来停止更新预览图面;
  10. 【重要事项】:调用 release() 以释放相机以供其他应用程序使用。应用程序应立即在 android.app.Activity.onPause()中释放相机(并在android.app.Activity.onResume()中re-open())。 

2.视频录制模式的相关步骤:

  1. 获取并初始化相机并按照拍照流程开始预览取景;
  2. 调用unlock()去允许媒体进程访问摄像机;
  3. 将相机传递到 android.media.MediaRecorder.setCamera(Camera);
  4. 录制完成后,调用reconnect()去重新获得并重新锁定相机;
  5. 如果有需要,重新启动预览并拍摄更多照片或视频;
  6. 最后一步要像拍照步骤流程一样调用 stopPreview()和release() 来停止预览和释放相机。

本文仅代表个人观点和经验,难免存在不足之处。如果有任何错误或改进的建议,欢迎指正和交流,共同进步。

你可能感兴趣的:(android基础,Java基础,数码相机,android,java)