美文网首页
晓龙相机添加一组自定制预览,录像分辨率

晓龙相机添加一组自定制预览,录像分辨率

作者: 窝窝蜗牛 | 来源:发表于2020-11-14 16:43 被阅读0次

前言

目前有个需求需要添加一个810x720的预览和录像分辨率,测试app是晓龙相机。本文的默认要求是底层能够支持810x720的分辨率请求,另外晓龙相机使用的是api1。

一、预览更改

参考代码

public static Point getCameraPreviewSize() {
        Point result = null;
        if (PERSIST_CAMERA_PREVIEW_SIZE != null) {
            String[] sourceStrArray = PERSIST_CAMERA_PREVIEW_SIZE.split("x");
            if (sourceStrArray != null && sourceStrArray.length >= 2) {
                result = new Point();
                result.x = Integer.parseInt(sourceStrArray[0]);
                result.y = Integer.parseInt(sourceStrArray[1]);
            }
        }
        return result;
    }
//private static final String PERSIST_CAMERA_PREVIEW_SIZE =
//            SystemProperties.get("persist.sys.camera.preview.size", "");

adb shell setprop persist.sys.camera.preview.size 810x720 //设置预览分辨率
adb shell pm clear org.codeaurora.snapcam //清空原先static数据,重启app

二、录像分辨率更改

录像分辨率没有相应的属性来控制,所以考虑在UI设置中添加该项,操作起来也很麻烦
视频画质中添加810x720项,下面是具体过程

第一步 在控件中加入该项

--- a/packages/apps/SnapdragonCamera/res/values/arrays.xml
+++ b/packages/apps/SnapdragonCamera/res/values/arrays.xml
@@ -24,7 +24,8 @@
         <item>@string/pref_video_quality_entry_2k</item>
         <item>@string/pref_video_quality_entry_1080p</item>
         <item>@string/pref_video_quality_entry_720p</item>
         <item>@string/pref_video_quality_entry_480p</item>
+       <item>810x720</item>
         <item>@string/pref_video_quality_entry_480p</item>
         <item>@string/pref_video_quality_entry_vga</item>
         <item>@string/pref_video_quality_entry_cif</item>
         <item>@string/pref_video_quality_entry_qvga</item>
@@ -36,6 +37,7 @@
         <item>2048x1080</item>
         <item>1920x1080</item>
         <item>1280x720</item>
+       <item>810x720</item>
         <item>720x480</item>
         <item>640x480</item>
         <item>352x288</item>
--- a/packages/apps/SnapdragonCamera/src/com/android/camera/CameraSettings.java
+++ b/packages/apps/SnapdragonCamera/src/com/android/camera/CameraSettings.java
@@ -328,6 +328,7 @@ public class CameraSettings {
         }
         VIDEO_QUALITY_TABLE.put("1920x1080", CamcorderProfile.QUALITY_1080P);
         VIDEO_QUALITY_TABLE.put("1280x720",  CamcorderProfile.QUALITY_720P);
+       VIDEO_QUALITY_TABLE.put("810x720", CamcorderProfile.QUALITY_PRIV);
         VIDEO_QUALITY_TABLE.put("720x480",   CamcorderProfile.QUALITY_480P);
         if ( CamcorderProfileWrapper.QUALITY_VGA != -1 ) {
             VIDEO_QUALITY_TABLE.put("640x480", CamcorderProfileWrapper.QUALITY_VGA);

另外,这里可以设置list控件的默认值
SnapdragonCamera/res/values/strings.xml
<string name="pref_video_quality_default" translatable="false">1920x1080</string>
这里主要参考代码:
res/xml/video_preferences.xml


image.png

这个是设置界面的list控件的布局,第一张负责控制录像的视频质量,即是控制分辨率,videoQuality 是从控件的entity value中拿到的,如参考如下代码:

private void readVideoPreferences() {
        // The preference stores values from ListPreference and is thus string type for all values.
        // We need to convert it to int manually.
        String videoQuality = mPreferences.getString(CameraSettings.KEY_VIDEO_QUALITY,
                        null);    //通过IconListPreference拿到需要设置的分辨率大小
        Log.e(TAG,"videoQuality" + videoQuality);
        if (videoQuality == null) {  //第一次进入取默认值
            mParameters = mCameraDevice.getParameters();
            String defaultQuality = mActivity.getResources().getString(
                    R.string.pref_video_quality_default);
            if (!defaultQuality.equals("") &&
                    CameraUtil.isSupported(defaultQuality,
                            CameraSettings.getSupportedVideoQualities(
                                                    mCameraId, mParameters))){
                videoQuality = defaultQuality;
            } else {
                // check for highest quality supported
                videoQuality = CameraSettings.getSupportedHighestVideoQuality(
                        mCameraId, mParameters);
            }
            mPreferences.edit().putString(CameraSettings.KEY_VIDEO_QUALITY, videoQuality).apply();
        }
        ......
        int mappedQuality = quality;
        if (mCaptureTimeLapse) {
            mappedQuality = CameraSettings.getTimeLapseQualityFor(quality);
        } else if (hfrRate > 0) {
            mappedQuality = CameraSettings.getHighSpeedQualityFor(quality);
            Log.i(TAG,"NOTE: HighSpeed quality (" + mappedQuality + ") for (" + quality + ")");
        }
        Log.e(TAG,"Quality " + mappedQuality);
        if (CamcorderProfile.hasProfile(mCameraId, mappedQuality)) {
            quality = mappedQuality;
        } else {
            Log.e(TAG,"NOTE: Quality " + mappedQuality + " is not supported ! Will use " + quality);
        }
        mProfile = CamcorderProfile.get(mCameraId, quality);  //关键地方,通过CamcorderProfile得到video分辨率
        getDesiredPreviewSize();
        qcomReadVideoPreferences();
        ......
    }

此处为读取配置的地方,应用数据则参考如下:
mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
第二步,添加系统支持的quality level : QUALITY_PRIV

--- a/frameworks/av/media/libmedia/MediaProfiles.cpp
+++ b/frameworks/av/media/libmedia/MediaProfiles.cpp
@@ -76,6 +76,7 @@ const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
     {"1080p", CAMCORDER_QUALITY_1080P},
     {"2160p", CAMCORDER_QUALITY_2160P},
     {"qvga", CAMCORDER_QUALITY_QVGA},
+    {"priv", CAMCORDER_QUALITY_PRIV},
      {"timelapselow",  CAMCORDER_QUALITY_TIME_LAPSE_LOW},
      {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
--- a/frameworks/av/media/libmedia/include/media/MediaProfiles.h
+++ b/frameworks/av/media/libmedia/include/media/MediaProfiles.h
@@ -34,7 +34,8 @@ enum camcorder_quality {
     CAMCORDER_QUALITY_1080P = 6,
     CAMCORDER_QUALITY_QVGA = 7,
     CAMCORDER_QUALITY_2160P = 8,
-    CAMCORDER_QUALITY_LIST_END = 8,
+    CAMCORDER_QUALITY_PRIV = 9,
+    CAMCORDER_QUALITY_LIST_END = 9,
 
     CAMCORDER_QUALITY_TIME_LAPSE_LIST_START = 1000,
     CAMCORDER_QUALITY_TIME_LAPSE_LOW  = 1000,
--- a/frameworks/base/media/java/android/media/CamcorderProfile.java
+++ b/frameworks/base/media/java/android/media/CamcorderProfile.java
@@ -95,9 +96,11 @@ public class CamcorderProfile
      */
     public static final int QUALITY_2160P = 8;
 
+       public static final int QUALITY_PRIV  = 9;
+
     // Start and end of quality list
     private static final int QUALITY_LIST_START = QUALITY_LOW;
-    private static final int QUALITY_LIST_END = QUALITY_2160P;
+    private static final int QUALITY_LIST_END = QUALITY_PRIV;

默认CamcorderProfile类是没有QUALITY_PRIV这个变量的,需要在framework层添加
最后一步,添加MediaProfiles实例对象

--- a/device/qcom/msm8937_32go/media/media_profiles_8937.xml
+++ b/device/qcom/msm8937_32go/media/media_profiles_8937.xml
@@ -185,6 +185,18 @@
              sampleRate="48000"
              channels="2" />
     </EncoderProfile>
+       
+       <EncoderProfile quality="priv" fileFormat="mp4" duration="30">
+         <Video codec="h264"
+                bitRate="20000000"
+                        width="810"
+                        height="720"
+                        frameRate="30" />
+         <Audio codec="aac"
+                bitRate="156000"
+                sampleRate="48000"
+                channels="2" />
+       </EncoderProfile>
 
     <EncoderProfile quality="qcif" fileFormat="3gp" duration="30">
       <Video codec="h264"

另外,需要说明一下,在list中添加了对应的项未必就能够显示出来,因为camerasetting会将VIDEO_QUALITY_TABLE中不存在的选项给过滤,另外,没有实例化CamcorderProfile的选项也会被去掉,可参考代码:

public static ArrayList<String> getSupportedVideoQualities(int cameraId,Parameters parameters) {
        ArrayList<String> supported = new ArrayList<String>();
        List<String> temp = sizeListToStringList(parameters.getSupportedVideoSizes());
        Log.i(TAG,"strings " + temp);
        for (String videoSize : temp) {
            if (VIDEO_QUALITY_TABLE.containsKey(videoSize)) {
                int profile = VIDEO_QUALITY_TABLE.get(videoSize);
                if (CamcorderProfile.hasProfile(cameraId, profile)) {
                      supported.add(videoSize);
                      Log.i(TAG,"support " + videoSize);
                }
            }
        }
        Log.i(TAG,"supported " + supported);
        return supported;
    }

这也是为什么第一步需要往VIDEO_QUALITY_TABLE填充值的原因,另外,跟踪一下 mProfile = CamcorderProfile.get(mCameraId, quality);的调用流程

==>
CamcorderProfile.java
public static CamcorderProfile get(int cameraId, int quality) {
        if (!((quality >= QUALITY_LIST_START &&
               quality <= QUALITY_LIST_END) ||
              (quality >= QUALITY_TIME_LAPSE_LIST_START &&
               quality <= QUALITY_TIME_LAPSE_LIST_END) ||
               (quality >= QUALITY_HIGH_SPEED_LIST_START &&
               quality <= QUALITY_HIGH_SPEED_LIST_END) ||
               (quality >= QUALITY_VENDOR_LIST_START &&
               quality <= QUALITY_VENDOR_LIST_END))) {
            String errMessage = "Unsupported quality level: " + quality;
            throw new IllegalArgumentException(errMessage);
        }
        return native_get_camcorder_profile(cameraId, quality);
    }
==>
android_media_MediaProfiles.cpp
static const JNINativeMethod gMethodsForCamcorderProfileClass[] = {
    {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
    {"native_get_camcorder_profile",           "(II)Landroid/media/CamcorderProfile;",
                                                                         (void *)android_media_MediaProfiles_native_get_camcorder_profile},
    {"native_has_camcorder_profile",           "(II)Z",
                                                                         (void *)android_media_MediaProfiles_native_has_camcorder_profile},
};
static jobject
android_media_MediaProfiles_native_get_camcorder_profile(JNIEnv *env, jobject /* thiz */, jint id,
                                                         jint quality)
{
    ALOGV("native_get_camcorder_profile: %d %d", id, quality);
    if (!isCamcorderQualityKnown(quality)) {
        jniThrowException(env, "java/lang/RuntimeException", "Unknown camcorder profile quality");
        return NULL;
    }

    camcorder_quality q = static_cast<camcorder_quality>(quality);
    int duration         = sProfiles->getCamcorderProfileParamByName("duration",    id, q);
    int fileFormat       = sProfiles->getCamcorderProfileParamByName("file.format", id, q);
    int videoCodec       = sProfiles->getCamcorderProfileParamByName("vid.codec",   id, q);
    int videoBitRate     = sProfiles->getCamcorderProfileParamByName("vid.bps",     id, q);
    int videoFrameRate   = sProfiles->getCamcorderProfileParamByName("vid.fps",     id, q);
    int videoFrameWidth  = sProfiles->getCamcorderProfileParamByName("vid.width",   id, q);
    int videoFrameHeight = sProfiles->getCamcorderProfileParamByName("vid.height",  id, q);
    int audioCodec       = sProfiles->getCamcorderProfileParamByName("aud.codec",   id, q);
    int audioBitRate     = sProfiles->getCamcorderProfileParamByName("aud.bps",     id, q);
    int audioSampleRate  = sProfiles->getCamcorderProfileParamByName("aud.hz",      id, q);
    int audioChannels    = sProfiles->getCamcorderProfileParamByName("aud.ch",      id, q);

    // Check on the values retrieved
    if (duration == -1 || fileFormat == -1 || videoCodec == -1 || audioCodec == -1 ||
        videoBitRate == -1 || videoFrameRate == -1 || videoFrameWidth == -1 || videoFrameHeight == -1 ||
        audioBitRate == -1 || audioSampleRate == -1 || audioChannels == -1) {

        jniThrowException(env, "java/lang/RuntimeException", "Error retrieving camcorder profile params");
        return NULL;
    }

    jclass camcorderProfileClazz = env->FindClass("android/media/CamcorderProfile");
    jmethodID camcorderProfileConstructorMethodID = env->GetMethodID(camcorderProfileClazz, "<init>", "(IIIIIIIIIIII)V");
    return env->NewObject(camcorderProfileClazz,
                          camcorderProfileConstructorMethodID,
                          duration,
                          quality,
                          fileFormat,
                          videoCodec,
                          videoBitRate,
                          videoFrameRate,
                          videoFrameWidth,
                          videoFrameHeight,
                          audioCodec,
                          audioBitRate,
                          audioSampleRate,
                          audioChannels);
}
==>
CamcorderProfile.java
private CamcorderProfile(int duration,
                             int quality,
                             int fileFormat,
                             int videoCodec,
                             int videoBitRate,
                             int videoFrameRate,
                             int videoWidth,
                             int videoHeight,
                             int audioCodec,
                             int audioBitRate,
                             int audioSampleRate,
                             int audioChannels) {

        this.duration         = duration;
        this.quality          = quality;
        this.fileFormat       = fileFormat;
        this.videoCodec       = videoCodec;
        this.videoBitRate     = videoBitRate;
        this.videoFrameRate   = videoFrameRate;
        this.videoFrameWidth  = videoWidth;
        this.videoFrameHeight = videoHeight;
        this.audioCodec       = audioCodec;
        this.audioBitRate     = audioBitRate;
        this.audioSampleRate  = audioSampleRate;
        this.audioChannels    = audioChannels;
    }

再跟踪sProfiles = MediaProfiles::getInstance实例

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 : xmlFiles) {
                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 {
            if (!strncmp(value, "/vendor/etc", strlen("/vendor/etc"))) {
                 AVMediaUtils::get()->getCustomProfileLocation(value,
                    PROPERTY_VALUE_MAX);
            }
            sInstance = createInstanceFromXmlFile(value);
        }
        CHECK(sInstance != NULL);
        sInstance->checkAndAddRequiredProfilesIfNecessary();
        sIsInitialized = true;
    }

    return sInstance;
}

这里就可以知道为什么最后需要更改xml文件了
MediaProfiles.h

  static constexpr char const * const xmlFiles[] = {
            "vendor/etc/media_profiles_V1_0.xml",
            "system/etc/media_profiles.xml"
            };

编译生成规则


image.png

可查看下xml内容:

<MediaSettings>
    <!-- Each camcorder profile defines a set of predefined configuration parameters -->
    <!-- Back Camera -->
    <CamcorderProfiles cameraId="0">

    <EncoderProfile quality="low" fileFormat="3gp" duration="30">
      <Video codec="h264"
             bitRate="192000"
             width="176"
             height="144"
             frameRate="30" />

      <Audio codec="amrnb"
             bitRate="12200"
             sampleRate="8000"
             channels="1" />
    </EncoderProfile>

    <EncoderProfile quality="high" fileFormat="mp4" duration="30">
      <Video codec="h264"
             bitRate="20000000"
             width="1920"
             height="1080"
             frameRate="30" />

      <Audio codec="aac"
             bitRate="156000"
             sampleRate="48000"
             channels="2" />
    </EncoderProfile>

    <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
      <Video codec="h264"
             bitRate="512000"
             width="320"
             height="240"
             frameRate="30" />

      <Audio codec="aac"
             bitRate="156000"
             sampleRate="48000"
             channels="2" />
    </EncoderProfile>

    <EncoderProfile quality="cif" fileFormat="3gp" duration="30">
      <Video codec="h264"
             bitRate="720000"
             width="352"
             height="288"
             frameRate="30" />

      <Audio codec="amrnb"
             bitRate="12200"
             sampleRate="8000"
             channels="1" />
    </EncoderProfile>
.....

最终使用的xml文件为media_profiles_vendor.xml,为方便调试,可直接使用该文件进行替换

相关文章

网友评论

      本文标题:晓龙相机添加一组自定制预览,录像分辨率

      本文链接:https://www.haomeiwen.com/subject/gzhwbktx.html