Android无法使用前置摄像头录制视频,MediaRecorder启动失败:-19。

23

我有两个不同的代码库都遇到了同样的问题。

第一个是从developer.android.com直接复制的代码:http://developer.android.com/guide/topics/media/camera.html#custom-camera

第二个是这个代码:http://android-er.blogspot.com.au/2011/10/simple-exercise-of-video-capture-using.html

正常的后置摄像头都能够工作,但只要我尝试使用前置摄像头,就会出现错误。

以下设备会发生这种情况:

  • Nexus S 4.1.2

  • Galaxy Nexus 4.1.2

  • Nexus 7 4.2.1(只有前置摄像头)

我已经尝试了看起来像是2.2时代相机参数的东西,有些人声称在一些三星和HTC设备上需要该参数,尽管多种不同的文章引用了不同的字符串键:

c = Camera.open(frontFacingCameraID); // attempt to get a Camera instance
Camera.Parameters params = c.getParameters();
params.set("cam-mode", 1);
params.set("cam_mode", 1);
params.set("camera-id", 1);
c.setParameters(params);

这些都没有用,而且请注意,我正在检测正确的前置摄像头ID,在Nexus 7上当然是:0。但是在所有设备上结果都是相同的。

我尝试使用低质量配置文件,手动以多种方式设置视频分辨率、编码器、输出格式、比特率、帧率和视频大小,但都没有起到作用。

让我认为代码大部分没有问题的原因是常规相机可以正常工作。所以我猜测问题出在prepareVideoRecorder() / prepareMediaRecorder()方法上,该方法设置了Media Recorder。

也许有一些媒体记录器的手动编码设置是可以在前置摄像头上正常工作的?

我必须说,Android相机和MediaRecorder API太烂了。与iOS相比,它有点乱,更不用说一些可怕的参数不兼容问题和在碎片化的设备环境中不同的分辨率。

假设我可以在我的JB设备上使其工作,是否有人根据经验知道这些问题是否在API 15 ICS中得到解决?

如果支持太困难,我会考虑不支持API 10 Gingerbread。

6个回答

39

我今天也遇到了这个问题。

首先,请确保您的权限设置正确。具体来说,为了录制视频,您需要:

<uses-feature android:name="android.hardware.camera.front" />
<uses-feature android:name="android.hardware.microphone"/>

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

第二点,这是比较棘手的部分,教程中的这行代码在使用前置摄像头时不起作用!
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

CamcorderProfile.get()的签名默认为后置摄像头的配置文件:

返回设备上给定质量级别的第一个后置摄像头的录像机配置文件。如果设备没有后置摄像头,则返回null。

相反,使用http://developer.android.com/reference/android/media/CamcorderProfile.html#get(int,%20int)。第一个参数是您打开的相机的ID,具体来说是前置相机。


抱歉这样联系您,但是否有人可以分享一下对以下MediaRecorder问题的看法。非常感谢。https://dev59.com/WOk6XIcBkEYKwwoYEf4H - muneikh

26

好的,我终于让它正常工作了。

问题似乎与 Profile Settings 有关,特别是与 Frame Rate 相关。

在 Nexus S上,我的主要测试设备上,如果我探测摄像头,会得到以下参数:

对于后置摄像头:
15 FPS 至 30 FPS,很好。

对于前置摄像头:
7.5 FPS 至 30 FPS,不错。

然后我检查我想要使用的资料:

CamcorderProfile.QUALITY_HIGH
CamcorderProfile.QUALITY_LOW

QUALITY_LOW:

audioBitRate: 12200
audioChannels: 1
audioCodec: AMR_NB audioSampleRate: 8000
duration: 30
fileFormat: THREE_GPP
quality: 0
videoBitRate: 256000
videoCodec: H264
videoFrameRate: 30
videoFrameWidth: 176
videoFrameHeight: 144

QUALITY_HIGH:

audioBitRate: 24000
audioChannels: 1
audioCodec: AAC
audioSampleRate: 16000
duration: 60
fileFormat: MPEG_4
quality: 1
videoBitRate: 3000000
videoCodec: H264
videoFrameRate: 30
videoFrameWidth: 720
videoFrameHeight: 480

显然,高质量的配置文件适用于后置摄像头,因为前置摄像头只有640x480。但它们都指定了30 FPS。

现在.... 这里奇怪的是:

如果我为后置摄像头设置任何帧率,无论使用哪个配置文件,它都会崩溃并出现可怕的错误:

-19 错误

mediaRecorder.setVideoFrameRate(fpsInt);

这不是什么大问题,因为我并不关心后置相机,但它很奇怪,考虑到配置文件默认为30,而Params说它们接受15-30。但我试过的所有整数值都没用。如果我省略setVideoFrameRate,那就没问题。

无论如何,我们来谈谈前置摄像头。

所以,如果我使用QUALITY_LOW配置文件,并将帧速率设置为15或更低,它就能神奇地工作。

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));
mediaRecorder.setVideoFrameRate(15);
实际上,任何值都可以,从1到15都可以。这似乎很奇怪。
所以问题来了,我可能可以探测分辨率并选择适当的分辨率来适配大多数摄像头,虽然我也相当自信,至少前置摄像头可以支持VGA 640x480。
但是,帧率应该如何处理呢? 在Nexus S的情况下,我没有看到任何可以确定15或更低值的方法,除非只是猜测? 我应该始终使用由相机返回的最低帧率吗?
我查看了Galaxy Nexus,它有3个帧率范围,第一个是15-15,第二个是15-30。虽然它的低质量配置文件类似但分辨率更高。如果我在Galaxy Nexus上使用低配置文件,似乎也能正常工作。
对于Nexus 7,我无法探测CamcorderProfile,一直得到null指针,这很奇怪。 它说它支持4 FPS - 60 FPS。 如果我选择QUALITY_LOW,你会认为它应该可以工作,但它会崩溃,我找不到一个可以工作的帧率。 尽管错误与setProfile相关,所以我认为问题在内置属性上。 Android API的目的显然是一致的,这是旗舰设备,FF相机是用于视频会议的,不是吗???
因此,尽管我已经成功地在两个设备上使用手动自定义设置,但我无法找到一种清晰明确的方法通过代码实现跨多个设备的工作。
看起来Nexus S并没有按照Camera.getParameters().getSupportedPreviewFpsRange()所承诺的那样处理设置FPS的方式。
我愿意让它使用自动FPS设置,但显然它无法在FF相机上使用,那么我该怎么办呢?我必须在Nexus S上明确设置FPS,在这种情况下,可以任意选择1到15 FPS,尽管相机告诉我它支持7.5-30 FPS。
看来2.x中setProfile解决所有问题的承诺并不完全正确。
我可以理解,如果你正在为特定的ROM编写相机应用程序,你只需要将其定制为特定的硬件,这可能解释了为什么人们似乎总是在定制的ROM上出现有缺陷的相机应用程序。但是......可下载的录像应用程序如何工作?它们针对每个设备进行定制吗?
这难道就是为什么在Android上还没有Facebook Poke和Twitter Vine吗? :P
谷歌,你的相机API怎么了?
有没有人知道确定所有API 15+兼容设备的分辨率和帧率的“最佳实践”?
这是否可能,还是我将在测试每个设备时编写自定义代码,然后在其余设备上随机运行?或者Nexus S和Nexus 7只是偶然事件?

2
你正在使用哪个调用来检索前置摄像头的摄像机配置文件?你应该使用http://developer.android.com/reference/android/media/CamcorderProfile.html#get(int, int),它以相机ID作为参数。单参数函数仅为主摄像头提供定义。 - Eddy Talvala
此外,您只能使用http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFrameRate(int)设置帧速率为http://developer.android.com/reference/android/hardware/Camera.Parameters.html#getSupportedPreviewFrameRates()中列出的值之一。如果您使用范围设置方法(setPreviewFpsRange),则必须使用getSupportedPreviewFpsRange中的值之一。 - Eddy Talvala
相机ID的Camera.Parameters有意义,我会试一下。setPreviewFpsRange()和MediaRecorder setVideoFrameRate()有什么关系吗?还有,为什么Nexus 7上没有这些配置文件? - Madhava Jay
1
@MadhavaJay 很棒的文章,不过看看这个简单的解决方案 https://dev59.com/G3bZa4cB1Zd3GeqPBxhQ#18477029 - Muzikant
也许这里的线索是方法名称getSupportedPreviewFpsRange()中的“Preview”一词,返回值仅适用于预览表面。也许这些手机的OEM太过字面理解该方法名称,只返回预览fps值,使开发人员猜测视频帧速率;我也发现了一个艰难的事实,似乎根本没有办法找出支持MediaRecorder视频录制的FPS值。正如@Madhava Jay所指出的那样,“我看不到任何确定[帧速率]的方法,除非只是猜测”。好帖子! - DDSports
显示剩余2条评论

3

使用QUALITY_LOW选项,因为在前置摄像头中不支持QUALITY_HIGH。


2
我已经花了几个小时来解决一个-19错误。对我来说,Madhava的回答特别有用,尤其是mCamera.unlock();即与有关设置配置文件的第一个答案结合使用,这段代码……
        Camera cam = Camera.open(frontCamID);
        cam.unlock();
        recorder.setCamera(cam);

让我能够选择并从前置摄像头录制。


1

你应该在这里查看: http://developer.android.com/guide/topics/media/camera.html#capture-video

那里列出的命令顺序非常重要。

我使用了这里的代码第二个示例: How can I capture a video recording on Android?

并修改了开始录制函数。

protected void startRecording() throws IOException 
{
    mrec = new MediaRecorder();  // Works well

    mCamera.setPreviewDisplay(surfaceHolder);
    mCamera.startPreview();

    mCamera.unlock();
    mrec.setCamera(mCamera);

    mrec.setPreviewDisplay(surfaceHolder.getSurface());
    mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    mrec.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); 

    mrec.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

    mrec.setOutputFile("/sdcard/zzzz.3gp");
    mrec.setPreviewDisplay(surfaceHolder.getSurface());

    mrec.prepare();
    mrec.start();
}

mrec.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW)); - Arkady
不行,那个不起作用。你有没有真的用mCamera = Camera.open(1)测试过那段代码?如果有人能确认一组可用于前置摄像头的代码,那就太好了。我认为问题不是与Media Recorder语句的顺序有关,因为正常的后置摄像头每次都能工作。此外,这些设备上的前置摄像头在普通相机应用程序中也能正常工作,所以它没有坏掉。这真的没有任何意义。 - Madhava Jay
E/MediaRecorder(24557): 启动失败:-19 - Madhava Jay

1
我遇到了同样的问题。在我纠正了原因之后,我发现只有一个罪犯,即相机默认的720×480分辨率。我将其更改为任何其他分辨率,现在可以成功录制了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接