CamcorderProfile.videoCodec返回错误的值

时间:2019-05-28 12:32:18

标签: java android android-camera android-mediarecorder

根据docs,您可以使用CamcorderProfile获取设备的默认视频编解码器格式,然后将其设置为MediaRecorder,如下所示:

CamcorderProfile mProfile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_HIGH);

//

mMediaRecorder.setVideoEncoder(mProfile.videoCodec);

但是由于某种原因,它返回了错误的格式。

我正在使用CameraView库,并且在FullVideoRecorder类中定义了以下内容:

switch (mResult.getVideoCodec()) {
    case H_263: mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); break;
    case H_264: mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); break;
    case DEVICE_DEFAULT: mMediaRecorder.setVideoEncoder(mProfile.videoCodec); break;
} 

当我将视频编码器设置为H_263时,遇到问题的设备可以很好地工作,但是由于某种原因,当我将其设置为默认值时,它会崩溃-在这种情况下,默认值表示{{ 1}}应该选择设备默认的视频编解码器格式。


我的问题:

CamcorderProfile是否有返回错误值的原因,该如何解决?


编辑-添加更多信息

我实现了以下内容,以确保CamcorderProfile.videoCodec是否返回错误的值:

CamcoderProfile

在我的日志中,我得到//In onCreate CamcorderProfile camcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH); //getVideoCodec method below String profileCodec = getVideoCodec(camcorderProfile.videoCodec); //Log the result I get Log.e("Video Codec =", profileCodec); private String getVideoCodec(int videoCodec){ switch(videoCodec){ case MediaRecorder.VideoEncoder.H263: return "H263"; case MediaRecorder.VideoEncoder.H264: return "H264"; case MediaRecorder.VideoEncoder.MPEG_4_SP: return "MPEG_4_SP"; case MediaRecorder.VideoEncoder.DEFAULT: return "DEFAULT"; default: return "unknown"; } } ,但这是不正确的,它应该返回Video Codec = H264


如果我将以下内容传递给Video Codec = H263,则效果很好:

MediaRecorder

但当我设置以下任何一项时,则不会:

mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);

2 个答案:

答案 0 :(得分:0)

它看起来与CameraView库中发现的问题有关 https://github.com/natario1/CameraView/issues/467

根据Android文档,如果使用了旧的android.hardware.camera,那么您将无法信任视频配置文件API返回的值。 如果您将新的android.hardware.camera2使用INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY模式,则会出现相同的问题。

  

在LEGACY模式下使用Camera 2 API时(即,将CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL设置为CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY)时,对于不支持的分辨率,hasProfile(int)可能返回true。为了确保在LEGACY模式下支持给定的分辨率,CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP中给定的配置必须包含支持的输出大小中的分辨率。

camcorder.hasProfile是用于以给定质量级别测试给定相机是否存在摄像机配置文件的方法。

因此,在使用帧频和分辨率之前,必须先进行检查。

可以使用getSupportedVideoSizes,getSupportedPreviewSizes,getSupportedPreviewFpsRange方法检索支持的值

getSupportedVideoSizes获取MediaRecorder可以使用的受支持的视频帧大小。

如果返回的列表不为null,则返回的列表将至少包含一个Size,并且如果将相机用作视频源,则返回的列表中的其中一个尺寸必须传递给摄录机应用程序的MediaRecorder.setVideoSize()。在这种情况下,预览的大小可能与视频录制期间录制的视频的分辨率不同。

因此,也许我们应该检查视频大小,如果视频大小为空,则将预览大小锁定为等于录制大小。

答案 1 :(得分:0)

似乎问题出在图书馆。让我解释一下。

看了OpenCamera如何实现他们的相机后,我注意到他们首先检查camCoderProfile是否具有CamcorderProfile.QUALITY...,然后设置配置文件并传递配置文件的大小,如下如下所示:

private void initialiseVideoQuality() {
    int cameraId = camera_controller.getCameraId();
    List<Integer> profiles = new ArrayList<>();
    List<VideoQualityHandler.Dimension2D> dimensions = new ArrayList<>();

    if( CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_HIGH) ) {
        CamcorderProfile profile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_HIGH);
        profiles.add(CamcorderProfile.QUALITY_HIGH);
        dimensions.add(new VideoQualityHandler.Dimension2D(profile.videoFrameWidth, profile.videoFrameHeight));
    }
    if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) {
        if( CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_2160P) ) {
            CamcorderProfile profile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_2160P);
            profiles.add(CamcorderProfile.QUALITY_2160P);
            dimensions.add(new VideoQualityHandler.Dimension2D(profile.videoFrameWidth, profile.videoFrameHeight));
        }
    }
    if( CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_1080P) ) {
        CamcorderProfile profile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_1080P);
        profiles.add(CamcorderProfile.QUALITY_1080P);
        dimensions.add(new VideoQualityHandler.Dimension2D(profile.videoFrameWidth, profile.videoFrameHeight));
    }
    if( CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_720P) ) {
        CamcorderProfile profile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_720P);
        profiles.add(CamcorderProfile.QUALITY_720P);
        dimensions.add(new VideoQualityHandler.Dimension2D(profile.videoFrameWidth, profile.videoFrameHeight));
    }
    if( CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_480P) ) {
        CamcorderProfile profile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_480P);
        profiles.add(CamcorderProfile.QUALITY_480P);
        dimensions.add(new VideoQualityHandler.Dimension2D(profile.videoFrameWidth, profile.videoFrameHeight));
    }
    if( CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_CIF) ) {
        CamcorderProfile profile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_CIF);
        profiles.add(CamcorderProfile.QUALITY_CIF);
        dimensions.add(new VideoQualityHandler.Dimension2D(profile.videoFrameWidth, profile.videoFrameHeight));
    }
    if( CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_QVGA) ) {
        CamcorderProfile profile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_QVGA);
        profiles.add(CamcorderProfile.QUALITY_QVGA);
        dimensions.add(new VideoQualityHandler.Dimension2D(profile.videoFrameWidth, profile.videoFrameHeight));
    }
    if( CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_QCIF) ) {
        CamcorderProfile profile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_QCIF);
        profiles.add(CamcorderProfile.QUALITY_QCIF);
        dimensions.add(new VideoQualityHandler.Dimension2D(profile.videoFrameWidth, profile.videoFrameHeight));
    }
    if( CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_LOW) ) {
        CamcorderProfile profile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_LOW);
        profiles.add(CamcorderProfile.QUALITY_LOW);
        dimensions.add(new VideoQualityHandler.Dimension2D(profile.videoFrameWidth, profile.videoFrameHeight));
    }
    this.video_quality_handler.initialiseVideoQualityFromProfiles(profiles, dimensions);
}

如果支持的配置文件宽度为1920,高度为1080,则看来OpenCamera只会将视频质量从default / 0更改-我认为这是因为摄像机的活动始终处于横向状态:

if( video_quality_handler.getCurrentVideoQualityIndex() == -1 && video_quality_handler.getSupportedVideoQuality().size() > 0 ) {
video_quality_handler.setCurrentVideoQualityIndex(0); // start with highest quality

//If I log video_quality_handler.getSupportedVideoQuality() here, I get:
//[1, 5_r1440x1080, 5, 4_r960x720, 4_r800x450, 4, 7_r640x480, 7_r480x320, 7_r352x288, 7, 2]
//With 1 being QUALITY_HIGH
//https://developer.android.com/reference/android/media/CamcorderProfile.html#constants_2

for(int i=0;i<video_quality_handler.getSupportedVideoQuality().size();i++) {
    CamcorderProfile profile = getCamcorderProfile(video_quality_handler.getSupportedVideoQuality().get(i));
        if( profile.videoFrameWidth == 1920 && profile.videoFrameHeight == 1080 ) {
            video_quality_handler.setCurrentVideoQualityIndex(i);
            break;
        }
    }
}

private CamcorderProfile getCamcorderProfile(String quality) {
    if( camera_controller == null ) {
        //Camera is not opened
        return CamcorderProfile.get(0, CamcorderProfile.QUALITY_HIGH);
    }

    int cameraId = camera_controller.getCameraId();
    CamcorderProfile camcorder_profile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_HIGH); // default
        try {
            String profile_string = quality;
            int index = profile_string.indexOf('_');
            if( index != -1 ) {
                profile_string = quality.substring(0, index);
            }
            int profile = Integer.parseInt(profile_string);
            camcorder_profile = CamcorderProfile.get(cameraId, profile);
            if( index != -1 && index+1 < quality.length() ) {
                String override_string = quality.substring(index+1);
                    if( override_string.charAt(0) == 'r' && override_string.length() >= 4 ) {
                        index = override_string.indexOf('x');
                        if( index == -1 ) {
                            Log.d(TAG, "override_string invalid format, can't find x");
                        }
                        else {
                            String resolution_w_s = override_string.substring(1, index); // skip first 'r'
                            String resolution_h_s = override_string.substring(index+1);
                            // copy to local variable first, so that if we fail to parse height, we don't set the width either
                            int resolution_w = Integer.parseInt(resolution_w_s);
                            int resolution_h = Integer.parseInt(resolution_h_s);
                            camcorder_profile.videoFrameWidth = resolution_w;
                            camcorder_profile.videoFrameHeight = resolution_h;
                        }
                    }
                    else {
                        Log.d(TAG, "unknown override_string initial code, or otherwise invalid format");
                    }
                }
            }
            catch(NumberFormatException e) {
                e.printStackTrace();
            }
        return camcorder_profile;
    }
}

现在,我将使用与OpenCamera相同的实现。由于它是根据GPLv3获得许可的,因此我将项目更改为仅实现视频记录,并提供了源代码here