RK3588 camera2 支持4K录像

  • Post author:
  • Post category:其他



  1. 确认摄像头是否支持4K

指令 adb shell dumpsys media.camera | grep picture-size

adb shell 
rk3588_s:/ # dumpsys media.camera | grep picture-size                                                                                                                
    picture-size: 3840x2160
    picture-size-values: 3840x2160,2592x1944,1920x1080,1280x960,1280x720,640x480,320x240,176x144
rk3588_s:/ # 

可以看到当前摄像头是支持4K的


2、查看录像设置分辨率列表

可以看到目前最高支持480p分辨率,开始跟踪代码


3、跟踪列表加载代码

packages/apps/Camera2/src/com/android/camera/settings/CameraSettingsActivity.java文件中加载的list

private void setSummary(Preference preference) {
            if (!(preference instanceof ListPreference)) {
                return;
            }

            ListPreference listPreference = (ListPreference) preference;
            if (listPreference.getKey().equals(Keys.KEY_PICTURE_SIZE_BACK)) {
                setSummaryForSelection(mPictureSizes.backCameraSizes,
                        listPreference);
            } else if (listPreference.getKey().equals(Keys.KEY_PICTURE_SIZE_FRONT)) {
                setSummaryForSelection(mPictureSizes.frontCameraSizes,
                        listPreference);
            } else if (listPreference.getKey().equals(Keys.KEY_VIDEO_QUALITY_BACK)) {
                setSummaryForSelection(mPictureSizes.videoQualitiesBack.orNull(), listPreference);
            } else if (listPreference.getKey().equals(Keys.KEY_VIDEO_QUALITY_FRONT)) {
                setSummaryForSelection(mPictureSizes.videoQualitiesFront.orNull(), listPreference);
            } else if (listPreference.getKey().equals(Keys.KEY_MEDIA_SAVE_PATH)) {
                /*listPreference.setSummary(listPreference.getEntry());
                String value = listPreference.getValue();
                if (FLASH.equals(value))
                    Storage.DIRECTORY = Storage.DEFAULT_DIRECTORY;
                else if (SDCARD.equals(value)) {
                    String state = Environment.getStorageState(new File(Storage.EXTENAL_SD));
                    Log.i(TAG,"getSecondVolumeStorageState = " + state);
                    if (!Environment.MEDIA_MOUNTED.equalsIgnoreCase(state)) {
                        mSettingsManager.setToDefault(SettingsManager.SCOPE_GLOBAL, Keys.KEY_MEDIA_SAVE_PATH);
                        restoreMediaSavePath();
                        Toast.makeText(getActivity(), R.string.external_sd_unmounted, Toast.LENGTH_SHORT).show();
                    } else {
                        Storage.DIRECTORY = Storage.EXTERNAL_DIRECTORY;
                    }
                }
                Log.i(TAG, "setSummary Storage.DIRECTORY = " + Storage.DIRECTORY);*/
            } else {
                listPreference.setSummary(listPreference.getEntry());
            }
        }

搜索KEY_VIDEO_QUALITY_BACK,加载list的值是mPictureSizes.videoQualitiesBack,继续查看videoQualitiesBack加载过程

packages/apps/Camera2/src/com/android/camera/settings/PictureSizeLoader.java

    private Optional<SelectedVideoQualities> computeQualitiesForCamera(
            CameraDeviceSelector facingSelector) {
        int cameraId = SettingsUtil.getCameraId(mCameraDeviceInfo, facingSelector);
        if (cameraId >= 0) {
            // This is guaranteed not to be null/absent.
            return Optional.of(SettingsUtil.getSelectedVideoQualities(cameraId));
        }
        return Optional.absent();
    }

SettingsUtil.getSelectedVideoQualities(cameraId)); 这个地方获取分辨率list

    static SelectedVideoQualities getSelectedVideoQualities(int cameraId) {
        if (sCachedSelectedVideoQualities.get(cameraId) != null) {
            return sCachedSelectedVideoQualities.get(cameraId);
        }

        // Go through the sizes in descending order, see if they are supported,
        // and set large/medium/small accordingly.
        // If no quality is supported at all, the first call to
        // getNextSupportedQuality will throw an exception.
        // If only one quality is supported, then all three selected qualities
        // will be the same.
        int largeIndex = getNextSupportedVideoQualityIndex(cameraId, -1);
        int mediumIndex = getNextSupportedVideoQualityIndex(cameraId, largeIndex);
        int smallIndex = getNextSupportedVideoQualityIndex(cameraId, mediumIndex);

        SelectedVideoQualities selectedQualities = new SelectedVideoQualities();
        selectedQualities.large = sVideoQualities[largeIndex];
        selectedQualities.medium = sVideoQualities[mediumIndex];
        selectedQualities.small = sVideoQualities[smallIndex];
        sCachedSelectedVideoQualities.put(cameraId, selectedQualities);
        return selectedQualities;
    }

largeIndex mediumIndex smallIndex 大 中 小 列表中的三个值,需要继续一层层的跟下去,getNextSupportedVideoQualityIndex里面有个判断把4K分辨率过滤掉了,这个判断需要打开

    private static boolean isVideoQualitySupported(int videoQuality) {
        // 4k is only supported on L or higher but some devices falsely report
        // to have support for it on K, see b/18172081.
        if (!ApiHelper.isLOrHigher() && videoQuality == CamcorderProfile.QUALITY_2160P) {
            return false;
        }
        return true;
    }


&& videoQuality == CamcorderProfile.QUALITY_2160P 这个条件判断去掉

getNextSupportedVideoQualityIndex是获取的接口,代码都贴出来太多,整个调用顺序好了。

getNextSupportedVideoQualityIndex -> hasProfile -> native_has_camcorder_profile -> android_media_MediaProfiles_native_has_camcorder_profile ->  sProfiles->hasCamcorderProfile -> getCamcorderProfileIndex

int MediaProfiles::getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const
{
    int index = -1;
    for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
        if (mCamcorderProfiles[i]->mCameraId == cameraId &&
            mCamcorderProfiles[i]->mQuality == quality) {
            index = i;
            break;
        }
    }
    return index;
}

mCamcorderProfiles 加载过程就很重要了,MediaProfiles.cpp初始化的时候会去加载它

/*static*/ MediaProfiles*
MediaProfiles::getInstance()
{
    ALOGV("getInstance");
    Mutex::Autolock lock(sLock);
    if (!sIsInitialized) {
        char value[PROPERTY_VALUE_MAX];
        if (property_get("media.settings.xml", value, NULL) <= 0) {
            const char* xmlFile = nullptr;
            for (auto const& f : getXmlPaths()) {
                if (checkXmlFile(f)) {
                    xmlFile = f;
                    break;
                }
            }
            if (xmlFile == nullptr) {
                ALOGW("Could not find a validated xml file. "
                        "Using the default instance instead.");
                sInstance = createDefaultInstance();
            } else {
                sInstance = createInstanceFromXmlFile(xmlFile);
            }
        } else {
            sInstance = createInstanceFromXmlFile(value);
        }
        CHECK(sInstance != NULL);
        sInstance->checkAndAddRequiredProfilesIfNecessary();
        sIsInitialized = true;
    }

getprop 了下没有media.settings.xml,所有走 <= 0这条路了,getXmlPaths接口会去搜索product/etc/ odm/etc/ vendor/etc/ system/etc 路径下有没有media_profiles_V1_0.xml文件,查看后在vendor/etc有这个文件,那就是要修改这个xml文件。


4、解决方法


修改media_profiles_V1_0.xml

  #添加 注意区分camera0和camera1     
<EncoderProfile quality="2160p" fileFormat="mp4" duration="30">
            <Video codec="h264"
                   bitRate="6000000"
                   width="3840"
                   height="2160"
                   frameRate="30" />

            <Audio codec="aac"
                   bitRate="61000"
                   sampleRate="44100"
                   channels="1" />
</EncoderProfile>
    把h264编解码的最大分辨率改下,之前最大支持是1920
    <VideoEncoderCap name="h264" enabled="true"
        minBitRate="64000" maxBitRate="6000000"
        minFrameWidth="176" maxFrameWidth="3840"
        minFrameHeight="144" maxFrameHeight="2160"
        minFrameRate="1" maxFrameRate="30" />

改后后直接push到vendor/etc目录下,重启后验证ok,可以录4K的视频了。

设置界面也可以看到4K选项。我自己也添加了1920×1080,都是一样的方法。

红色标注是修改的地方,不能遗漏。



版权声明:本文为QliumengQ原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。