原生Camera2中video mode录像模式下size尺寸如何选择?

2023-12-27 15:31:23

1,video mode在平台下支持哪些质量、分辨率、编码格式

在Android中,CamcorderProfile类提供了一系列方法,用于获取和设置录制视频的参数,如质量、分辨率、编码格式等。以下是CamcorderProfile的作用以及详细用法说明:
作用:
CamcorderProfile类提供了对录制视频质量的控制,可以根据不同的需求选择不同的质量级别。
通过使用CamcorderProfile,可以获取和设置录制视频的分辨率、帧率、编码格式等参数。
该类还提供了对视频录制源的选择,可以设置不同的视频来源,如摄像头或文件。
详细用法说明:
获取CamcorderProfile对象:可以通过调用CamcorderProfile.get()方法来获取不同质量级别的CamcorderProfile对象。例如,可以通过传递CamcorderProfile.QUALITY_HIGH来获取高质量的录制配置。
设置视频参数:通过调用CamcorderProfile对象的方法,可以设置录制视频的参数。例如,可以使用setVideoEncoder()方法设置视频的编码格式,使用setVideoFrameRate()方法设置视频的帧率等。
开始和停止录制:使用CamcorderProfile对象配置好视频参数后,可以通过调用MediaRecorder类的setProfile()方法来设置录制的配置,然后使用MediaRecorder类的start()方法开始录制,使用stop()方法停止录制。
需要注意的是,使用CamcorderProfile类需要相应的权限,需要在AndroidManifest.xml文件中添加相应的权限声明。同时,不同的设备和Android版本可能支持不同的参数和功能,因此在使用时需要考虑到兼容性和设备差异。

2,代码调用流程
1.获取CamcorderProfile对象

quality = CamcorderProfile.QUALITY_HIGH;
mProfile = CamcorderProfile.get(mCameraId, quality);

而CamcorderProfile的路径在Android目录下:frameworks\base\media\java\android\media\CamcorderProfile.java

2.接着看get接口的内容,里面主要是调用了jni层的接口,如下

native_get_camcorder_profile(cameraId, quality);

这个jni接口的路径:frameworks\base\media\jni\android_media_MediaProfiles.cpp

3,继续看jni的接口内容

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。

而sProfiles是在jni的初始init中创建。然后调用sProfiles的接口来获取录制视频的参数。

sProfiles = MediaProfiles::getInstance();

MediaProfiles这个文件的路径:frameworks\av\media\libmedia\MediaProfiles.cpp

3.接着看MediaProfiles中getCamcorderProfileParamByName接口获取参数

int MediaProfiles::getCamcorderProfileParamByName(const char *name,
                                                  int cameraId,
                                                  camcorder_quality quality) const
{
    ALOGV("getCamcorderProfileParamByName: %s for camera %d, quality %d",
        name, cameraId, quality);

    int index = getCamcorderProfileIndex(cameraId, quality);
    if (index == -1) {
        ALOGE("The given camcorder profile camera %d quality %d is not found",
            cameraId, quality);
        return -1;
    }

    if (!strcmp("duration", name)) return mCamcorderProfiles[index]->mDuration;
    if (!strcmp("file.format", name)) return mCamcorderProfiles[index]->mFileFormat;
    if (!strcmp("vid.codec", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mCodec;
    if (!strcmp("vid.width", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mFrameWidth;
    if (!strcmp("vid.height", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mFrameHeight;
    if (!strcmp("vid.bps", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mBitRate;
    if (!strcmp("vid.fps", name)) return mCamcorderProfiles[index]->mVideoCodecs[0].mFrameRate;
    if (!strcmp("aud.codec", name)) return mCamcorderProfiles[index]->mAudioCodecs[0].mCodec;
    if (!strcmp("aud.bps", name)) return mCamcorderProfiles[index]->mAudioCodecs[0].mBitRate;
    if (!strcmp("aud.ch", name)) return mCamcorderProfiles[index]->mAudioCodecs[0].mChannels;
    if (!strcmp("aud.hz", name)) return mCamcorderProfiles[index]->mAudioCodecs[0].mSampleRate;

    ALOGE("The given camcorder profile param id %d name %s is not found", cameraId, name);
    return -1;
}

主要是通过不同name到mCamcorderProfiles去获取对应的参数。

4,看关键地方 MediaProfiles::getInstance()创建mCamcorderProfiles。
解析getXmlPaths()文件的路径vendor/etc/media_profiles_V1_0.xml。在:getInstance()主要的调用

sInstance = createInstanceFromXmlFile(xmlFile);

这个接口主要是解析/media_profiles_V1_0.xml来生成mCamcorderProfiles。

5,media_profiles_V1_0.xml就是平台支持的录制视频的参数

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<!--
     This file is used to declare the multimedia profiles and capabilities
     on an android-powered device.
-->
<MediaSettings>
    <!-- Each camcorder profile defines a set of predefined configuration parameters -->
    <CamcorderProfiles cameraId="0">

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

            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>

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

            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>

        <EncoderProfile quality="720p" fileFormat="mp4" duration="60">
            <Video codec="h264"
                   bitRate="3000000"
                   width="1280"
                   height="720"
                   frameRate="30" />

            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>

        <EncoderProfile quality="480p" fileFormat="mp4" duration="60">
            <Video codec="h264"
                   bitRate="3000000"
                   width="640"
                   height="480"
                   frameRate="30" />

            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>

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

            <!-- Audio settings are not used for timealpse video recording -->
            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>

        <EncoderProfile quality="timelapse720p" fileFormat="mp4" duration="60">
            <Video codec="h264"
                   bitRate="3000000"
                   width="1280"
                   height="720"
                   frameRate="30" />

            <!-- Audio settings are not used for timealpse video recording -->
            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>


        <EncoderProfile quality="timelapse480p" fileFormat="mp4" duration="60">
            <Video codec="h264"
                   bitRate="3000000"
                   width="640"
                   height="480"
                   frameRate="30" />

            <!-- Audio settings are not used for timealpse video recording -->
            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>

        <ImageEncoding quality="90" />
        <ImageEncoding quality="80" />
        <ImageEncoding quality="70" />
        <ImageDecoding memCap="20000000" />

    </CamcorderProfiles>
    <CamcorderProfiles cameraId="1">

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

            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>

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

            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>

        <EncoderProfile quality="720p" fileFormat="mp4" duration="60">
            <Video codec="h264"
                   bitRate="3000000"
                   width="1280"
                   height="720"
                   frameRate="30" />

            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>

        <EncoderProfile quality="480p" fileFormat="mp4" duration="60">
            <Video codec="h264"
                   bitRate="3000000"
                   width="640"
                   height="480"
                   frameRate="30" />

            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>

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

            <!-- Audio settings are not used for timealpse video recording -->
            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>

        <EncoderProfile quality="timelapse720p" fileFormat="mp4" duration="60">
            <Video codec="h264"
                   bitRate="3000000"
                   width="1280"
                   height="720"
                   frameRate="30" />

            <!-- Audio settings are not used for timealpse video recording -->
            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>


        <EncoderProfile quality="timelapse480p" fileFormat="mp4" duration="60">
            <Video codec="h264"
                   bitRate="3000000"
                   width="640"
                   height="480"
                   frameRate="30" />

            <!-- Audio settings are not used for timealpse video recording -->
            <Audio codec="aac"
                   bitRate="24000"
                   sampleRate="16000"
                   channels="1" />
        </EncoderProfile>

        <ImageEncoding quality="90" />
        <ImageEncoding quality="80" />
        <ImageEncoding quality="70" />
        <ImageDecoding memCap="20000000" />

    </CamcorderProfiles>

    <EncoderOutputFileFormat name="3gp" />
    <EncoderOutputFileFormat name="mp4" />

    <!--
         If a codec is not enabled, it is invisible to the applications
         In other words, the applications won't be able to use the codec
         or query the capabilities of the codec at all if it is disabled
    -->
    <VideoEncoderCap name="h264" enabled="true"
        minBitRate="64000" maxBitRate="3000000"
        minFrameWidth="144" maxFrameWidth="1920"
        minFrameHeight="96" maxFrameHeight="1088"
        minFrameRate="15" maxFrameRate="30" />

    <VideoEncoderCap name="h263" enabled="true"
        minBitRate="64000" maxBitRate="1000000"
        minFrameWidth="176" maxFrameWidth="640"
        minFrameHeight="144" maxFrameHeight="480"
        minFrameRate="15" maxFrameRate="30" />

    <VideoEncoderCap name="m4v" enabled="true"
        minBitRate="64000" maxBitRate="2000000"
        minFrameWidth="176" maxFrameWidth="1280"
        minFrameHeight="144" maxFrameHeight="720"
        minFrameRate="15" maxFrameRate="30" />

    <AudioEncoderCap name="aac" enabled="true"
        minBitRate="758" maxBitRate="288000"
        minSampleRate="8000" maxSampleRate="48000"
        minChannels="1" maxChannels="1" />

    <AudioEncoderCap name="amrwb" enabled="true"
        minBitRate="6600" maxBitRate="23050"
        minSampleRate="16000" maxSampleRate="16000"
        minChannels="1" maxChannels="1" />

    <AudioEncoderCap name="amrnb" enabled="true"
        minBitRate="4750" maxBitRate="12200"
        minSampleRate="8000" maxSampleRate="8000"
        minChannels="1" maxChannels="1" />

    <!--
        FIXME:
        We do not check decoder capabilities at present
        At present, we only check whether windows media is visible
        for TEST applications. For other applications, we do
        not perform any checks at all.
    -->
    <VideoDecoderCap name="wmv" enabled="false"/>
    <AudioDecoderCap name="wma" enabled="false"/>
</MediaSettings>

6.现在已经了解录制视频支持的参数,接着看Camera2录制视频的Size的选择。在初始化录制视频时调用:packages\apps\Camera2\src\com\android\camera\VideoModule.java

mMediaRecorder.setProfile(mProfile);
mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);

就是前面CamcorderProfile解析处理的参数。而设置录制视频时的菜单时怎么生成的呢?接看,
这里的mProfile是根据quality 和cameraID来创建,当选择的是1080P时quality = large,如果quality =medium选择的就是720p,small对应得就是480P了。如下获取quality

int quality = SettingsUtil.getVideoQuality(videoQuality, mCameraId);

7.CameraSettingsActivity.java设置菜单选择界面。主要使用PreferenceScreen是一个非常重要的布局控件,主要用于创建设置界面(settings page)
主要看关键部分,录制视频的size怎么选择:

private void loadSizes() {
            if (mInfos == null) {
                Log.w(TAG, "null deviceInfo, cannot display resolution sizes");
                return;
            }
            PictureSizeLoader loader = new PictureSizeLoader(getActivity().getApplicationContext());
            mPictureSizes = loader.computePictureSizes();
            loader.release();
}

8.接着看PictureSizeLoader,上面的接口主要是这个对象的使用

Optional<SelectedVideoQualities> videoQualitiesBack =
                computeQualitiesForCamera(SettingsUtil.CAMERA_FACING_BACK);

这里就是获取录像size的地方。

9.computeQualitiesForCamera接口获取录像size:

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();
    }

10.继续看getSelectedVideoQualities这个接口

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;
    }

就可以拿到录制视频时的size了。如下的size

public static final int QUALITY_480P = 4;

    /**
     * Quality level corresponding to the 720p (1280 x 720) resolution.
     */
    public static final int QUALITY_720P = 5;

    /**
     * Quality level corresponding to the 1080p (1920 x 1080) resolution.
     * Note that the vertical resolution for 1080p can also be 1088,
     * instead of 1080 (used by some vendors to avoid cropping during
     * video playback).
     */
    public static final int QUALITY_1080P = 6;

11.getNextSupportedVideoQualityIndex这个接口就和前面的CamcorderProfile.java关联起来了。

private static int getNextSupportedVideoQualityIndex(int cameraId, int start) {
        for (int i = start + 1; i < sVideoQualities.length; ++i) {
            if (isVideoQualitySupported(sVideoQualities[i])
                    && CamcorderProfile.hasProfile(cameraId, sVideoQualities[i])) {
                // We found a new supported quality.
                return i;
            }
        }

        
    }

这里就根据CamcorderProfile来判断是否支持对于的size进行过滤处理。

整个录像size的分析得流程就清晰了。

文章来源:https://blog.csdn.net/jiangchaobing_2017/article/details/135245079
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。