Android 13.0 MTK Camera2 设置默认拍照尺寸功能实现

Android 13.0 MTK Camera2 设置默认拍照尺寸功能实现


需求:

默认相机拍照尺寸

需求原因
1)客户自身喜好
2)部分客户自己的摄像头不兼容,比如拍照尺寸太大会卡顿,拉丝等现象

在这里插入图片描述

参考资料

Android 13.0 MTK Camera2 设置默认拍照尺寸功能实现
Android 11.0 MTK Camera2 设置默认拍照尺寸功能实现

这两篇文章介绍的蛮好的,可以看看,对于类似需求同理也可以按照改一改? 为什么有些会默认最高分辨率拍照,可能原因在于手机端产品为了最好的拍摄效果,尺寸会默认到最大。

对于Camera2 开发,遇到的困难点就是源码代码量太多,对于很多同事来说就是一脸懵逼,建议多积累一定的代码量,掌握基本的知识。

架构图了解

MTKCamera2相机架构
Camera2架构
Android Camera架构简析

Camera相关专栏

Camera Framework 专栏
小驰私房菜系列
小驰私房菜MTK系列
小驰Camera 开发系列
Camera 相机开发
展讯平台 Camera
官方文档:谷歌官方 API 描述

零散知识了解

MTK 相机UI介绍
Camera2 相机认知
Camera2学习笔记
camera2关于拍照预览方向旋转90度和拍照图片镜像功能实现
Camera2 预览集成、简单拍照:熟悉预览步骤流程比较有用
Camera镜像上下左右颠倒问题的解决办法
MTK相机成像质量差
Camera应用分析

部分相机源码参考,学习API使用,梳理流程,偏应用层

极客相机 Camera2 API
Camera2 API详解
极客相机源码
Camera2 相机Demo
Camera2 专业相机Demo
拍照、预览、录像Demo
使用Camera2 拍照

Camera2 系统相关

Camera2 Service 启动

修改文件-修改方案

修改文件:

\vendor\mediatek\proprietary\packages\apps\Camera2\feature\setting\picturesize\src\com\mediatek\camera\feature\setting\picturesize\PictureSize.java

\vendor\mediatek\proprietary\packages\apps\Camera2\feature\setting\picturesize\src\com\mediatek\camera\feature\setting\picturesize\PictureSizeHelper.java

修改内容:

PictureSize.java onValueInitialized 方法

在 onValueInitialized 方法中,默认valueInStore 中调用PictureSizeHelper 类中自定义的 getCustomDefault 方法

         if (valueInStore == null) {
             // Default picture size is the max full-ratio size.
-            List<String> entryValues = getEntryValues();
+                       LogHelper.d(TAG, "valueInStore == null  Default picture size is the max full-ratio size:");
+            /*List<String> entryValues = getEntryValues();
             for (String value : entryValues) {
                 if (PictureSizeHelper.getStandardAspectRatio(value) == fullRatio) {
                     valueInStore = value;
+                                       LogHelper.d(TAG, "valueInStore == null:valueInStore:"+valueInStore);
                     break;
                 }
-            }
+            }*/
+                        valueInStore =PictureSizeHelper.getCustomDefault(getEntryValues());
+                       
         }

PictureSizeHelper.java getCustomDefault 方法

自定义 getCustomDefault 方法,设置默认分辨率。 这里直接写死,或者 根据客需要求设置为最大、最小 等。

    public static String getCustomDefault(List<String> supportedEntryValues){
       
        for (int i=0;i< supportedEntryValues.size();i++) {   
            /*Size size = valueToSize(supportedEntryValues.get(i));
            temp = size.width * size.height;        
            if (temp > maxSize) {
                maxSize = temp;
                maxIndex = i;
            }*/
		 LogHelper.d(TAG,   "getCustomDefault:" +supportedEntryValues.get(i));

        }
        return  "1920x1088";
    }

源码分析

设置拍照尺寸的核心类

\vendor\mediatek\proprietary\packages\apps\Camera2\feature\setting\picturesize\src\com\mediatek\camera\feature\setting\picturesize\PictureSize.java
\vendor\mediatek\proprietary\packages\apps\Camera2\feature\setting\picturesize\src\com\mediatek\camera\feature\setting\picturesize\PictureSizeHelper.java
\vendor\mediatek\proprietary\packages\apps\Camera2\feature\setting\picturesize\src\com\mediatek\camera\feature\setting\picturesize\PictureSizeSettingView.java

源码逐步分析

关联的照片大小搜索

grep -rn 照片大小

在这里插入图片描述
找到如下路径相关关键字:照片大小

feature/mode/vsdof/res/values-zh-rCN/strings.xml
<string name="sdof_picture_size_title">"照片大小"</string>


feature/setting/picturesize/res/values-zh-rCN/strings.xml
 <string name="pref_camera_picturesize_title">"照片大小"</string>

PictureSizeSelector

上面已经找到了两个关键字,这里先根据第一个关键字找一下源码:
路径:

/vendor/mediatek/proprietary/packages/apps/Camera2/feature/setting/picturesize/src/com/mediatek/camera/feature/setting/picturesize/PictureSizeSelector.java
R.string.pref_camera_picturesize_title

在这里插入图片描述

我们看类定义:


/**
 * Picture size selector.
 */

public class PictureSizeSelector extends PreferenceFragment {

就是图片大小选择器
对应的是如下界面:
在这里插入图片描述
既然是这个界面,那就看一下点击选中方法和进入这个界面的设置方法

进入界面选中的逻辑

这里关联的有四个方法,对应的进入界面选中逻辑:


    @Override
    public void onCreate(Bundle savedInstanceState) {
        LogHelper.d(TAG, "[onCreate]");
        super.onCreate(savedInstanceState);

        prepareValuesOnShown();
        Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
        if (toolbar != null) {
            toolbar.setTitle(getActivity().getResources()
                    .getString(R.string.pref_camera_picturesize_title));
        }
        addPreferencesFromResource(R.xml.picturesize_selector_preference);
        PreferenceScreen screen = getPreferenceScreen();
        for (int i = 0 ; i < mEntryValues.size(); i++) {
            RadioPreference preference = new RadioPreference(getActivity());
            if (mEntryValues.get(i).equals(mSelectedValue)) {
                preference.setChecked(true);
            }
			LogHelper.d(TAG," onCreate  ->mEntryValues.get(i):"+mEntryValues.get(i));
            preference.setTitle(mTitleList.get(i));
            preference.setSummary(mSummaryList.get(i));
            preference.setOnPreferenceClickListener(mOnPreferenceClickListener);
            screen.addPreference(preference);
        }
    }




    /**
     * Set the default selected value.
     *
     * @param value The default selected value.
     */
    public void setValue(String value) {
		LogHelper.d(TAG,"  setValue: value->"+value);
        mSelectedValue = value;
    }

    /**
     * Set the picture sizes supported.
     *
     * @param entryValues The picture sizes supported.
     */
    public void setEntryValues(List<String> entryValues) {
        mEntryValues.clear();
        mEntryValues.addAll(entryValues);
    }

    private void prepareValuesOnShown() {
        List<String> tempValues = new ArrayList<>(mEntryValues);
        mEntryValues.clear();
        mTitleList.clear();
        mSummaryList.clear();
        for (int i = 0; i < tempValues.size(); i++) {
            String value = tempValues.get(i);
            String title = PictureSizeHelper.getPixelsAndRatio(value);
			
			LogHelper.d(TAG,"  prepareValuesOnShown: value->"+value+"     title:"+title);

			
            if (title != null) {
                mTitleList.add(title);
                mEntryValues.add(value);
                mSummaryList.add(value);
            }else{
                LogHelper.d(TAG, "[prepareValuesOnShown] value :"+value+" will not shown.");
            }
        }
    }
方法作用
setEntryValues设置支持的图片大小 分辨率
prepareValuesOnShown准备显示的数据 在onCreate 方法里面调用的
setValue设置默认选择的值
onCreate通过setEntryValue 设置的集合,遍历创建PreferenceScreen ,对于传递进来的value 作为选中效果
点击选中图片大小逻辑

对于点击逻辑更为简单,回调 返回上一层,代码如下:

   private class MyOnPreferenceClickListener implements Preference.OnPreferenceClickListener {
        @Override
        public boolean onPreferenceClick(Preference preference) {
            String summary = (String) preference.getSummary();
            int index = mSummaryList.indexOf(summary);
            String value = mEntryValues.get(index);
            mListener.onItemClick(value);
			
			LogHelper.d(TAG,"  MyOnPreferenceClickListener: onPreferenceClick  value->"+value);

			
            mSelectedValue = value;
            getActivity().getFragmentManager().popBackStack();
            return true;
        }
    }

PictureSizeSelectorPreference

同 PictureSizeSelector 上面已经找到了两个关键字,这里先根据第二个关键字找一下源码:
路径:

./vendor/mediatek/proprietary/packages/apps/Camera2/feature/mode/aicombo/src/com/mediatek/camera/feature/mode/aicombo/photo/view/PictureSizeSelectorPreference.java
./vendor/mediatek/proprietary/packages/apps/Camera2/feature/mode/vsdof/src/com/mediatek/camera/feature/mode/vsdof/photo/view/PictureSizeSelectorPreference.java



看源码发现和 PictureSizeSelector 代码基本一致 ,但是仔细看一个方法的说明如下:

   /**
     * Set the video quality supported.
     * @param entryValues The video quality supported.
     */
    public void setEntryValues(List<String> entryValues) {
        mEntryValues.clear();
        mEntryValues.addAll(entryValues);
    }

这些事设置Vieo 的  并不是设置picture 的。 所以我们需求设置图片质量的其实应该是上面找到的 PictureSizeSelector 


PictureSizeSettingView

路径:

/vendor/mediatek/proprietary/packages/apps/Camera2/feature/setting/picturesize/src/com/mediatek/camera/feature/setting/picturesize/PictureSizeSettingView.java

找到这个类的方法有两种

  • grep 查找关键字 “照片大小”
  • 根据上面定位到的源码 PictureSizeSelector

就是进入到 PictureSizeSelector 界面之前的页面,如下:
在这里插入图片描述
准确的来说, PictureSizeSettingView 对应的其实是这个界面中 图片大小的这个item .
源码代码量不多,我们赋上来看看:

package com.mediatek.camera.feature.setting.picturesize;

import android.app.Activity;
import android.app.FragmentTransaction;
import android.preference.PreferenceFragment;

import com.mediatek.camera.R;
import com.mediatek.camera.common.debug.LogHelper;
import com.mediatek.camera.common.debug.LogUtil;
import com.mediatek.camera.common.preference.Preference;
import com.mediatek.camera.common.setting.ICameraSettingView;

import java.util.ArrayList;
import java.util.List;

/**
 * Picture size setting view.
 */
public class PictureSizeSettingView implements ICameraSettingView,
        PictureSizeSelector.OnItemClickListener {
    private static final LogUtil.Tag TAG =
            new LogUtil.Tag(PictureSizeSettingView.class.getSimpleName());

    private Activity mActivity;
    private Preference mPref;
    private OnValueChangeListener mListener;
    private String mKey;
    private String mSelectedValue;
    private List<String> mEntryValues = new ArrayList<>();
    private String mSummary;
    private PictureSizeSelector mSizeSelector;
    private boolean mEnabled;

    /**
     * Listener to listen picture size value changed.
     */
    public interface OnValueChangeListener {
        /**
         * Callback when picture size value changed.
         *
         * @param value The changed picture size, such as "1920x1080".
         */
        void onValueChanged(String value);
    }

    /**
     * Picture size setting view constructor.
     *
     * @param key The key of picture size.
     */
    public PictureSizeSettingView(String key) {
        mKey = key;
    }

    @Override
    public void loadView(PreferenceFragment fragment) {
        LogHelper.d(TAG, "[loadView]");
        mActivity = fragment.getActivity();

        if (mSizeSelector == null) {
            mSizeSelector = new PictureSizeSelector();
            mSizeSelector.setOnItemClickListener(this);
        }

        fragment.addPreferencesFromResource(R.xml.picturesize_preference);
        mPref = (Preference) fragment.findPreference(mKey);
        mPref.setRootPreference(fragment.getPreferenceScreen());
        mPref.setId(R.id.picture_size_setting);
        mPref.setContentDescription(mActivity.getResources()
                .getString(R.string.picture_size_content_description));
        mPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {

            @Override
            public boolean onPreferenceClick(android.preference.Preference preference) {
                mSizeSelector.setValue(mSelectedValue);
                mSizeSelector.setEntryValues(mEntryValues);

                FragmentTransaction transaction = mActivity.getFragmentManager()
                        .beginTransaction();
                transaction.addToBackStack(null);
                transaction.replace(R.id.setting_container,
                        mSizeSelector, "picture_size_selector").commit();
                return true;
            }

        });
        mPref.setEnabled(mEnabled);
        if (mSelectedValue != null) {
            mSummary = PictureSizeHelper.getPixelsAndRatio(mSelectedValue);
        }
    }

    @Override
    public void refreshView() {
        if (mPref != null) {
            LogHelper.d(TAG, "[refreshView]");
            mPref.setSummary(mSummary);
            mPref.setEnabled(mEnabled);
        }
    }

    @Override
    public void unloadView() {
        LogHelper.d(TAG, "[unloadView]");
    }

    @Override
    public void setEnabled(boolean enabled) {
        mEnabled = enabled;
    }

    @Override
    public boolean isEnabled() {
        return mEnabled;
    }

    /**
     * Set listener to listen the changed picture size value.
     *
     * @param listener The instance of {@link OnValueChangeListener}.
     */
    public void setOnValueChangeListener(OnValueChangeListener listener) {
        mListener = listener;
    }

    /**
     * Set the default selected value.
     *
     * @param value The default selected value.
     */
    public void setValue(String value) {
        mSelectedValue = value;
    }

    /**
     * Set the picture sizes supported.
     *
     * @param entryValues The picture sizes supported.
     */
    public void setEntryValues(List<String> entryValues) {
        mEntryValues = entryValues;
    }

    @Override
    public void onItemClick(String value) {
        mSelectedValue = value;
        mSummary = PictureSizeHelper.getPixelsAndRatio(value);
        if (mListener != null) {
            mListener.onValueChanged(value);
        }
    }
}
onItemClick

这里关注下这个 onItemClick 点击方法,我们看类声明如下:

PictureSizeSettingView implements ICameraSettingView,
        PictureSizeSelector.OnItemClickListener

所以 这个 onItemClick 方法其实是PictureSizeSelector 类的点击方法的回调。

onPreferenceClick

先看源码,如下:

  mPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {

            @Override
            public boolean onPreferenceClick(android.preference.Preference preference) {
                mSizeSelector.setValue(mSelectedValue);
                mSizeSelector.setEntryValues(mEntryValues);

                FragmentTransaction transaction = mActivity.getFragmentManager()
                        .beginTransaction();
                transaction.addToBackStack(null);
                transaction.replace(R.id.setting_container,
                        mSizeSelector, "picture_size_selector").commit();
                return true;
            }

        });

这个方法其实就做了三件事情:

  • setValue 设置默认图片大小
  • setEntryValues 设置支持的所有图片大小集合
  • transaction.replace 操作,跳转到PictureSizeSelector 界面
    这里其实就和PictureSizeSelector 完全关联起来了。

接下来就要关注 两个事情:

  • mListener.onValueChanged(value); 在哪里设置回调的
  • setValue 这个类里面也有设置默认图片大小,到底在哪里设置的

PictureSize

源码路径:

/vendor/mediatek/proprietary/packages/apps/Camera2/feature/setting/picturesize/src/com/mediatek/camera/feature/setting/picturesize/PictureSize.java

如何关联到这个类?
上面已经分析到了 PictureSizeSettingView 的 onValueChanged,其实就是要找 PictureSizeSettingView 中 接口 OnValueChangeListener 是在哪里实现的,这样来找到具体的实现和调用地方。

先看类说明:
这里我们看下部分代码片段截图:
在这里插入图片描述
上面截图就可以基本确认了,它对应的界面才是 照片设置图,如下:
在这里插入图片描述

onValueInitialized

源代码如下:

 /**
     * Invoked after setting's all values are initialized.
     *
     * @param supportedPictureSize Picture sizes which is supported in current platform.
     */
    public void onValueInitialized(List<String> supportedPictureSize) {
        LogHelper.d(TAG, "[onValueInitialized], supportedPictureSize:" + supportedPictureSize);

        double fullRatio = PictureSizeHelper.findFullScreenRatio(mActivity);
        List<Double> desiredAspectRatios = new ArrayList<>();
        desiredAspectRatios.add(fullRatio);
        desiredAspectRatios.add(PictureSizeHelper.RATIO_4_3);
        PictureSizeHelper.setDesiredAspectRatios(desiredAspectRatios);
        PictureSizeHelper.setFilterParameters(DEGRESSIVE_RATIO, MAX_COUNT);
        if (sFilterPictureSize) {
            supportedPictureSize = PictureSizeHelper.filterSizes(supportedPictureSize);
            LogHelper.d(TAG, "[onValueInitialized], after filter, supportedPictureSize = "
                    + supportedPictureSize);
        }
        if (FILTER_MODE.equals(mModeKey)
                || VFB_MODE.equals(mModeKey)
                || FB_MODE.equals(mModeKey)) {
            //for low rom
            if ((VFB_MODE.equals(mModeKey)||FILTER_MODE.equals(mModeKey))
                    && isLowRam()) {
                List<String> supportedPictureSizeAfterCheck = new ArrayList<String>();
                for (String pictureSize : supportedPictureSize) {
                    String[] size = pictureSize.split("x");
                    int width = Integer.parseInt(size[0]);
                    int height = Integer.parseInt(size[1]);
                    if (width < PICTURE_SIZE_9M_WIDTH
                            && height < PICTURE_SIZE_9M_HEIGHT) {
                        supportedPictureSizeAfterCheck.add(pictureSize);
                    }
                }
                supportedPictureSize = supportedPictureSizeAfterCheck;
                LogHelper.d(TAG, "[onValueInitialized], low ram, after check, " +
                        "supportedPictureSize:"
                        + supportedPictureSize);
            } else {
                List<String> supportedPictureSizeAfterCheck = new ArrayList<String>();
                for (String pictureSize : supportedPictureSize) {
                    String[] size = pictureSize.split("x");
                    int width = Integer.parseInt(size[0]);
                    int height = Integer.parseInt(size[1]);
                    if (width <= PictureSizeHelper.getMaxTexureSize()
                            && height <= PictureSizeHelper.getMaxTexureSize()) {
                        supportedPictureSizeAfterCheck.add(pictureSize);
                    }
                }
                supportedPictureSize = supportedPictureSizeAfterCheck;
                LogHelper.d(TAG, "[onValueInitialized], GPU Mode, after check, " +
                        "supportedPictureSize:"
                        + supportedPictureSize);
            }
        }
        if (HDR_MODE.equals(mModeKey)) {
            List<String> supportedPictureSizeAfterCheck = new ArrayList<String>();
            for (String pictureSize : supportedPictureSize) {
                for (String yuvSize:mYUVsupportedSize){
                    if(pictureSize.equals(yuvSize)){
                        supportedPictureSizeAfterCheck.add(pictureSize);
                    }
                }
            }
            supportedPictureSize=supportedPictureSizeAfterCheck;
            LogHelper.d(TAG, "[onValueInitialized], PostAlgo Mode, after check, supportedPictureSize:"
                    + supportedPictureSize);
        }
        if (AIBEAUTYPHOTO_MODE.equals(mModeKey)
                || AIBOKEHPHOTO_MODE.equals(mModeKey)
                || AICOLORPHOTO_MODE.equals(mModeKey)
                || AILEGGYPHOTO_MODE.equals(mModeKey)
                || AISLIMMINGPHOTO_MODE.equals(mModeKey)) {
            List<String> supportedPictureSizeAfterCheck = new ArrayList<String>();
            for (String pictureSize : supportedPictureSize) {
                    String[] size = pictureSize.split("x");
                    int width = Integer.parseInt(size[0]);
                    int height = Integer.parseInt(size[1]);
                    if (width <= PictureSizeHelper.getMaxTexureSize()
                            && height <= PictureSizeHelper.getMaxTexureSize()) {
                        supportedPictureSizeAfterCheck.add(pictureSize);
                    }
            }
            supportedPictureSize = supportedPictureSizeAfterCheck;
            LogHelper.d(TAG, "[onValueInitialized], mModeKey:" + mModeKey + ",after check, supportedPictureSize:"
                    + supportedPictureSize);
        }

        setSupportedPlatformValues(supportedPictureSize);
        setSupportedEntryValues(supportedPictureSize);
        setEntryValues(supportedPictureSize);
        refreshViewEntry();

        String valueInStore = mDataStore.getValue(getKey(), null, getStoreScope());
        if (valueInStore != null
                && !supportedPictureSize.contains(valueInStore)) {
            LogHelper.d(TAG, "[onValueInitialized], value:" + valueInStore
                    + " isn't supported in current platform");
            valueInStore = null;
            mDataStore.setValue(getKey(), null, getStoreScope(), false);
        }
        if (valueInStore == null) {
            // Default picture size is the max full-ratio size.
			LogHelper.d(TAG, "valueInStore == null  Default picture size is the max full-ratio size:");
            /*List<String> entryValues = getEntryValues();
            for (String value : entryValues) {
                if (PictureSizeHelper.getStandardAspectRatio(value) == fullRatio) {
                    valueInStore = value;
					LogHelper.d(TAG, "valueInStore == null:valueInStore:"+valueInStore);
                    break;
                }
            }*/
			 valueInStore =PictureSizeHelper.getCustomDefault(getEntryValues());
			
        }
        // If there is no full screen ratio picture size, use the first value in
        // entry values as the default value.
        if (valueInStore == null) {
            valueInStore = getEntryValues().get(0);
			LogHelper.d(TAG, "valueInStore:valueInStore:"+valueInStore);
        }
        setValue(valueInStore);
    }

看方法注释就一目了然了,根据当前平台设置-初始化图片大小

 /**
     * Invoked after setting's all values are initialized.
     *
     * @param supportedPictureSize Picture sizes which is supported in current platform.
     */

对于 valueInStore 的具体设置内容和关联逻辑,这里暂不分析。

总结

  • 实现了MTK Android13 平台下默认图片大小的逻辑
  • 分析了解决问题的思路,源码分析流程
  • 建议对Camera2 相关知识需要一定的了解最好
  • 在查看源码的过程中,难免找不到关键字,不知道修改哪里。 可以借助IDE- AS VS 操作,方便定位源码位置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值