问题描述
根据文档,您可以使用CamcorderProfile
来获取设备默认的视频编解码器格式,然后将其设置为MediaRecorder
,如下所示:
According to the docs, you can use CamcorderProfile
to get the devices default video codec format, then set it to MediaRecorder
, like this:
CamcorderProfile mProfile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_HIGH);
//
mMediaRecorder.setVideoEncoder(mProfile.videoCodec);
但是由于某种原因,它返回了错误的格式.
But for some reason it is returning the wrong format.
我正在使用 CameraView 库和 FullVideoRecorder 类,定义了以下内容:
I'm using the CameraView library and in the FullVideoRecorder class the following is defined:
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
时,遇到问题的设备可以正常工作,但是由于某种原因,当我将其设置为默认值时,它会崩溃-在这种情况下,默认值表示CamcorderProfile
应该选择设备默认的视频编解码器格式.
The device I'm experiencing the issue with works perfectly fine when I set the video encoder to H_263
, but for some reason, when I set it to default it crashes - In this case default means that CamcorderProfile
should select the devices default video codec format.
我的问题:
CamcorderProfile.videoCodec
是否有任何原因会返回错误的值,并且该如何解决?
Is there any reason why CamcorderProfile.videoCodec
would return the wrong value and how can this be resolved?
编辑-添加更多信息
我实现了以下内容,以确保CamcoderProfile
是否返回错误的值:
I implemented the following to make sure if CamcoderProfile
is returning the wrong value:
//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
.
In my log I get Video Codec = H264
, but this is incorrect, it should return Video Codec = H263
.
如果我将以下内容传递给MediaRecorder
,则可以正常运行:
If I pass the following to MediaRecorder
, it works perfectly:
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
但是当我设置以下任何一项时,不是:
but not when I set any of the following:
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
mMediaRecorder.setVideoEncoder(mProfile.videoCodec);
推荐答案
问题似乎出在库中.让我解释一下.
It seems that the issue is with the library. Let me explain..
在查看 OpenCamera 的实现方式之后,我注意到他们首先检查是否camCoderProfile
具有CamcorderProfile.QUALITY...
,然后设置配置文件并沿配置文件的大小传递,如下所示:
After having a look at how OpenCamera implemented their camera, I noticed that they first check if camCoderProfile
has CamcorderProfile.QUALITY...
then setting the profile and passing along the size of the profile, as shown below:
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更改为水平-我认为这是因为摄像机的活动始终处于横向状态:
It looks like OpenCamera only changes the video quality from default
/0, if the supported profile width is 1920 and hight is 1080 - I think it is because the camera activity is always in landscape:
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 许可的,因此我将项目更改为仅实现视频在此处录音并提供源代码.
For now, I will be using the same implementation OpenCamera used. Since it is licensed under GPLv3, I have change the project to only implement video recording and made the source code available here.
这篇关于CamcorderProfile.videoCodec返回错误的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!