23

I have two different code bases with the same problem.

The first one is code copied straight from developer.android.com here: http://developer.android.com/guide/topics/media/camera.html#custom-camera

The second one is this code:

http://android-er.blogspot.com.au/2011/10/simple-exercise-of-video-capture-using.html

Both work fine with the normal rear camera, but as soon as I try to use the front facing camera I get the error.

This happens on the following devices:

  • Nexus S 4.1.2

  • Galaxy Nexus 4.1.2

  • Nexus 7 4.2.1 (it only has front facing camera)

I have tried what looks like 2.2 era Camera Params as well, which some people claim is required with some Samsung and HTC devices, although multiple different articles reference different String Keys:

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

None of these work, also please note that I am detecting the correct Front Facing Camera ID which on the Nexus 7 is of course: 0. But the results are the same on all the devices.

I have tried using low quality profile, I have tried setting the video resolution, encoder, output format, bitrate, frame rate and video size manually in a multitude of ways but none which have worked.

The thing which makes me think theres nothing wrong with most of the code is that the regular camera works fine. So my guess is its something to do with the prepareVideoRecorder() / prepareMediaRecorder() method which sets up the Media Recorder.

Perhaps a Media Recorder manual encoding settings that are known to work on a front facing camera?

I have to say, the Android Camera and MediaRecorder API's suck. Compared with iOS its a bit of a mess, not to mention some of the scary looking param incompatibility issues and different resolutions across the fragmented device landscape.

Assuming I can get it working on my JB devices, does anyone know from experience if most of these issues are resolved with API 15 ICS?

I would consider not supporting API 10 Gingerbread if its going to be too hard to support.

Cœur
  • 32,421
  • 21
  • 173
  • 232
Madhava Jay
  • 712
  • 1
  • 5
  • 13

6 Answers6

39

I wrestled with this problem a bit today, too.

First, make sure that your permissions are set up correctly. Specifically, to record video, you'll want:

<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" />

Second, and this is the tricky part, this line from the tutorial does not work with the front-facing camera!

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

That signature for CamcorderProfile.get() defaults to a profile for the back-facing camera:

Returns the camcorder profile for the first back-facing camera on the device at the given quality level. If the device has no back-facing camera, this returns null.

Instead, use http://developer.android.com/reference/android/media/CamcorderProfile.html#get(int,%20int). The first parameter is the id of the camera that you opened, specifically, the front-facing camera.

spitzanator
  • 1,789
  • 4
  • 17
  • 27
  • Apologies for approaching this way but could anyone share his thoughts on the following MediaRecorder question. Would really appreciate it. http://stackoverflow.com/q/32715573/1053097 – muneikh Sep 23 '15 at 16:30
25

Okay so I finally have it working sort of.

The issue seems to definitely relate to Profile Settings and in particular Frame Rate.

On the Nexus S, my primary test device, if I probe the Camera I receive following Parameters:

For the Rear Camera:
15 FPS to 30 FPS, fair enough.

For the Front Facing Camera:
7.5 FPS to 30 FPS, okay.

Then I check the Profiles I am trying to use:

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

Clearly, the High Quality Profile is meant for the Rear Camera, seeing as the front facing is only 640x480. But they both state 30 FPS.

Now.... Here's the weirdness:

If I set ANY frame rate for the rear facing camera, no matter what profile, it crashes with the dreaded:

-19 error

mediaRecorder.setVideoFrameRate(fpsInt);

That's not a big deal coz I don't care about the rear camera but it is weird, considering the profiles are defaulting to 30 and the Params say they accept 15-30. But no int value I've tried has worked. If I omit the setVideoFrameRate it's fine.

Anyway, moving onto the Front Facing Camera.

So, if I use the QUALITY_LOW profile AND set the frame-rate to 15 or lower, it magically works.

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));
mediaRecorder.setVideoFrameRate(15);

In fact any value, 1 - 15 works. Which seems weird.

So here's the conundrum, I can probably probe for resolution and select an appropriate res for most cameras, although I'm also fairly confident almost all front-facing cameras at minimum VGA 640x480.

But, what about the frame rate? In the case of the Nexus S, I don't see any way I could determine the value of 15 or lower without just guessing? Should I aim to always use the LOWEST frame-rate that is returned by the Camera?

I took a look at the Galaxy Nexus and it has 3 frame rate ranges, the first one is 15 - 15 and the second is 15 - 30. Its low quality profile is similar albeit higher resolution. If I use low profile on Galaxy Nexus it seems to work fine.

With the Nexus 7, I cant probe the CamcorderProfile's I keep getting null pointers, which is weird. It says it supports 4 FPS - 60 FPS. If I choose QUALITY_LOW which you'd think it should work, it crashes, and I can't find a frame rate it will work with. Although the error relates to setProfile, so I think the issue is with the built in profile. Surely the point of Android API is that it's consistent, this is a flag ship device and the FF camera is there for Video Conferencing isn't it?????

So, while I have it working on two of the devices using manual custom settings for each, I can't see a clear way of making it work across multiple devices through code.

It seems that the Nexus S does not behave the way it promises to with regards to setting the FPS as per its Camera.getParameters().getSupportedPreviewFpsRange()

I'm all happy for it to use Auto FPS settings but apparently it won't with the FF camera so what am I supposed to do? I have to explicitly set the FPS on the Nexus S and in this case to anything from 1 to 15 FPS, despite the Camera telling me it handles 7.5 - 30 FPS.

Seems like the promise of the setProfile fixing all the issues in 2.x wasn't entirely true.

I can understand if your writing the Camera App for a particular ROM you just customize it to that particular hardware, which might explain why people seem to always have buggy camera apps on custom ROMs. BUT..... How do downloadable video recording apps work? Are they custom to each device?

Is this why there's no Facebook Poke and Twitter Vine on Android yet???? :P

Google, what is with your Camera API?

Does anyone know the "best practices" to determine resolution and frame-rate for all API 15+ compatible devices?

Is that even possible, or am I going to be writing custom code on each device I test and then just roll the dice on the rest?

Or is the Nexus S and the Nexus 7 just freak accidents?

sud007
  • 4,289
  • 2
  • 49
  • 56
Madhava Jay
  • 712
  • 1
  • 5
  • 13
  • 2
    Which call are you using to retrieve the camcorder profile for the front camera? You should use http://developer.android.com/reference/android/media/CamcorderProfile.html#get(int, int), which takes the camera ID as an argument. The single-argument function gives you the definitions for the main camera only. – Eddy Talvala Feb 06 '13 at 20:32
  • Also, you can only set the frame rate with http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFrameRate(int) to one of the values listed in http://developer.android.com/reference/android/hardware/Camera.Parameters.html#getSupportedPreviewFrameRates(). If you use the range set method (setPreviewFpsRange), then you have to use of the values from getSupportedPreviewFpsRange. – Eddy Talvala Feb 06 '13 at 20:34
  • The Camera.Parameters with camera ID makes sense, ill give that a go. Does setPreviewFpsRange() actually have anything to do with the MediaRecorder setVideoFrameRate() ? also Any idea why the profiles don't exist on the Nexus 7? – Madhava Jay Feb 07 '13 at 03:55
  • I had some issues like you described and just want to warn you that asking camera its optimal fps or resolution is not enough if you try to record the video. Camera may be capable of what its reporting but media recorder can be more stupid. I saw that 30 fps is not working for most of the cases its reported by camera (tried on sony xperia tablet, google nexus s) – Cynichniy Bandera Apr 23 '13 at 10:24
  • @MadhavaJay I loved reading this thread. Very informative. I'd recommend this thread to everyone who's working on a Camera App. – Adil Malik Jun 29 '13 at 16:15
  • 1
    @MadhavaJay Great post, but take a look at this simple solution http://stackoverflow.com/a/18477029/624109 – Muzikant Feb 05 '14 at 19:09
  • Maybe the clue here is the word "Preview" in the method name getSupportedPreviewFpsRange() and the returned values ONLY apply to a preview surface. Maybe the OEM for these phones took that method name too literally, and only returned Preview fps values, leaving the developer to guess the video frame rates; I also found out the hard way that there doesn't seem to be any way at all to find out what FPS values are supported for MediaRecorder video recording. As @Madhava Jay points out "I don't see any way I could determine the [frame rate] without just guessing". Good post! – DDSports Mar 23 '15 at 13:21
3

try with QUALITY_LOW because QUALITY_HIGH is not supported in Front Camera.

2

I've been struggling with a -19 error for a few hours now. The answer for me is in Madhava's response and in particular mCamera.unlock();

i.e. In combination with the first answer about set profile, this code

        Camera cam = Camera.open(frontCamID);
        cam.unlock();
        recorder.setCamera(cam);

Allows me to select and record from the front camera.

Tim Smith
  • 332
  • 4
  • 4
1

you should look here http://developer.android.com/guide/topics/media/camera.html#capture-video

the order of the commands listed there is very important.

i used the the second example of the code from here How can I capture a video recording on Android?

and modified the start recording functions

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();
}
Community
  • 1
  • 1
Arkady
  • 506
  • 1
  • 7
  • 16
  • if it doesn't help, try changing the quality to low mrec.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW)); – Arkady Feb 04 '13 at 10:47
  • Nope that doesnt work. Have you actually tested that code with: mCamera = Camera.open(1); It would be nice if someone could confirm a set of code that works for them with the front facing camera. The reason why I dont think its anything to do with the order of the Media Recorder statements is that the normal rear camera works every time. Also the front facing camera works fine in the normal camera app on all these devices so its not broken. This really makes no sense. – Madhava Jay Feb 05 '13 at 01:28
  • E/MediaRecorder(24557): start failed: -19 – Madhava Jay Feb 05 '13 at 01:49
1

I had the same problem. After i rectified what was the cause i found only 1 culprit.,720×480 resolution which is default in camera. I changed it to anything and yeah i can record it well